diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifsglob.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 4 | ||||
-rw-r--r-- | fs/cifs/link.c | 84 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 1 |
4 files changed, 60 insertions, 32 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 0e68893f26f3..52ca861ed35e 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -370,6 +370,9 @@ struct smb_version_operations { | |||
370 | void (*generate_signingkey)(struct TCP_Server_Info *server); | 370 | void (*generate_signingkey)(struct TCP_Server_Info *server); |
371 | int (*calc_signature)(struct smb_rqst *rqst, | 371 | int (*calc_signature)(struct smb_rqst *rqst, |
372 | struct TCP_Server_Info *server); | 372 | struct TCP_Server_Info *server); |
373 | int (*query_mf_symlink)(const unsigned char *path, char *pbuf, | ||
374 | unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb, | ||
375 | unsigned int xid); | ||
373 | }; | 376 | }; |
374 | 377 | ||
375 | struct smb_version_values { | 378 | struct smb_version_values { |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f7e584d047e2..b29a012bed33 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -497,5 +497,7 @@ void cifs_writev_complete(struct work_struct *work); | |||
497 | struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages, | 497 | struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages, |
498 | work_func_t complete); | 498 | work_func_t complete); |
499 | void cifs_writedata_release(struct kref *refcount); | 499 | void cifs_writedata_release(struct kref *refcount); |
500 | 500 | int open_query_close_cifs_symlink(const unsigned char *path, char *pbuf, | |
501 | unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb, | ||
502 | unsigned int xid); | ||
501 | #endif /* _CIFSPROTO_H */ | 503 | #endif /* _CIFSPROTO_H */ |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index b83c3f5646bd..562044f700e5 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -305,67 +305,89 @@ CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr) | |||
305 | } | 305 | } |
306 | 306 | ||
307 | int | 307 | int |
308 | CIFSCheckMFSymlink(struct cifs_fattr *fattr, | 308 | open_query_close_cifs_symlink(const unsigned char *path, char *pbuf, |
309 | const unsigned char *path, | 309 | unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb, |
310 | struct cifs_sb_info *cifs_sb, unsigned int xid) | 310 | unsigned int xid) |
311 | { | 311 | { |
312 | int rc; | 312 | int rc; |
313 | int oplock = 0; | 313 | int oplock = 0; |
314 | __u16 netfid = 0; | 314 | __u16 netfid = 0; |
315 | struct tcon_link *tlink; | 315 | struct tcon_link *tlink; |
316 | struct cifs_tcon *pTcon; | 316 | struct cifs_tcon *ptcon; |
317 | struct cifs_io_parms io_parms; | 317 | struct cifs_io_parms io_parms; |
318 | u8 *buf; | ||
319 | char *pbuf; | ||
320 | unsigned int bytes_read = 0; | ||
321 | int buf_type = CIFS_NO_BUFFER; | 318 | int buf_type = CIFS_NO_BUFFER; |
322 | unsigned int link_len = 0; | ||
323 | FILE_ALL_INFO file_info; | 319 | FILE_ALL_INFO file_info; |
324 | 320 | ||
325 | if (!CIFSCouldBeMFSymlink(fattr)) | ||
326 | /* it's not a symlink */ | ||
327 | return 0; | ||
328 | |||
329 | tlink = cifs_sb_tlink(cifs_sb); | 321 | tlink = cifs_sb_tlink(cifs_sb); |
330 | if (IS_ERR(tlink)) | 322 | if (IS_ERR(tlink)) |
331 | return PTR_ERR(tlink); | 323 | return PTR_ERR(tlink); |
332 | pTcon = tlink_tcon(tlink); | 324 | ptcon = tlink_tcon(tlink); |
333 | 325 | ||
334 | rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, | 326 | rc = CIFSSMBOpen(xid, ptcon, path, FILE_OPEN, GENERIC_READ, |
335 | CREATE_NOT_DIR, &netfid, &oplock, &file_info, | 327 | CREATE_NOT_DIR, &netfid, &oplock, &file_info, |
336 | cifs_sb->local_nls, | 328 | cifs_sb->local_nls, |
337 | cifs_sb->mnt_cifs_flags & | 329 | cifs_sb->mnt_cifs_flags & |
338 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 330 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
339 | if (rc != 0) | 331 | if (rc != 0) { |
340 | goto out; | 332 | cifs_put_tlink(tlink); |
333 | return rc; | ||
334 | } | ||
341 | 335 | ||
342 | if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { | 336 | if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { |
343 | CIFSSMBClose(xid, pTcon, netfid); | 337 | CIFSSMBClose(xid, ptcon, netfid); |
338 | cifs_put_tlink(tlink); | ||
344 | /* it's not a symlink */ | 339 | /* it's not a symlink */ |
345 | goto out; | 340 | return rc; |
346 | } | 341 | } |
347 | 342 | ||
348 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); | ||
349 | if (!buf) { | ||
350 | rc = -ENOMEM; | ||
351 | goto out; | ||
352 | } | ||
353 | pbuf = buf; | ||
354 | io_parms.netfid = netfid; | 343 | io_parms.netfid = netfid; |
355 | io_parms.pid = current->tgid; | 344 | io_parms.pid = current->tgid; |
356 | io_parms.tcon = pTcon; | 345 | io_parms.tcon = ptcon; |
357 | io_parms.offset = 0; | 346 | io_parms.offset = 0; |
358 | io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; | 347 | io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; |
359 | 348 | ||
360 | rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); | 349 | rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type); |
361 | CIFSSMBClose(xid, pTcon, netfid); | 350 | CIFSSMBClose(xid, ptcon, netfid); |
362 | if (rc != 0) { | 351 | cifs_put_tlink(tlink); |
363 | kfree(buf); | 352 | return rc; |
353 | } | ||
354 | |||
355 | |||
356 | int | ||
357 | CIFSCheckMFSymlink(struct cifs_fattr *fattr, | ||
358 | const unsigned char *path, | ||
359 | struct cifs_sb_info *cifs_sb, unsigned int xid) | ||
360 | { | ||
361 | int rc = 0; | ||
362 | u8 *buf = NULL; | ||
363 | unsigned int link_len = 0; | ||
364 | unsigned int bytes_read = 0; | ||
365 | struct cifs_tcon *ptcon; | ||
366 | |||
367 | if (!CIFSCouldBeMFSymlink(fattr)) | ||
368 | /* it's not a symlink */ | ||
369 | return 0; | ||
370 | |||
371 | buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL); | ||
372 | if (!buf) { | ||
373 | rc = -ENOMEM; | ||
364 | goto out; | 374 | goto out; |
365 | } | 375 | } |
366 | 376 | ||
377 | ptcon = tlink_tcon(cifs_sb_tlink(cifs_sb)); | ||
378 | if ((ptcon->ses) && (ptcon->ses->server->ops->query_mf_symlink)) | ||
379 | rc = ptcon->ses->server->ops->query_mf_symlink(path, buf, | ||
380 | &bytes_read, cifs_sb, xid); | ||
381 | else | ||
382 | goto out; | ||
383 | |||
384 | if (rc != 0) | ||
385 | goto out; | ||
386 | |||
387 | if (bytes_read == 0) /* not a symlink */ | ||
388 | goto out; | ||
389 | |||
367 | rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); | 390 | rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); |
368 | kfree(buf); | ||
369 | if (rc == -EINVAL) { | 391 | if (rc == -EINVAL) { |
370 | /* it's not a symlink */ | 392 | /* it's not a symlink */ |
371 | rc = 0; | 393 | rc = 0; |
@@ -381,7 +403,7 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr, | |||
381 | fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; | 403 | fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; |
382 | fattr->cf_dtype = DT_LNK; | 404 | fattr->cf_dtype = DT_LNK; |
383 | out: | 405 | out: |
384 | cifs_put_tlink(tlink); | 406 | kfree(buf); |
385 | return rc; | 407 | return rc; |
386 | } | 408 | } |
387 | 409 | ||
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 6457690731a2..60943978aec3 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -944,6 +944,7 @@ struct smb_version_operations smb1_operations = { | |||
944 | .mand_lock = cifs_mand_lock, | 944 | .mand_lock = cifs_mand_lock, |
945 | .mand_unlock_range = cifs_unlock_range, | 945 | .mand_unlock_range = cifs_unlock_range, |
946 | .push_mand_locks = cifs_push_mandatory_locks, | 946 | .push_mand_locks = cifs_push_mandatory_locks, |
947 | .query_mf_symlink = open_query_close_cifs_symlink, | ||
947 | }; | 948 | }; |
948 | 949 | ||
949 | struct smb_version_values smb1_values = { | 950 | struct smb_version_values smb1_values = { |