diff options
author | Steve French <sfrench@us.ibm.com> | 2008-05-14 21:50:56 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2008-05-14 21:50:56 -0400 |
commit | 646dd539878a194bc14b104621c0b2b33587e40f (patch) | |
tree | ba3e9a8a9565e66ea53905b209438fae6d413853 | |
parent | 35fc37d5175091c36d034a28c057da0f9594ee7e (diff) |
[CIFS] Fix paths when share is in DFS to include proper prefix
Some versions of Samba (3.2-pre e.g.) are stricter about checking to make sure that
paths in DFS name spaces are sent in the form \\server\share\dir\subdir ...
instead of \dir\subdir
Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r-- | fs/cifs/cifsproto.h | 3 | ||||
-rw-r--r-- | fs/cifs/connect.c | 26 | ||||
-rw-r--r-- | fs/cifs/dir.c | 28 | ||||
-rw-r--r-- | fs/cifs/inode.c | 65 | ||||
-rw-r--r-- | fs/cifs/link.c | 42 |
5 files changed, 37 insertions, 127 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 08248e85b788..845b18e1abe5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -150,9 +150,6 @@ extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, | |||
150 | unsigned int *number_of_UNC_in_array, | 150 | unsigned int *number_of_UNC_in_array, |
151 | const struct nls_table *nls_codepage, int remap); | 151 | const struct nls_table *nls_codepage, int remap); |
152 | 152 | ||
153 | extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | ||
154 | const char *old_path, | ||
155 | const struct nls_table *nls_codepage, int remap); | ||
156 | extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | 153 | extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, |
157 | const char *old_path, | 154 | const char *old_path, |
158 | const struct nls_table *nls_codepage, | 155 | const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7c2e5ea03305..d5747e30f1c9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1419,27 +1419,6 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) | |||
1419 | } | 1419 | } |
1420 | 1420 | ||
1421 | int | 1421 | int |
1422 | connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | ||
1423 | const char *old_path, const struct nls_table *nls_codepage, | ||
1424 | int remap) | ||
1425 | { | ||
1426 | struct dfs_info3_param *referrals = NULL; | ||
1427 | unsigned int num_referrals; | ||
1428 | int rc = 0; | ||
1429 | |||
1430 | rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage, | ||
1431 | &num_referrals, &referrals, remap); | ||
1432 | |||
1433 | /* BB Add in code to: if valid refrl, if not ip address contact | ||
1434 | the helper that resolves tcp names, mount to it, try to | ||
1435 | tcon to it unmount it if fail */ | ||
1436 | |||
1437 | kfree(referrals); | ||
1438 | |||
1439 | return rc; | ||
1440 | } | ||
1441 | |||
1442 | int | ||
1443 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | 1422 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, |
1444 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, | 1423 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, |
1445 | struct dfs_info3_param **preferrals, int remap) | 1424 | struct dfs_info3_param **preferrals, int remap) |
@@ -2161,10 +2140,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2161 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) | 2140 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) |
2162 | && (strchr(volume_info.UNC + 3, '/') == | 2141 | && (strchr(volume_info.UNC + 3, '/') == |
2163 | NULL)) { | 2142 | NULL)) { |
2164 | rc = connect_to_dfs_path(xid, pSesInfo, | 2143 | /* rc = connect_to_dfs_path(xid, pSesInfo, |
2165 | "", cifs_sb->local_nls, | 2144 | "", cifs_sb->local_nls, |
2166 | cifs_sb->mnt_cifs_flags & | 2145 | cifs_sb->mnt_cifs_flags & |
2167 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 2146 | CIFS_MOUNT_MAP_SPECIAL_CHR);*/ |
2147 | cFYI(1, ("DFS root not supported")); | ||
2168 | rc = -ENODEV; | 2148 | rc = -ENODEV; |
2169 | goto out; | 2149 | goto out; |
2170 | } else { | 2150 | } else { |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e4e0078a0526..05afe33ea644 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -49,18 +49,25 @@ build_path_from_dentry(struct dentry *direntry) | |||
49 | struct dentry *temp; | 49 | struct dentry *temp; |
50 | int namelen; | 50 | int namelen; |
51 | int pplen; | 51 | int pplen; |
52 | int dfsplen; | ||
52 | char *full_path; | 53 | char *full_path; |
53 | char dirsep; | 54 | char dirsep; |
55 | struct cifs_sb_info *cifs_sb; | ||
54 | 56 | ||
55 | if (direntry == NULL) | 57 | if (direntry == NULL) |
56 | return NULL; /* not much we can do if dentry is freed and | 58 | return NULL; /* not much we can do if dentry is freed and |
57 | we need to reopen the file after it was closed implicitly | 59 | we need to reopen the file after it was closed implicitly |
58 | when the server crashed */ | 60 | when the server crashed */ |
59 | 61 | ||
60 | dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); | 62 | cifs_sb = CIFS_SB(direntry->d_sb); |
61 | pplen = CIFS_SB(direntry->d_sb)->prepathlen; | 63 | dirsep = CIFS_DIR_SEP(cifs_sb); |
64 | pplen = cifs_sb->prepathlen; | ||
65 | if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS)) | ||
66 | dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1); | ||
67 | else | ||
68 | dfsplen = 0; | ||
62 | cifs_bp_rename_retry: | 69 | cifs_bp_rename_retry: |
63 | namelen = pplen; | 70 | namelen = pplen + dfsplen; |
64 | for (temp = direntry; !IS_ROOT(temp);) { | 71 | for (temp = direntry; !IS_ROOT(temp);) { |
65 | namelen += (1 + temp->d_name.len); | 72 | namelen += (1 + temp->d_name.len); |
66 | temp = temp->d_parent; | 73 | temp = temp->d_parent; |
@@ -91,7 +98,7 @@ cifs_bp_rename_retry: | |||
91 | return NULL; | 98 | return NULL; |
92 | } | 99 | } |
93 | } | 100 | } |
94 | if (namelen != pplen) { | 101 | if (namelen != pplen + dfsplen) { |
95 | cERROR(1, | 102 | cERROR(1, |
96 | ("did not end path lookup where expected namelen is %d", | 103 | ("did not end path lookup where expected namelen is %d", |
97 | namelen)); | 104 | namelen)); |
@@ -107,7 +114,18 @@ cifs_bp_rename_retry: | |||
107 | since the '\' is a valid posix character so we can not switch | 114 | since the '\' is a valid posix character so we can not switch |
108 | those safely to '/' if any are found in the middle of the prepath */ | 115 | those safely to '/' if any are found in the middle of the prepath */ |
109 | /* BB test paths to Windows with '/' in the midst of prepath */ | 116 | /* BB test paths to Windows with '/' in the midst of prepath */ |
110 | strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen); | 117 | |
118 | if (dfsplen) { | ||
119 | strncpy(full_path, cifs_sb->tcon->treeName, dfsplen); | ||
120 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { | ||
121 | int i; | ||
122 | for (i = 0; i < dfsplen; i++) { | ||
123 | if (full_path[i] == '\\') | ||
124 | full_path[i] = '/'; | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen); | ||
111 | return full_path; | 129 | return full_path; |
112 | } | 130 | } |
113 | 131 | ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 2d53b436d511..9d9b56a9c08e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -161,52 +161,18 @@ static void cifs_unix_info_to_inode(struct inode *inode, | |||
161 | spin_unlock(&inode->i_lock); | 161 | spin_unlock(&inode->i_lock); |
162 | } | 162 | } |
163 | 163 | ||
164 | static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb, | ||
165 | const char *search_path) | ||
166 | { | ||
167 | int tree_len; | ||
168 | int path_len; | ||
169 | int i; | ||
170 | char *tmp_path; | ||
171 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
172 | |||
173 | if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS)) | ||
174 | return search_path; | ||
175 | |||
176 | /* use full path name for working with DFS */ | ||
177 | tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1); | ||
178 | path_len = strnlen(search_path, MAX_PATHCONF); | ||
179 | |||
180 | tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL); | ||
181 | if (tmp_path == NULL) | ||
182 | return search_path; | ||
183 | |||
184 | strncpy(tmp_path, pTcon->treeName, tree_len); | ||
185 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | ||
186 | for (i = 0; i < tree_len; i++) { | ||
187 | if (tmp_path[i] == '\\') | ||
188 | tmp_path[i] = '/'; | ||
189 | } | ||
190 | strncpy(tmp_path+tree_len, search_path, path_len); | ||
191 | tmp_path[tree_len+path_len] = 0; | ||
192 | return tmp_path; | ||
193 | } | ||
194 | |||
195 | int cifs_get_inode_info_unix(struct inode **pinode, | 164 | int cifs_get_inode_info_unix(struct inode **pinode, |
196 | const unsigned char *search_path, struct super_block *sb, int xid) | 165 | const unsigned char *full_path, struct super_block *sb, int xid) |
197 | { | 166 | { |
198 | int rc = 0; | 167 | int rc = 0; |
199 | FILE_UNIX_BASIC_INFO findData; | 168 | FILE_UNIX_BASIC_INFO findData; |
200 | struct cifsTconInfo *pTcon; | 169 | struct cifsTconInfo *pTcon; |
201 | struct inode *inode; | 170 | struct inode *inode; |
202 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 171 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
203 | const unsigned char *full_path; | ||
204 | bool is_dfs_referral = false; | 172 | bool is_dfs_referral = false; |
205 | 173 | ||
206 | pTcon = cifs_sb->tcon; | 174 | pTcon = cifs_sb->tcon; |
207 | cFYI(1, ("Getting info on %s", search_path)); | 175 | cFYI(1, ("Getting info on %s", full_path)); |
208 | |||
209 | full_path = cifs_get_search_path(cifs_sb, search_path); | ||
210 | 176 | ||
211 | try_again_CIFSSMBUnixQPathInfo: | 177 | try_again_CIFSSMBUnixQPathInfo: |
212 | /* could have done a find first instead but this returns more info */ | 178 | /* could have done a find first instead but this returns more info */ |
@@ -218,10 +184,6 @@ try_again_CIFSSMBUnixQPathInfo: | |||
218 | if (rc) { | 184 | if (rc) { |
219 | if (rc == -EREMOTE && !is_dfs_referral) { | 185 | if (rc == -EREMOTE && !is_dfs_referral) { |
220 | is_dfs_referral = true; | 186 | is_dfs_referral = true; |
221 | if (full_path != search_path) { | ||
222 | kfree(full_path); | ||
223 | full_path = search_path; | ||
224 | } | ||
225 | goto try_again_CIFSSMBUnixQPathInfo; | 187 | goto try_again_CIFSSMBUnixQPathInfo; |
226 | } | 188 | } |
227 | goto cgiiu_exit; | 189 | goto cgiiu_exit; |
@@ -271,8 +233,6 @@ try_again_CIFSSMBUnixQPathInfo: | |||
271 | cifs_set_ops(inode, is_dfs_referral); | 233 | cifs_set_ops(inode, is_dfs_referral); |
272 | } | 234 | } |
273 | cgiiu_exit: | 235 | cgiiu_exit: |
274 | if (full_path != search_path) | ||
275 | kfree(full_path); | ||
276 | return rc; | 236 | return rc; |
277 | } | 237 | } |
278 | 238 | ||
@@ -380,20 +340,19 @@ static int get_sfu_mode(struct inode *inode, | |||
380 | } | 340 | } |
381 | 341 | ||
382 | int cifs_get_inode_info(struct inode **pinode, | 342 | int cifs_get_inode_info(struct inode **pinode, |
383 | const unsigned char *search_path, FILE_ALL_INFO *pfindData, | 343 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, |
384 | struct super_block *sb, int xid, const __u16 *pfid) | 344 | struct super_block *sb, int xid, const __u16 *pfid) |
385 | { | 345 | { |
386 | int rc = 0; | 346 | int rc = 0; |
387 | struct cifsTconInfo *pTcon; | 347 | struct cifsTconInfo *pTcon; |
388 | struct inode *inode; | 348 | struct inode *inode; |
389 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 349 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
390 | const unsigned char *full_path = NULL; | ||
391 | char *buf = NULL; | 350 | char *buf = NULL; |
392 | bool adjustTZ = false; | 351 | bool adjustTZ = false; |
393 | bool is_dfs_referral = false; | 352 | bool is_dfs_referral = false; |
394 | 353 | ||
395 | pTcon = cifs_sb->tcon; | 354 | pTcon = cifs_sb->tcon; |
396 | cFYI(1, ("Getting info on %s", search_path)); | 355 | cFYI(1, ("Getting info on %s", full_path)); |
397 | 356 | ||
398 | if ((pfindData == NULL) && (*pinode != NULL)) { | 357 | if ((pfindData == NULL) && (*pinode != NULL)) { |
399 | if (CIFS_I(*pinode)->clientCanCacheRead) { | 358 | if (CIFS_I(*pinode)->clientCanCacheRead) { |
@@ -409,8 +368,6 @@ int cifs_get_inode_info(struct inode **pinode, | |||
409 | return -ENOMEM; | 368 | return -ENOMEM; |
410 | pfindData = (FILE_ALL_INFO *)buf; | 369 | pfindData = (FILE_ALL_INFO *)buf; |
411 | 370 | ||
412 | full_path = cifs_get_search_path(cifs_sb, search_path); | ||
413 | |||
414 | try_again_CIFSSMBQPathInfo: | 371 | try_again_CIFSSMBQPathInfo: |
415 | /* could do find first instead but this returns more info */ | 372 | /* could do find first instead but this returns more info */ |
416 | rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, | 373 | rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData, |
@@ -432,10 +389,6 @@ try_again_CIFSSMBQPathInfo: | |||
432 | if (rc) { | 389 | if (rc) { |
433 | if (rc == -EREMOTE && !is_dfs_referral) { | 390 | if (rc == -EREMOTE && !is_dfs_referral) { |
434 | is_dfs_referral = true; | 391 | is_dfs_referral = true; |
435 | if (full_path != search_path) { | ||
436 | kfree(full_path); | ||
437 | full_path = search_path; | ||
438 | } | ||
439 | goto try_again_CIFSSMBQPathInfo; | 392 | goto try_again_CIFSSMBQPathInfo; |
440 | } | 393 | } |
441 | goto cgii_exit; | 394 | goto cgii_exit; |
@@ -470,7 +423,7 @@ try_again_CIFSSMBQPathInfo: | |||
470 | __u64 inode_num; | 423 | __u64 inode_num; |
471 | 424 | ||
472 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, | 425 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, |
473 | search_path, &inode_num, | 426 | full_path, &inode_num, |
474 | cifs_sb->local_nls, | 427 | cifs_sb->local_nls, |
475 | cifs_sb->mnt_cifs_flags & | 428 | cifs_sb->mnt_cifs_flags & |
476 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 429 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
@@ -539,7 +492,7 @@ try_again_CIFSSMBQPathInfo: | |||
539 | (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { | 492 | (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { |
540 | if (decode_sfu_inode(inode, | 493 | if (decode_sfu_inode(inode, |
541 | le64_to_cpu(pfindData->EndOfFile), | 494 | le64_to_cpu(pfindData->EndOfFile), |
542 | search_path, | 495 | full_path, |
543 | cifs_sb, xid)) | 496 | cifs_sb, xid)) |
544 | cFYI(1, ("Unrecognized sfu inode type")); | 497 | cFYI(1, ("Unrecognized sfu inode type")); |
545 | 498 | ||
@@ -582,12 +535,12 @@ try_again_CIFSSMBQPathInfo: | |||
582 | /* fill in 0777 bits from ACL */ | 535 | /* fill in 0777 bits from ACL */ |
583 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 536 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
584 | cFYI(1, ("Getting mode bits from ACL")); | 537 | cFYI(1, ("Getting mode bits from ACL")); |
585 | acl_to_uid_mode(inode, search_path, pfid); | 538 | acl_to_uid_mode(inode, full_path, pfid); |
586 | } | 539 | } |
587 | #endif | 540 | #endif |
588 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | 541 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { |
589 | /* fill in remaining high mode bits e.g. SUID, VTX */ | 542 | /* fill in remaining high mode bits e.g. SUID, VTX */ |
590 | get_sfu_mode(inode, search_path, cifs_sb, xid); | 543 | get_sfu_mode(inode, full_path, cifs_sb, xid); |
591 | } else if (atomic_read(&cifsInfo->inUse) == 0) { | 544 | } else if (atomic_read(&cifsInfo->inUse) == 0) { |
592 | inode->i_uid = cifs_sb->mnt_uid; | 545 | inode->i_uid = cifs_sb->mnt_uid; |
593 | inode->i_gid = cifs_sb->mnt_gid; | 546 | inode->i_gid = cifs_sb->mnt_gid; |
@@ -599,8 +552,6 @@ try_again_CIFSSMBQPathInfo: | |||
599 | cifs_set_ops(inode, is_dfs_referral); | 552 | cifs_set_ops(inode, is_dfs_referral); |
600 | } | 553 | } |
601 | cgii_exit: | 554 | cgii_exit: |
602 | if (full_path != search_path) | ||
603 | kfree(full_path); | ||
604 | kfree(buf); | 555 | kfree(buf); |
605 | return rc; | 556 | return rc; |
606 | } | 557 | } |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 1c2c3ce5020b..316f9830ce3b 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -295,45 +295,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) | |||
295 | cFYI(1, ("Error closing junction point " | 295 | cFYI(1, ("Error closing junction point " |
296 | "(open for ioctl)")); | 296 | "(open for ioctl)")); |
297 | } | 297 | } |
298 | /* BB unwind this long, nested function, or remove BB */ | 298 | /* If it is a DFS junction earlier we would have gotten |
299 | if (rc == -EIO) { | 299 | PATH_NOT_COVERED returned from server so we do |
300 | /* Query if DFS Junction */ | 300 | not need to request the DFS info here */ |
301 | unsigned int num_referrals = 0; | ||
302 | struct dfs_info3_param *refs = NULL; | ||
303 | tmp_path = | ||
304 | kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, | ||
305 | GFP_KERNEL); | ||
306 | if (tmp_path) { | ||
307 | strncpy(tmp_path, pTcon->treeName, | ||
308 | MAX_TREE_SIZE); | ||
309 | strncat(tmp_path, full_path, | ||
310 | MAX_PATHCONF); | ||
311 | rc = get_dfs_path(xid, pTcon->ses, | ||
312 | tmp_path, | ||
313 | cifs_sb->local_nls, | ||
314 | &num_referrals, &refs, | ||
315 | cifs_sb->mnt_cifs_flags & | ||
316 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
317 | cFYI(1, ("Get DFS for %s rc = %d ", | ||
318 | tmp_path, rc)); | ||
319 | if ((num_referrals == 0) && (rc == 0)) | ||
320 | rc = -EACCES; | ||
321 | else { | ||
322 | cFYI(1, ("num referral: %d", | ||
323 | num_referrals)); | ||
324 | if (refs && refs->path_name) { | ||
325 | strncpy(tmpbuffer, | ||
326 | refs->path_name, | ||
327 | len-1); | ||
328 | } | ||
329 | } | ||
330 | kfree(refs); | ||
331 | kfree(tmp_path); | ||
332 | } | ||
333 | /* BB add code like else decode referrals | ||
334 | then memcpy to tmpbuffer and free referrals | ||
335 | string array BB */ | ||
336 | } | ||
337 | } | 301 | } |
338 | } | 302 | } |
339 | /* BB Anything else to do to handle recursive links? */ | 303 | /* BB Anything else to do to handle recursive links? */ |