aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-05-14 21:50:56 -0400
committerSteve French <sfrench@us.ibm.com>2008-05-14 21:50:56 -0400
commit646dd539878a194bc14b104621c0b2b33587e40f (patch)
treeba3e9a8a9565e66ea53905b209438fae6d413853
parent35fc37d5175091c36d034a28c057da0f9594ee7e (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.h3
-rw-r--r--fs/cifs/connect.c26
-rw-r--r--fs/cifs/dir.c28
-rw-r--r--fs/cifs/inode.c65
-rw-r--r--fs/cifs/link.c42
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
153extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
154 const char *old_path,
155 const struct nls_table *nls_codepage, int remap);
156extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, 153extern 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
1421int 1421int
1422connect_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
1442int
1443get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, 1422get_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;
62cifs_bp_rename_retry: 69cifs_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
164static 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
195int cifs_get_inode_info_unix(struct inode **pinode, 164int 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
211try_again_CIFSSMBUnixQPathInfo: 177try_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 }
273cgiiu_exit: 235cgiiu_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
382int cifs_get_inode_info(struct inode **pinode, 342int 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
414try_again_CIFSSMBQPathInfo: 371try_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 }
601cgii_exit: 554cgii_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? */