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

Commit b9a3260f authored by Steve French's avatar Steve French
Browse files

[CIFS] Enable DFS support for Windows query path info



Final piece for handling DFS in query_path_info, constructing a
fake inode for the junction directory which the submount will cover.

This handles the non-Unix (Windows etc.) code path.

Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 0e4bbde9
Loading
Loading
Loading
Loading
+178 −146
Original line number Diff line number Diff line
@@ -161,6 +161,12 @@ static void cifs_unix_info_to_inode(struct inode *inode,
	spin_unlock(&inode->i_lock);
}


/*
 *	Needed to setup inode data for the directory which is the
 *	junction to the new submount (ie to setup the fake directory
 *      which represents a DFS referral)
 */
static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
			       struct super_block *sb)
{
@@ -370,11 +376,42 @@ static int get_sfu_mode(struct inode *inode,
#endif
}

/*
 *	Needed to setup inode data for the directory which is the
 *	junction to the new submount (ie to setup the fake directory
 *      which represents a DFS referral)
 */
static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat,
			       struct super_block *sb)
{
	memset(pfnd_dat, sizeof(FILE_ALL_INFO), 0);

/*	__le64 pfnd_dat->AllocationSize = cpu_to_le64(0);
	__le64 pfnd_dat->EndOfFile = cpu_to_le64(0);
	__u8 pfnd_dat->DeletePending = 0;
	__u8 pfnd_data->Directory = 0;
	__le32 pfnd_dat->EASize = 0;
	__u64 pfnd_dat->IndexNumber = 0;
	__u64 pfnd_dat->IndexNumber1 = 0;  */
	pfnd_dat->CreationTime =
		cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	pfnd_dat->LastAccessTime =
		cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	pfnd_dat->LastWriteTime =
		cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	pfnd_dat->ChangeTime =
		cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
	pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY);
	pfnd_dat->NumberOfLinks = cpu_to_le32(2);
}

int cifs_get_inode_info(struct inode **pinode,
	const unsigned char *full_path, FILE_ALL_INFO *pfindData,
	struct super_block *sb, int xid, const __u16 *pfid)
{
	int rc = 0;
	__u32 attr;
	struct cifsInodeInfo *cifsInfo;
	struct cifsTconInfo *pTcon;
	struct inode *inode;
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
@@ -399,7 +436,6 @@ int cifs_get_inode_info(struct inode **pinode,
			return -ENOMEM;
		pfindData = (FILE_ALL_INFO *)buf;

try_again_CIFSSMBQPathInfo:
		/* could do find first instead but this returns more info */
		rc = CIFSSMBQPathInfo(xid, pTcon, full_path, pfindData,
			      0 /* not legacy */,
@@ -417,15 +453,14 @@ int cifs_get_inode_info(struct inode **pinode,
		}
	}
	/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
	if (rc) {
		if (rc == -EREMOTE && !is_dfs_referral) {
	if (rc == -EREMOTE) {
		is_dfs_referral = true;
			goto try_again_CIFSSMBQPathInfo;
		}
		fill_fake_finddata(pfindData, sb);
		rc = 0;
	} else if (rc)
		goto cgii_exit;
	} else {
		struct cifsInodeInfo *cifsInfo;
		__u32 attr = le32_to_cpu(pfindData->Attributes);

	attr = le32_to_cpu(pfindData->Attributes);

	/* get new inode */
	if (*pinode == NULL) {
@@ -442,8 +477,7 @@ int cifs_get_inode_info(struct inode **pinode,
		/* We can not use the IndexNumber field by default from
		   Windows or Samba (in ALL_INFO buf) but we can request
		   it explicitly.  It may not be unique presumably if
			   the server has multiple devices mounted under one
			   share */
		   the server has multiple devices mounted under one share */

		/* There may be higher info levels that work but are
		   there Windows server or network appliances for which
@@ -490,7 +524,7 @@ int cifs_get_inode_info(struct inode **pinode,
		    cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
	inode->i_ctime =
	    cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
		cFYI(0, ("Attributes came in as 0x%x", attr));
	cFYI(DBG2, ("Attributes came in as 0x%x", attr));
	if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
		inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
		inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
@@ -521,27 +555,22 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB Finish for SFU style symlinks and devices */
	} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
		   (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
			if (decode_sfu_inode(inode,
					 le64_to_cpu(pfindData->EndOfFile),
					 full_path,
					 cifs_sb, xid))
		if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile),
				     full_path, cifs_sb, xid))
			cFYI(1, ("Unrecognized sfu inode type"));

		cFYI(1, ("sfu mode 0%o", inode->i_mode));
	} else {
		inode->i_mode |= S_IFREG;
			/* treat the dos attribute of read-only as read-only
			   mode e.g. 555 */
		/* treat dos attribute of read-only as read-only mode eg 555 */
		if (cifsInfo->cifsAttrs & ATTR_READONLY)
			inode->i_mode &= ~(S_IWUGO);
		else if ((inode->i_mode & S_IWUGO) == 0)
			/* the ATTR_READONLY flag may have been	*/
			/* changed on server -- set any w bits	*/
			/* allowed by mnt_file_mode		*/
				inode->i_mode |= (S_IWUGO &
						  cifs_sb->mnt_file_mode);
		/* BB add code here -
		   validate if device or weird share or device type? */
			inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
	/* BB add code to validate if device or weird share or device type? */
	}

	spin_lock(&inode->i_lock);
@@ -581,7 +610,10 @@ int cifs_get_inode_info(struct inode **pinode,
	}

	cifs_set_ops(inode, is_dfs_referral);
	}




cgii_exit:
	kfree(buf);
	return rc;