Browse Source

[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>
Steve French 17 years ago
parent
commit
646dd53987
5 changed files with 37 additions and 127 deletions
  1. 0 3
      fs/cifs/cifsproto.h
  2. 3 23
      fs/cifs/connect.c
  3. 23 5
      fs/cifs/dir.c
  4. 8 57
      fs/cifs/inode.c
  5. 3 39
      fs/cifs/link.c

+ 0 - 3
fs/cifs/cifsproto.h

@@ -150,9 +150,6 @@ extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
 			unsigned int *number_of_UNC_in_array,
 			unsigned int *number_of_UNC_in_array,
 			const struct nls_table *nls_codepage, int remap);
 			const struct nls_table *nls_codepage, int remap);
 
 
-extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
-			const char *old_path,
-			const struct nls_table *nls_codepage, int remap);
 extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 			const char *old_path,
 			const char *old_path,
 			const struct nls_table *nls_codepage,
 			const struct nls_table *nls_codepage,

+ 3 - 23
fs/cifs/connect.c

@@ -1418,27 +1418,6 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
 	return NULL;
 	return NULL;
 }
 }
 
 
-int
-connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
-		    const char *old_path, const struct nls_table *nls_codepage,
-		    int remap)
-{
-	struct dfs_info3_param *referrals = NULL;
-	unsigned int num_referrals;
-	int rc = 0;
-
-	rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
-			&num_referrals, &referrals, remap);
-
-	/* BB Add in code to: if valid refrl, if not ip address contact
-		the helper that resolves tcp names, mount to it, try to
-		tcon to it unmount it if fail */
-
-	kfree(referrals);
-
-	return rc;
-}
-
 int
 int
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
 get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
 	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
 	     const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
@@ -2161,10 +2140,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 				if ((strchr(volume_info.UNC + 3, '\\') == NULL)
 				if ((strchr(volume_info.UNC + 3, '\\') == NULL)
 				    && (strchr(volume_info.UNC + 3, '/') ==
 				    && (strchr(volume_info.UNC + 3, '/') ==
 					NULL)) {
 					NULL)) {
-					rc = connect_to_dfs_path(xid, pSesInfo,
+/*					rc = connect_to_dfs_path(xid, pSesInfo,
 						"", cifs_sb->local_nls,
 						"", cifs_sb->local_nls,
 						cifs_sb->mnt_cifs_flags &
 						cifs_sb->mnt_cifs_flags &
-						  CIFS_MOUNT_MAP_SPECIAL_CHR);
+						  CIFS_MOUNT_MAP_SPECIAL_CHR);*/
+					cFYI(1, ("DFS root not supported"));
 					rc = -ENODEV;
 					rc = -ENODEV;
 					goto out;
 					goto out;
 				} else {
 				} else {

+ 23 - 5
fs/cifs/dir.c

@@ -49,18 +49,25 @@ build_path_from_dentry(struct dentry *direntry)
 	struct dentry *temp;
 	struct dentry *temp;
 	int namelen;
 	int namelen;
 	int pplen;
 	int pplen;
+	int dfsplen;
 	char *full_path;
 	char *full_path;
 	char dirsep;
 	char dirsep;
+	struct cifs_sb_info *cifs_sb;
 
 
 	if (direntry == NULL)
 	if (direntry == NULL)
 		return NULL;  /* not much we can do if dentry is freed and
 		return NULL;  /* not much we can do if dentry is freed and
 		we need to reopen the file after it was closed implicitly
 		we need to reopen the file after it was closed implicitly
 		when the server crashed */
 		when the server crashed */
 
 
-	dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb));
-	pplen = CIFS_SB(direntry->d_sb)->prepathlen;
+	cifs_sb = CIFS_SB(direntry->d_sb);
+	dirsep = CIFS_DIR_SEP(cifs_sb);
+	pplen = cifs_sb->prepathlen;
+	if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
+		dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
+	else
+		dfsplen = 0;
 cifs_bp_rename_retry:
 cifs_bp_rename_retry:
-	namelen = pplen;
+	namelen = pplen + dfsplen;
 	for (temp = direntry; !IS_ROOT(temp);) {
 	for (temp = direntry; !IS_ROOT(temp);) {
 		namelen += (1 + temp->d_name.len);
 		namelen += (1 + temp->d_name.len);
 		temp = temp->d_parent;
 		temp = temp->d_parent;
@@ -91,7 +98,7 @@ cifs_bp_rename_retry:
 			return NULL;
 			return NULL;
 		}
 		}
 	}
 	}
-	if (namelen != pplen) {
+	if (namelen != pplen + dfsplen) {
 		cERROR(1,
 		cERROR(1,
 		       ("did not end path lookup where expected namelen is %d",
 		       ("did not end path lookup where expected namelen is %d",
 			namelen));
 			namelen));
@@ -107,7 +114,18 @@ cifs_bp_rename_retry:
 	   since the '\' is a valid posix character so we can not switch
 	   since the '\' is a valid posix character so we can not switch
 	   those safely to '/' if any are found in the middle of the prepath */
 	   those safely to '/' if any are found in the middle of the prepath */
 	/* BB test paths to Windows with '/' in the midst of prepath */
 	/* BB test paths to Windows with '/' in the midst of prepath */
-	strncpy(full_path, CIFS_SB(direntry->d_sb)->prepath, pplen);
+
+	if (dfsplen) {
+		strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
+			int i;
+			for (i = 0; i < dfsplen; i++) {
+				if (full_path[i] == '\\')
+					full_path[i] = '/';
+			}
+		}
+	}
+	strncpy(full_path + dfsplen, CIFS_SB(direntry->d_sb)->prepath, pplen);
 	return full_path;
 	return full_path;
 }
 }
 
 

+ 8 - 57
fs/cifs/inode.c

@@ -161,52 +161,18 @@ static void cifs_unix_info_to_inode(struct inode *inode,
 	spin_unlock(&inode->i_lock);
 	spin_unlock(&inode->i_lock);
 }
 }
 
 
-static const unsigned char *cifs_get_search_path(struct cifs_sb_info *cifs_sb,
-						const char *search_path)
-{
-	int tree_len;
-	int path_len;
-	int i;
-	char *tmp_path;
-	struct cifsTconInfo *pTcon = cifs_sb->tcon;
-
-	if (!(pTcon->Flags & SMB_SHARE_IS_IN_DFS))
-		return search_path;
-
-	/* use full path name for working with DFS */
-	tree_len = strnlen(pTcon->treeName, MAX_TREE_SIZE + 1);
-	path_len = strnlen(search_path, MAX_PATHCONF);
-
-	tmp_path = kmalloc(tree_len+path_len+1, GFP_KERNEL);
-	if (tmp_path == NULL)
-		return search_path;
-
-	strncpy(tmp_path, pTcon->treeName, tree_len);
-	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
-		for (i = 0; i < tree_len; i++) {
-			if (tmp_path[i] == '\\')
-				tmp_path[i] = '/';
-		}
-	strncpy(tmp_path+tree_len, search_path, path_len);
-	tmp_path[tree_len+path_len] = 0;
-	return tmp_path;
-}
-
 int cifs_get_inode_info_unix(struct inode **pinode,
 int cifs_get_inode_info_unix(struct inode **pinode,
-	const unsigned char *search_path, struct super_block *sb, int xid)
+	const unsigned char *full_path, struct super_block *sb, int xid)
 {
 {
 	int rc = 0;
 	int rc = 0;
 	FILE_UNIX_BASIC_INFO findData;
 	FILE_UNIX_BASIC_INFO findData;
 	struct cifsTconInfo *pTcon;
 	struct cifsTconInfo *pTcon;
 	struct inode *inode;
 	struct inode *inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	const unsigned char *full_path;
 	bool is_dfs_referral = false;
 	bool is_dfs_referral = false;
 
 
 	pTcon = cifs_sb->tcon;
 	pTcon = cifs_sb->tcon;
-	cFYI(1, ("Getting info on %s", search_path));
-
-	full_path = cifs_get_search_path(cifs_sb, search_path);
+	cFYI(1, ("Getting info on %s", full_path));
 
 
 try_again_CIFSSMBUnixQPathInfo:
 try_again_CIFSSMBUnixQPathInfo:
 	/* could have done a find first instead but this returns more info */
 	/* could have done a find first instead but this returns more info */
@@ -218,10 +184,6 @@ try_again_CIFSSMBUnixQPathInfo:
 	if (rc) {
 	if (rc) {
 		if (rc == -EREMOTE && !is_dfs_referral) {
 		if (rc == -EREMOTE && !is_dfs_referral) {
 			is_dfs_referral = true;
 			is_dfs_referral = true;
-			if (full_path != search_path) {
-				kfree(full_path);
-				full_path = search_path;
-			}
 			goto try_again_CIFSSMBUnixQPathInfo;
 			goto try_again_CIFSSMBUnixQPathInfo;
 		}
 		}
 		goto cgiiu_exit;
 		goto cgiiu_exit;
@@ -271,8 +233,6 @@ try_again_CIFSSMBUnixQPathInfo:
 		cifs_set_ops(inode, is_dfs_referral);
 		cifs_set_ops(inode, is_dfs_referral);
 	}
 	}
 cgiiu_exit:
 cgiiu_exit:
-	if (full_path != search_path)
-		kfree(full_path);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -380,20 +340,19 @@ static int get_sfu_mode(struct inode *inode,
 }
 }
 
 
 int cifs_get_inode_info(struct inode **pinode,
 int cifs_get_inode_info(struct inode **pinode,
-	const unsigned char *search_path, FILE_ALL_INFO *pfindData,
+	const unsigned char *full_path, FILE_ALL_INFO *pfindData,
 	struct super_block *sb, int xid, const __u16 *pfid)
 	struct super_block *sb, int xid, const __u16 *pfid)
 {
 {
 	int rc = 0;
 	int rc = 0;
 	struct cifsTconInfo *pTcon;
 	struct cifsTconInfo *pTcon;
 	struct inode *inode;
 	struct inode *inode;
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
-	const unsigned char *full_path = NULL;
 	char *buf = NULL;
 	char *buf = NULL;
 	bool adjustTZ = false;
 	bool adjustTZ = false;
 	bool is_dfs_referral = false;
 	bool is_dfs_referral = false;
 
 
 	pTcon = cifs_sb->tcon;
 	pTcon = cifs_sb->tcon;
-	cFYI(1, ("Getting info on %s", search_path));
+	cFYI(1, ("Getting info on %s", full_path));
 
 
 	if ((pfindData == NULL) && (*pinode != NULL)) {
 	if ((pfindData == NULL) && (*pinode != NULL)) {
 		if (CIFS_I(*pinode)->clientCanCacheRead) {
 		if (CIFS_I(*pinode)->clientCanCacheRead) {
@@ -409,8 +368,6 @@ int cifs_get_inode_info(struct inode **pinode,
 			return -ENOMEM;
 			return -ENOMEM;
 		pfindData = (FILE_ALL_INFO *)buf;
 		pfindData = (FILE_ALL_INFO *)buf;
 
 
-		full_path = cifs_get_search_path(cifs_sb, search_path);
-
 try_again_CIFSSMBQPathInfo:
 try_again_CIFSSMBQPathInfo:
 		/* could do find first instead but this returns more info */
 		/* could do find first instead but this returns more info */
 		rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
 		rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
@@ -432,10 +389,6 @@ try_again_CIFSSMBQPathInfo:
 	if (rc) {
 	if (rc) {
 		if (rc == -EREMOTE && !is_dfs_referral) {
 		if (rc == -EREMOTE && !is_dfs_referral) {
 			is_dfs_referral = true;
 			is_dfs_referral = true;
-			if (full_path != search_path) {
-				kfree(full_path);
-				full_path = search_path;
-			}
 			goto try_again_CIFSSMBQPathInfo;
 			goto try_again_CIFSSMBQPathInfo;
 		}
 		}
 		goto cgii_exit;
 		goto cgii_exit;
@@ -470,7 +423,7 @@ try_again_CIFSSMBQPathInfo:
 				__u64 inode_num;
 				__u64 inode_num;
 
 
 				rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
 				rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
-					search_path, &inode_num,
+					full_path, &inode_num,
 					cifs_sb->local_nls,
 					cifs_sb->local_nls,
 					cifs_sb->mnt_cifs_flags &
 					cifs_sb->mnt_cifs_flags &
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
 						CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -539,7 +492,7 @@ try_again_CIFSSMBQPathInfo:
 			   (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
 			   (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
 			if (decode_sfu_inode(inode,
 			if (decode_sfu_inode(inode,
 					 le64_to_cpu(pfindData->EndOfFile),
 					 le64_to_cpu(pfindData->EndOfFile),
-					 search_path,
+					 full_path,
 					 cifs_sb, xid))
 					 cifs_sb, xid))
 				cFYI(1, ("Unrecognized sfu inode type"));
 				cFYI(1, ("Unrecognized sfu inode type"));
 
 
@@ -582,12 +535,12 @@ try_again_CIFSSMBQPathInfo:
 		/* fill in 0777 bits from ACL */
 		/* fill in 0777 bits from ACL */
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
 			cFYI(1, ("Getting mode bits from ACL"));
 			cFYI(1, ("Getting mode bits from ACL"));
-			acl_to_uid_mode(inode, search_path, pfid);
+			acl_to_uid_mode(inode, full_path, pfid);
 		}
 		}
 #endif
 #endif
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
 			/* fill in remaining high mode bits e.g. SUID, VTX */
 			/* fill in remaining high mode bits e.g. SUID, VTX */
-			get_sfu_mode(inode, search_path, cifs_sb, xid);
+			get_sfu_mode(inode, full_path, cifs_sb, xid);
 		} else if (atomic_read(&cifsInfo->inUse) == 0) {
 		} else if (atomic_read(&cifsInfo->inUse) == 0) {
 			inode->i_uid = cifs_sb->mnt_uid;
 			inode->i_uid = cifs_sb->mnt_uid;
 			inode->i_gid = cifs_sb->mnt_gid;
 			inode->i_gid = cifs_sb->mnt_gid;
@@ -599,8 +552,6 @@ try_again_CIFSSMBQPathInfo:
 		cifs_set_ops(inode, is_dfs_referral);
 		cifs_set_ops(inode, is_dfs_referral);
 	}
 	}
 cgii_exit:
 cgii_exit:
-	if (full_path != search_path)
-		kfree(full_path);
 	kfree(buf);
 	kfree(buf);
 	return rc;
 	return rc;
 }
 }

+ 3 - 39
fs/cifs/link.c

@@ -295,45 +295,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
 				cFYI(1, ("Error closing junction point "
 				cFYI(1, ("Error closing junction point "
 					 "(open for ioctl)"));
 					 "(open for ioctl)"));
 			}
 			}
-			/* BB unwind this long, nested function, or remove BB */
-			if (rc == -EIO) {
-				/* Query if DFS Junction */
-				unsigned int num_referrals = 0;
-				struct dfs_info3_param *refs = NULL;
-				tmp_path =
-					kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
-						GFP_KERNEL);
-				if (tmp_path) {
-					strncpy(tmp_path, pTcon->treeName,
-						MAX_TREE_SIZE);
-					strncat(tmp_path, full_path,
-						MAX_PATHCONF);
-					rc = get_dfs_path(xid, pTcon->ses,
-						tmp_path,
-						cifs_sb->local_nls,
-						&num_referrals, &refs,
-						cifs_sb->mnt_cifs_flags &
-						    CIFS_MOUNT_MAP_SPECIAL_CHR);
-					cFYI(1, ("Get DFS for %s rc = %d ",
-						tmp_path, rc));
-					if ((num_referrals == 0) && (rc == 0))
-						rc = -EACCES;
-					else {
-						cFYI(1, ("num referral: %d",
-							num_referrals));
-						if (refs && refs->path_name) {
-							strncpy(tmpbuffer,
-								refs->path_name,
-								len-1);
-						}
-					}
-					kfree(refs);
-					kfree(tmp_path);
-}
-				/* BB add code like else decode referrals
-				then memcpy to tmpbuffer and free referrals
-				string array BB */
-			}
+			/* If it is a DFS junction earlier we would have gotten
+			   PATH_NOT_COVERED returned from server so we do
+			   not need to request the DFS info here */
 		}
 		}
 	}
 	}
 	/* BB Anything else to do to handle recursive links? */
 	/* BB Anything else to do to handle recursive links? */