[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:
parent
0e4bbde94f
commit
b9a3260f25
|
@ -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 @@ try_again_CIFSSMBQPathInfo:
|
|||
}
|
||||
}
|
||||
/* 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 @@ try_again_CIFSSMBQPathInfo:
|
|||
/* 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 @@ try_again_CIFSSMBQPathInfo:
|
|||
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 @@ try_again_CIFSSMBQPathInfo:
|
|||
/* 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 @@ try_again_CIFSSMBQPathInfo:
|
|||
}
|
||||
|
||||
cifs_set_ops(inode, is_dfs_referral);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
cgii_exit:
|
||||
kfree(buf);
|
||||
return rc;
|
||||
|
|
Loading…
Reference in New Issue