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/readdir.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/readdir.c')
-rw-r--r-- | fs/cifs/readdir.c | 40 |
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 | */ | ||
141 | static bool | ||
142 | cifs_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 | |||
153 | static void | 137 | static void |
154 | cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) | 138 | cifs_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 | ||