diff options
| -rw-r--r-- | fs/cifs/link.c | 124 |
1 files changed, 68 insertions, 56 deletions
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 3f259aad361d..5988b6060e8a 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
| @@ -29,6 +29,10 @@ | |||
| 29 | #include "cifs_debug.h" | 29 | #include "cifs_debug.h" |
| 30 | #include "cifs_fs_sb.h" | 30 | #include "cifs_fs_sb.h" |
| 31 | 31 | ||
| 32 | /* | ||
| 33 | * M-F Symlink Functions - Begin | ||
| 34 | */ | ||
| 35 | |||
| 32 | #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1) | 36 | #define CIFS_MF_SYMLINK_LEN_OFFSET (4+1) |
| 33 | #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1)) | 37 | #define CIFS_MF_SYMLINK_MD5_OFFSET (CIFS_MF_SYMLINK_LEN_OFFSET+(4+1)) |
| 34 | #define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1)) | 38 | #define CIFS_MF_SYMLINK_LINK_OFFSET (CIFS_MF_SYMLINK_MD5_OFFSET+(32+1)) |
| @@ -178,6 +182,20 @@ format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) | |||
| 178 | return 0; | 182 | return 0; |
| 179 | } | 183 | } |
| 180 | 184 | ||
| 185 | bool | ||
| 186 | couldbe_mf_symlink(const struct cifs_fattr *fattr) | ||
| 187 | { | ||
| 188 | if (!(fattr->cf_mode & S_IFREG)) | ||
| 189 | /* it's not a symlink */ | ||
| 190 | return false; | ||
| 191 | |||
| 192 | if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) | ||
| 193 | /* it's not a symlink */ | ||
| 194 | return false; | ||
| 195 | |||
| 196 | return true; | ||
| 197 | } | ||
| 198 | |||
| 181 | static int | 199 | static int |
| 182 | create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, | 200 | create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon, |
| 183 | struct cifs_sb_info *cifs_sb, const char *fromName, | 201 | struct cifs_sb_info *cifs_sb, const char *fromName, |
| @@ -241,20 +259,60 @@ out: | |||
| 241 | return rc; | 259 | return rc; |
| 242 | } | 260 | } |
| 243 | 261 | ||
| 244 | bool | 262 | int |
| 245 | couldbe_mf_symlink(const struct cifs_fattr *fattr) | 263 | check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, |
| 264 | struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, | ||
| 265 | const unsigned char *path) | ||
| 246 | { | 266 | { |
| 247 | if (!(fattr->cf_mode & S_IFREG)) | 267 | int rc; |
| 268 | u8 *buf = NULL; | ||
| 269 | unsigned int link_len = 0; | ||
| 270 | unsigned int bytes_read = 0; | ||
| 271 | |||
| 272 | if (!couldbe_mf_symlink(fattr)) | ||
| 248 | /* it's not a symlink */ | 273 | /* it's not a symlink */ |
| 249 | return false; | 274 | return 0; |
| 250 | 275 | ||
| 251 | if (fattr->cf_eof != CIFS_MF_SYMLINK_FILE_SIZE) | 276 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); |
| 277 | if (!buf) | ||
| 278 | return -ENOMEM; | ||
| 279 | |||
| 280 | if (tcon->ses->server->ops->query_mf_symlink) | ||
| 281 | rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon, | ||
| 282 | cifs_sb, path, buf, &bytes_read); | ||
| 283 | else | ||
| 284 | rc = -ENOSYS; | ||
| 285 | |||
| 286 | if (rc) | ||
| 287 | goto out; | ||
| 288 | |||
| 289 | if (bytes_read == 0) /* not a symlink */ | ||
| 290 | goto out; | ||
| 291 | |||
| 292 | rc = parse_mf_symlink(buf, bytes_read, &link_len, NULL); | ||
| 293 | if (rc == -EINVAL) { | ||
| 252 | /* it's not a symlink */ | 294 | /* it's not a symlink */ |
| 253 | return false; | 295 | rc = 0; |
| 296 | goto out; | ||
| 297 | } | ||
| 254 | 298 | ||
| 255 | return true; | 299 | if (rc != 0) |
| 300 | goto out; | ||
| 301 | |||
| 302 | /* it is a symlink */ | ||
| 303 | fattr->cf_eof = link_len; | ||
| 304 | fattr->cf_mode &= ~S_IFMT; | ||
| 305 | fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; | ||
| 306 | fattr->cf_dtype = DT_LNK; | ||
| 307 | out: | ||
| 308 | kfree(buf); | ||
| 309 | return rc; | ||
| 256 | } | 310 | } |
| 257 | 311 | ||
| 312 | /* | ||
| 313 | * SMB 1.0 Protocol specific functions | ||
| 314 | */ | ||
| 315 | |||
| 258 | int | 316 | int |
| 259 | cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, | 317 | cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, |
| 260 | struct cifs_sb_info *cifs_sb, const unsigned char *path, | 318 | struct cifs_sb_info *cifs_sb, const unsigned char *path, |
| @@ -324,55 +382,9 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, | |||
| 324 | return rc; | 382 | return rc; |
| 325 | } | 383 | } |
| 326 | 384 | ||
| 327 | int | 385 | /* |
| 328 | check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, | 386 | * M-F Symlink Functions - End |
| 329 | struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, | 387 | */ |
| 330 | const unsigned char *path) | ||
| 331 | { | ||
| 332 | int rc; | ||
| 333 | u8 *buf = NULL; | ||
| 334 | unsigned int link_len = 0; | ||
| 335 | unsigned int bytes_read = 0; | ||
| 336 | |||
| 337 | if (!couldbe_mf_symlink(fattr)) | ||
| 338 | /* it's not a symlink */ | ||
| 339 | return 0; | ||
| 340 | |||
| 341 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); | ||
| 342 | if (!buf) | ||
| 343 | return -ENOMEM; | ||
| 344 | |||
| 345 | if (tcon->ses->server->ops->query_mf_symlink) | ||
| 346 | rc = tcon->ses->server->ops->query_mf_symlink(xid, tcon, | ||
| 347 | cifs_sb, path, buf, &bytes_read); | ||
| 348 | else | ||
| 349 | rc = -ENOSYS; | ||
| 350 | |||
| 351 | if (rc) | ||
| 352 | goto out; | ||
| 353 | |||
| 354 | if (bytes_read == 0) /* not a symlink */ | ||
| 355 | goto out; | ||
| 356 | |||
| 357 | rc = parse_mf_symlink(buf, bytes_read, &link_len, NULL); | ||
| 358 | if (rc == -EINVAL) { | ||
| 359 | /* it's not a symlink */ | ||
| 360 | rc = 0; | ||
| 361 | goto out; | ||
| 362 | } | ||
| 363 | |||
| 364 | if (rc != 0) | ||
| 365 | goto out; | ||
| 366 | |||
| 367 | /* it is a symlink */ | ||
| 368 | fattr->cf_eof = link_len; | ||
| 369 | fattr->cf_mode &= ~S_IFMT; | ||
| 370 | fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; | ||
| 371 | fattr->cf_dtype = DT_LNK; | ||
| 372 | out: | ||
| 373 | kfree(buf); | ||
| 374 | return rc; | ||
| 375 | } | ||
| 376 | 388 | ||
| 377 | int | 389 | int |
| 378 | cifs_hardlink(struct dentry *old_file, struct inode *inode, | 390 | cifs_hardlink(struct dentry *old_file, struct inode *inode, |
