[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: Steve French <sfrench@us.ibm.com>
This commit is contained in:
@@ -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,
|
|||||||
#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,
|
|||||||
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 @@ try_again_CIFSSMBQPathInfo:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 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 @@ try_again_CIFSSMBQPathInfo:
|
|||||||
/* 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 @@ try_again_CIFSSMBQPathInfo:
|
|||||||
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 @@ try_again_CIFSSMBQPathInfo:
|
|||||||
/* 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 @@ try_again_CIFSSMBQPathInfo:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
Reference in New Issue
Block a user