Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7962670e authored by Igor Mammedov's avatar Igor Mammedov Committed by Steve French
Browse files

[CIFS] DFS patch that connects inode with dfs handling ops


 if DFS junction point

Signed-off-by: default avatarIgor Mammedov <niallain@gmail.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 84c6f604
Loading
Loading
Loading
Loading
+71 −62
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@
#include "cifs_fs_sb.h"


static void cifs_set_ops(struct inode *inode)
static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral)
{
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);

@@ -57,8 +57,12 @@ static void cifs_set_ops(struct inode *inode)
			inode->i_data.a_ops = &cifs_addr_ops;
		break;
	case S_IFDIR:
		if (is_dfs_referral) {
			inode->i_op = &cifs_dfs_referral_inode_operations;
		} else {
			inode->i_op = &cifs_dir_inode_ops;
			inode->i_fop = &cifs_dir_ops;
		}
		break;
	case S_IFLNK:
		inode->i_op = &cifs_symlink_inode_ops;
@@ -153,6 +157,30 @@ static void cifs_unix_info_to_inode(struct inode *inode,
	spin_unlock(&inode->i_lock);
}

static const unsigned char *cifs_get_search_path(struct cifsTconInfo *pTcon,
					const char *search_path)
{
	int tree_len;
	int path_len;
	char *tmp_path;

	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);
	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,
	const unsigned char *search_path, struct super_block *sb, int xid)
{
@@ -161,41 +189,28 @@ int cifs_get_inode_info_unix(struct inode **pinode,
	struct cifsTconInfo *pTcon;
	struct inode *inode;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	char *tmp_path;
	const unsigned char *full_path;
	bool is_dfs_referral = false;

	pTcon = cifs_sb->tcon;
	cFYI(1, ("Getting info on %s", search_path));

	full_path = cifs_get_search_path(pTcon, search_path);

try_again_CIFSSMBUnixQPathInfo:
	/* could have done a find first instead but this returns more info */
	rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
	rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &findData,
				  cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
					CIFS_MOUNT_MAP_SPECIAL_CHR);
/*	dump_mem("\nUnixQPathInfo return data", &findData,
		 sizeof(findData)); */
	if (rc) {
		if (rc == -EREMOTE) {
			tmp_path =
			    kmalloc(strnlen(pTcon->treeName,
					    MAX_TREE_SIZE + 1) +
				    strnlen(search_path, MAX_PATHCONF) + 1,
				    GFP_KERNEL);
			if (tmp_path == NULL)
				return -ENOMEM;

			/* have to skip first of the double backslash of
			   UNC name */
			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
			strncat(tmp_path, search_path, MAX_PATHCONF);
			rc = connect_to_dfs_path(xid, pTcon->ses,
						 /* treename + */ tmp_path,
						 cifs_sb->local_nls,
						 cifs_sb->mnt_cifs_flags &
						    CIFS_MOUNT_MAP_SPECIAL_CHR);
			kfree(tmp_path);

			/* BB fix up inode etc. */
		} else if (rc) {
			return rc;
		if (rc == -EREMOTE && !is_dfs_referral) {
			is_dfs_referral = true;
			full_path = search_path;
			goto try_again_CIFSSMBUnixQPathInfo;
		}
		goto cgiiu_exit;
	} else {
		struct cifsInodeInfo *cifsInfo;
		__u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
@@ -204,8 +219,10 @@ int cifs_get_inode_info_unix(struct inode **pinode,
		/* get new inode */
		if (*pinode == NULL) {
			*pinode = new_inode(sb);
			if (*pinode == NULL)
				return -ENOMEM;
			if (*pinode == NULL) {
				rc = -ENOMEM;
				goto cgiiu_exit;
			}
			/* Is an i_ino of zero legal? */
			/* Are there sanity checks we can use to ensure that
			   the server is really filling in that field? */
@@ -237,8 +254,11 @@ int cifs_get_inode_info_unix(struct inode **pinode,
			(unsigned long) inode->i_size,
			(unsigned long long)inode->i_blocks));

		cifs_set_ops(inode);
		cifs_set_ops(inode, is_dfs_referral);
	}
cgiiu_exit:
	if (full_path != search_path)
		kfree(full_path);
	return rc;
}

@@ -353,9 +373,10 @@ int cifs_get_inode_info(struct inode **pinode,
	struct cifsTconInfo *pTcon;
	struct inode *inode;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
	char *tmp_path;
	const unsigned char *full_path = NULL;
	char *buf = NULL;
	int adjustTZ = FALSE;
	bool is_dfs_referral = false;

	pTcon = cifs_sb->tcon;
	cFYI(1, ("Getting info on %s", search_path));
@@ -373,8 +394,12 @@ int cifs_get_inode_info(struct inode **pinode,
		if (buf == NULL)
			return -ENOMEM;
		pfindData = (FILE_ALL_INFO *)buf;

		full_path = cifs_get_search_path(pTcon, search_path);

try_again_CIFSSMBQPathInfo:
		/* could do find first instead but this returns more info */
		rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
		rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
			      0 /* not legacy */,
			      cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
				CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -382,7 +407,7 @@ int cifs_get_inode_info(struct inode **pinode,
		when server claims no NT SMB support and the above call
		failed at least once - set flag in tcon or mount */
		if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
			rc = SMBQueryInformation(xid, pTcon, search_path,
			rc = SMBQueryInformation(xid, pTcon, full_path,
					pfindData, cifs_sb->local_nls,
					cifs_sb->mnt_cifs_flags &
					  CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -391,31 +416,12 @@ int cifs_get_inode_info(struct inode **pinode,
	}
	/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
	if (rc) {
		if (rc == -EREMOTE) {
			tmp_path =
			    kmalloc(strnlen
				    (pTcon->treeName,
				     MAX_TREE_SIZE + 1) +
				    strnlen(search_path, MAX_PATHCONF) + 1,
				    GFP_KERNEL);
			if (tmp_path == NULL) {
				kfree(buf);
				return -ENOMEM;
			}

			strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
			strncat(tmp_path, search_path, MAX_PATHCONF);
			rc = connect_to_dfs_path(xid, pTcon->ses,
						 /* treename + */ tmp_path,
						 cifs_sb->local_nls,
						 cifs_sb->mnt_cifs_flags &
						   CIFS_MOUNT_MAP_SPECIAL_CHR);
			kfree(tmp_path);
			/* BB fix up inode etc. */
		} else if (rc) {
			kfree(buf);
			return rc;
		if (rc == -EREMOTE && !is_dfs_referral) {
			is_dfs_referral = true;
			full_path = search_path;
			goto try_again_CIFSSMBQPathInfo;
		}
		goto cgii_exit;
	} else {
		struct cifsInodeInfo *cifsInfo;
		__u32 attr = le32_to_cpu(pfindData->Attributes);
@@ -424,8 +430,8 @@ int cifs_get_inode_info(struct inode **pinode,
		if (*pinode == NULL) {
			*pinode = new_inode(sb);
			if (*pinode == NULL) {
				kfree(buf);
				return -ENOMEM;
				rc = -ENOMEM;
				goto cgii_exit;
			}
			/* Is an i_ino of zero legal? Can we use that to check
			   if the server supports returning inode numbers?  Are
@@ -573,8 +579,11 @@ int cifs_get_inode_info(struct inode **pinode,
			atomic_set(&cifsInfo->inUse, 1);
		}

		cifs_set_ops(inode);
		cifs_set_ops(inode, is_dfs_referral);
	}
cgii_exit:
	if (full_path != search_path)
		kfree(full_path);
	kfree(buf);
	return rc;
}
@@ -804,7 +813,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
	local_size  = tmp_inode->i_size;

	cifs_unix_info_to_inode(tmp_inode, pData, 1);
	cifs_set_ops(tmp_inode);
	cifs_set_ops(tmp_inode, false);

	if (!S_ISREG(tmp_inode->i_mode))
		return;