Commit b9a3260f authored by Steve French's avatar Steve French

[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
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment