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, ...@@ -161,6 +161,12 @@ static void cifs_unix_info_to_inode(struct inode *inode,
spin_unlock(&inode->i_lock); 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, static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
struct super_block *sb) struct super_block *sb)
{ {
...@@ -370,11 +376,42 @@ static int get_sfu_mode(struct inode *inode, ...@@ -370,11 +376,42 @@ static int get_sfu_mode(struct inode *inode,
#endif #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, int cifs_get_inode_info(struct inode **pinode,
const unsigned char *full_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;
__u32 attr;
struct cifsInodeInfo *cifsInfo;
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);
...@@ -399,7 +436,6 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -399,7 +436,6 @@ int cifs_get_inode_info(struct inode **pinode,
return -ENOMEM; return -ENOMEM;
pfindData = (FILE_ALL_INFO *)buf; pfindData = (FILE_ALL_INFO *)buf;
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,
0 /* not legacy */, 0 /* not legacy */,
...@@ -417,15 +453,14 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -417,15 +453,14 @@ int cifs_get_inode_info(struct inode **pinode,
} }
} }
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) { if (rc == -EREMOTE) {
if (rc == -EREMOTE && !is_dfs_referral) {
is_dfs_referral = true; is_dfs_referral = true;
goto try_again_CIFSSMBQPathInfo; fill_fake_finddata(pfindData, sb);
} rc = 0;
} else if (rc)
goto cgii_exit; goto cgii_exit;
} else {
struct cifsInodeInfo *cifsInfo; attr = le32_to_cpu(pfindData->Attributes);
__u32 attr = le32_to_cpu(pfindData->Attributes);
/* get new inode */ /* get new inode */
if (*pinode == NULL) { if (*pinode == NULL) {
...@@ -442,8 +477,7 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -442,8 +477,7 @@ int cifs_get_inode_info(struct inode **pinode,
/* We can not use the IndexNumber field by default from /* We can not use the IndexNumber field by default from
Windows or Samba (in ALL_INFO buf) but we can request Windows or Samba (in ALL_INFO buf) but we can request
it explicitly. It may not be unique presumably if it explicitly. It may not be unique presumably if
the server has multiple devices mounted under one the server has multiple devices mounted under one share */
share */
/* There may be higher info levels that work but are /* There may be higher info levels that work but are
there Windows server or network appliances for which there Windows server or network appliances for which
...@@ -490,7 +524,7 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -490,7 +524,7 @@ int cifs_get_inode_info(struct inode **pinode,
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
inode->i_ctime = inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); 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)) { if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
inode->i_mtime.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, ...@@ -521,27 +555,22 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB Finish for SFU style symlinks and devices */ /* BB Finish for SFU style symlinks and devices */
} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(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), full_path, cifs_sb, xid))
full_path,
cifs_sb, xid))
cFYI(1, ("Unrecognized sfu inode type")); cFYI(1, ("Unrecognized sfu inode type"));
cFYI(1, ("sfu mode 0%o", inode->i_mode)); cFYI(1, ("sfu mode 0%o", inode->i_mode));
} else { } else {
inode->i_mode |= S_IFREG; inode->i_mode |= S_IFREG;
/* treat the dos attribute of read-only as read-only /* treat dos attribute of read-only as read-only mode eg 555 */
mode e.g. 555 */
if (cifsInfo->cifsAttrs & ATTR_READONLY) if (cifsInfo->cifsAttrs & ATTR_READONLY)
inode->i_mode &= ~(S_IWUGO); inode->i_mode &= ~(S_IWUGO);
else if ((inode->i_mode & S_IWUGO) == 0) else if ((inode->i_mode & S_IWUGO) == 0)
/* the ATTR_READONLY flag may have been */ /* the ATTR_READONLY flag may have been */
/* changed on server -- set any w bits */ /* changed on server -- set any w bits */
/* allowed by mnt_file_mode */ /* allowed by mnt_file_mode */
inode->i_mode |= (S_IWUGO & inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
cifs_sb->mnt_file_mode); /* BB add code to validate if device or weird share or device type? */
/* BB add code here -
validate if device or weird share or device type? */
} }
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
...@@ -581,7 +610,10 @@ int cifs_get_inode_info(struct inode **pinode, ...@@ -581,7 +610,10 @@ int cifs_get_inode_info(struct inode **pinode,
} }
cifs_set_ops(inode, is_dfs_referral); cifs_set_ops(inode, is_dfs_referral);
}
cgii_exit: cgii_exit:
kfree(buf); kfree(buf);
return rc; 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