diff options
author | Pavel Shilovsky <piastry@etersoft.ru> | 2013-10-23 09:49:47 -0400 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2013-11-11 17:31:03 -0500 |
commit | eb85d94bdd91fb4dbea4ee465d4349cbea4eaaca (patch) | |
tree | 217ed41bd6bdf55b5a7263d42ebab386f6377785 /fs/cifs/inode.c | |
parent | 6c86ae2928f9e4cbf0d5844f5fcfd549e3450b8c (diff) |
CIFS: Fix symbolic links usage
Now we treat any reparse point as a symbolic link and map it to a Unix
one that is not true in a common case due to many reparse point types
supported by SMB servers.
Distinguish reparse point types into two groups:
1) that can be accessed directly through a reparse point
(junctions, deduplicated files, NFS symlinks);
2) that need to be processed manually (Windows symbolic links, DFS);
and map only Windows symbolic links to Unix ones.
Cc: <stable@vger.kernel.org>
Acked-by: Jeff Layton <jlayton@redhat.com>
Reported-and-tested-by: Joao Correia <joaomiguelcorreia@gmail.com>
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/inode.c')
-rw-r--r-- | fs/cifs/inode.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 867b7cdc794a..36f9ebb93ceb 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -542,7 +542,8 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, | |||
542 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ | 542 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ |
543 | static void | 543 | static void |
544 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, | 544 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, |
545 | struct cifs_sb_info *cifs_sb, bool adjust_tz) | 545 | struct cifs_sb_info *cifs_sb, bool adjust_tz, |
546 | bool symlink) | ||
546 | { | 547 | { |
547 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); | 548 | struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); |
548 | 549 | ||
@@ -569,7 +570,11 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, | |||
569 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); | 570 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); |
570 | 571 | ||
571 | fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); | 572 | fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); |
572 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | 573 | |
574 | if (symlink) { | ||
575 | fattr->cf_mode = S_IFLNK; | ||
576 | fattr->cf_dtype = DT_LNK; | ||
577 | } else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | ||
573 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | 578 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; |
574 | fattr->cf_dtype = DT_DIR; | 579 | fattr->cf_dtype = DT_DIR; |
575 | /* | 580 | /* |
@@ -578,10 +583,6 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, | |||
578 | */ | 583 | */ |
579 | if (!tcon->unix_ext) | 584 | if (!tcon->unix_ext) |
580 | fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; | 585 | fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; |
581 | } else if (fattr->cf_cifsattrs & ATTR_REPARSE) { | ||
582 | fattr->cf_mode = S_IFLNK; | ||
583 | fattr->cf_dtype = DT_LNK; | ||
584 | fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); | ||
585 | } else { | 586 | } else { |
586 | fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; | 587 | fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; |
587 | fattr->cf_dtype = DT_REG; | 588 | fattr->cf_dtype = DT_REG; |
@@ -626,7 +627,8 @@ cifs_get_file_info(struct file *filp) | |||
626 | rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data); | 627 | rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data); |
627 | switch (rc) { | 628 | switch (rc) { |
628 | case 0: | 629 | case 0: |
629 | cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false); | 630 | cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false, |
631 | false); | ||
630 | break; | 632 | break; |
631 | case -EREMOTE: | 633 | case -EREMOTE: |
632 | cifs_create_dfs_fattr(&fattr, inode->i_sb); | 634 | cifs_create_dfs_fattr(&fattr, inode->i_sb); |
@@ -673,6 +675,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, | |||
673 | bool adjust_tz = false; | 675 | bool adjust_tz = false; |
674 | struct cifs_fattr fattr; | 676 | struct cifs_fattr fattr; |
675 | struct cifs_search_info *srchinf = NULL; | 677 | struct cifs_search_info *srchinf = NULL; |
678 | bool symlink = false; | ||
676 | 679 | ||
677 | tlink = cifs_sb_tlink(cifs_sb); | 680 | tlink = cifs_sb_tlink(cifs_sb); |
678 | if (IS_ERR(tlink)) | 681 | if (IS_ERR(tlink)) |
@@ -702,12 +705,12 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, | |||
702 | } | 705 | } |
703 | data = (FILE_ALL_INFO *)buf; | 706 | data = (FILE_ALL_INFO *)buf; |
704 | rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, | 707 | rc = server->ops->query_path_info(xid, tcon, cifs_sb, full_path, |
705 | data, &adjust_tz); | 708 | data, &adjust_tz, &symlink); |
706 | } | 709 | } |
707 | 710 | ||
708 | if (!rc) { | 711 | if (!rc) { |
709 | cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *)data, cifs_sb, | 712 | cifs_all_info_to_fattr(&fattr, data, cifs_sb, adjust_tz, |
710 | adjust_tz); | 713 | symlink); |
711 | } else if (rc == -EREMOTE) { | 714 | } else if (rc == -EREMOTE) { |
712 | cifs_create_dfs_fattr(&fattr, sb); | 715 | cifs_create_dfs_fattr(&fattr, sb); |
713 | rc = 0; | 716 | rc = 0; |