aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/readdir.c
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2013-10-23 09:49:47 -0400
committerSteve French <smfrench@gmail.com>2013-11-11 17:31:03 -0500
commiteb85d94bdd91fb4dbea4ee465d4349cbea4eaaca (patch)
tree217ed41bd6bdf55b5a7263d42ebab386f6377785 /fs/cifs/readdir.c
parent6c86ae2928f9e4cbf0d5844f5fcfd549e3450b8c (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/readdir.c')
-rw-r--r--fs/cifs/readdir.c40
1 files changed, 8 insertions, 32 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 53a75f3d0179..5940ecabbe6a 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -134,22 +134,6 @@ out:
134 dput(dentry); 134 dput(dentry);
135} 135}
136 136
137/*
138 * Is it possible that this directory might turn out to be a DFS referral
139 * once we go to try and use it?
140 */
141static bool
142cifs_dfs_is_possible(struct cifs_sb_info *cifs_sb)
143{
144#ifdef CONFIG_CIFS_DFS_UPCALL
145 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
146
147 if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
148 return true;
149#endif
150 return false;
151}
152
153static void 137static void
154cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) 138cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
155{ 139{
@@ -159,27 +143,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
159 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { 143 if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
160 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; 144 fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
161 fattr->cf_dtype = DT_DIR; 145 fattr->cf_dtype = DT_DIR;
162 /*
163 * Windows CIFS servers generally make DFS referrals look
164 * like directories in FIND_* responses with the reparse
165 * attribute flag also set (since DFS junctions are
166 * reparse points). We must revalidate at least these
167 * directory inodes before trying to use them (if
168 * they are DFS we will get PATH_NOT_COVERED back
169 * when queried directly and can then try to connect
170 * to the DFS target)
171 */
172 if (cifs_dfs_is_possible(cifs_sb) &&
173 (fattr->cf_cifsattrs & ATTR_REPARSE))
174 fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
175 } else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
176 fattr->cf_mode = S_IFLNK;
177 fattr->cf_dtype = DT_LNK;
178 } else { 146 } else {
179 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; 147 fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
180 fattr->cf_dtype = DT_REG; 148 fattr->cf_dtype = DT_REG;
181 } 149 }
182 150
151 /*
152 * We need to revalidate it further to make a decision about whether it
153 * is a symbolic link, DFS referral or a reparse point with a direct
154 * access like junctions, deduplicated files, NFS symlinks.
155 */
156 if (fattr->cf_cifsattrs & ATTR_REPARSE)
157 fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
158
183 /* non-unix readdir doesn't provide nlink */ 159 /* non-unix readdir doesn't provide nlink */
184 fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; 160 fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
185 161