smb: client: parse reparse point flag in create response
Check for reparse point flag on query info calls as specified in MS-SMB2 2.2.14. Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
348a04a8d1
commit
5f71ebc412
5 changed files with 173 additions and 94 deletions
|
@ -199,6 +199,10 @@ struct cifs_open_info_data {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define cifs_open_data_reparse(d) \
|
||||||
|
((d)->reparse_point || \
|
||||||
|
(le32_to_cpu((d)->fi.Attributes) & ATTR_REPARSE))
|
||||||
|
|
||||||
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
|
static inline void cifs_free_open_info(struct cifs_open_info_data *data)
|
||||||
{
|
{
|
||||||
kfree(data->symlink_target);
|
kfree(data->symlink_target);
|
||||||
|
|
|
@ -207,6 +207,9 @@ extern struct inode *cifs_iget(struct super_block *sb,
|
||||||
int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||||
struct cifs_open_info_data *data, struct super_block *sb, int xid,
|
struct cifs_open_info_data *data, struct super_block *sb, int xid,
|
||||||
const struct cifs_fid *fid);
|
const struct cifs_fid *fid);
|
||||||
|
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||||
|
struct cifs_fattr *fattr,
|
||||||
|
u32 tag);
|
||||||
extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path,
|
extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path,
|
||||||
struct super_block *sb, unsigned int xid);
|
struct super_block *sb, unsigned int xid);
|
||||||
extern int cifs_get_inode_info_unix(struct inode **pinode,
|
extern int cifs_get_inode_info_unix(struct inode **pinode,
|
||||||
|
|
|
@ -687,6 +687,43 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
|
||||||
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
|
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||||
|
struct cifs_fattr *fattr,
|
||||||
|
u32 tag)
|
||||||
|
{
|
||||||
|
switch (tag) {
|
||||||
|
case IO_REPARSE_TAG_LX_SYMLINK:
|
||||||
|
fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
|
||||||
|
fattr->cf_dtype = DT_LNK;
|
||||||
|
break;
|
||||||
|
case IO_REPARSE_TAG_LX_FIFO:
|
||||||
|
fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
|
||||||
|
fattr->cf_dtype = DT_FIFO;
|
||||||
|
break;
|
||||||
|
case IO_REPARSE_TAG_AF_UNIX:
|
||||||
|
fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
|
||||||
|
fattr->cf_dtype = DT_SOCK;
|
||||||
|
break;
|
||||||
|
case IO_REPARSE_TAG_LX_CHR:
|
||||||
|
fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
|
||||||
|
fattr->cf_dtype = DT_CHR;
|
||||||
|
break;
|
||||||
|
case IO_REPARSE_TAG_LX_BLK:
|
||||||
|
fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
|
||||||
|
fattr->cf_dtype = DT_BLK;
|
||||||
|
break;
|
||||||
|
case 0: /* SMB1 symlink */
|
||||||
|
case IO_REPARSE_TAG_SYMLINK:
|
||||||
|
case IO_REPARSE_TAG_NFS:
|
||||||
|
fattr->cf_mode = S_IFLNK;
|
||||||
|
fattr->cf_dtype = DT_LNK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
|
static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
|
||||||
struct cifs_open_info_data *data,
|
struct cifs_open_info_data *data,
|
||||||
struct super_block *sb)
|
struct super_block *sb)
|
||||||
|
@ -694,7 +731,6 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
|
||||||
struct smb2_file_all_info *info = &data->fi;
|
struct smb2_file_all_info *info = &data->fi;
|
||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||||
u32 reparse_tag = data->reparse_tag;
|
|
||||||
|
|
||||||
memset(fattr, 0, sizeof(*fattr));
|
memset(fattr, 0, sizeof(*fattr));
|
||||||
fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
|
fattr->cf_cifsattrs = le32_to_cpu(info->Attributes);
|
||||||
|
@ -717,28 +753,13 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
|
||||||
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
|
fattr->cf_eof = le64_to_cpu(info->EndOfFile);
|
||||||
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
|
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
|
||||||
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
|
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
|
||||||
|
|
||||||
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
|
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
|
||||||
if (reparse_tag == IO_REPARSE_TAG_LX_SYMLINK) {
|
|
||||||
fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
|
if (cifs_open_data_reparse(data) &&
|
||||||
fattr->cf_dtype = DT_LNK;
|
cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag))
|
||||||
} else if (reparse_tag == IO_REPARSE_TAG_LX_FIFO) {
|
goto out_reparse;
|
||||||
fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
|
|
||||||
fattr->cf_dtype = DT_FIFO;
|
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||||
} else if (reparse_tag == IO_REPARSE_TAG_AF_UNIX) {
|
|
||||||
fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
|
|
||||||
fattr->cf_dtype = DT_SOCK;
|
|
||||||
} else if (reparse_tag == IO_REPARSE_TAG_LX_CHR) {
|
|
||||||
fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
|
|
||||||
fattr->cf_dtype = DT_CHR;
|
|
||||||
} else if (reparse_tag == IO_REPARSE_TAG_LX_BLK) {
|
|
||||||
fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
|
|
||||||
fattr->cf_dtype = DT_BLK;
|
|
||||||
} else if (data->symlink || reparse_tag == IO_REPARSE_TAG_SYMLINK ||
|
|
||||||
reparse_tag == IO_REPARSE_TAG_NFS) {
|
|
||||||
fattr->cf_mode = S_IFLNK;
|
|
||||||
fattr->cf_dtype = DT_LNK;
|
|
||||||
} else if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
|
||||||
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
|
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
|
||||||
fattr->cf_dtype = DT_DIR;
|
fattr->cf_dtype = DT_DIR;
|
||||||
/*
|
/*
|
||||||
|
@ -767,6 +788,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_reparse:
|
||||||
if (S_ISLNK(fattr->cf_mode)) {
|
if (S_ISLNK(fattr->cf_mode)) {
|
||||||
fattr->cf_symlink_target = data->symlink_target;
|
fattr->cf_symlink_target = data->symlink_target;
|
||||||
data->symlink_target = NULL;
|
data->symlink_target = NULL;
|
||||||
|
@ -957,6 +979,40 @@ static inline bool is_inode_cache_good(struct inode *ino)
|
||||||
return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0;
|
return ino && CIFS_CACHE_READ(CIFS_I(ino)) && CIFS_I(ino)->time != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int query_reparse(struct cifs_open_info_data *data,
|
||||||
|
struct super_block *sb,
|
||||||
|
const unsigned int xid,
|
||||||
|
struct cifs_tcon *tcon,
|
||||||
|
const char *full_path,
|
||||||
|
struct cifs_fattr *fattr)
|
||||||
|
{
|
||||||
|
struct TCP_Server_Info *server = tcon->ses->server;
|
||||||
|
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||||
|
bool reparse_point = data->reparse_point;
|
||||||
|
u32 tag = data->reparse_tag;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!tag && server->ops->query_reparse_tag) {
|
||||||
|
server->ops->query_reparse_tag(xid, tcon, cifs_sb,
|
||||||
|
full_path, &tag);
|
||||||
|
}
|
||||||
|
switch ((data->reparse_tag = tag)) {
|
||||||
|
case 0: /* SMB1 symlink */
|
||||||
|
reparse_point = false;
|
||||||
|
fallthrough;
|
||||||
|
case IO_REPARSE_TAG_NFS:
|
||||||
|
case IO_REPARSE_TAG_SYMLINK:
|
||||||
|
if (!data->symlink_target && server->ops->query_symlink) {
|
||||||
|
rc = server->ops->query_symlink(xid, tcon,
|
||||||
|
cifs_sb, full_path,
|
||||||
|
&data->symlink_target,
|
||||||
|
reparse_point);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||||
struct cifs_open_info_data *data, struct super_block *sb, int xid,
|
struct cifs_open_info_data *data, struct super_block *sb, int xid,
|
||||||
const struct cifs_fid *fid)
|
const struct cifs_fid *fid)
|
||||||
|
@ -1002,23 +1058,12 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||||
* since we have to check if its reparse tag matches a known
|
* since we have to check if its reparse tag matches a known
|
||||||
* special file type e.g. symlink or fifo or char etc.
|
* special file type e.g. symlink or fifo or char etc.
|
||||||
*/
|
*/
|
||||||
if (data->reparse_point && data->symlink_target) {
|
if (cifs_open_data_reparse(data)) {
|
||||||
data->reparse_tag = IO_REPARSE_TAG_SYMLINK;
|
rc = query_reparse(data, sb, xid, tcon,
|
||||||
} else if ((le32_to_cpu(data->fi.Attributes) & ATTR_REPARSE) &&
|
full_path, &fattr);
|
||||||
server->ops->query_reparse_tag) {
|
|
||||||
tmprc = server->ops->query_reparse_tag(xid, tcon, cifs_sb, full_path,
|
|
||||||
&data->reparse_tag);
|
|
||||||
cifs_dbg(FYI, "%s: query_reparse_tag: rc = %d\n", __func__, tmprc);
|
|
||||||
if (server->ops->query_symlink) {
|
|
||||||
tmprc = server->ops->query_symlink(xid, tcon, cifs_sb,
|
|
||||||
full_path,
|
|
||||||
&data->symlink_target,
|
|
||||||
data->reparse_point);
|
|
||||||
cifs_dbg(FYI, "%s: query_symlink: rc = %d\n",
|
|
||||||
__func__, tmprc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
cifs_open_info_to_fattr(&fattr, data, sb);
|
if (!rc)
|
||||||
|
cifs_open_info_to_fattr(&fattr, data, sb);
|
||||||
break;
|
break;
|
||||||
case -EREMOTE:
|
case -EREMOTE:
|
||||||
/* DFS link, no metadata available on this server */
|
/* DFS link, no metadata available on this server */
|
||||||
|
|
|
@ -163,29 +163,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
|
||||||
* TODO: go through all documented reparse tags to see if we can
|
* TODO: go through all documented reparse tags to see if we can
|
||||||
* reasonably map some of them to directories vs. files vs. symlinks
|
* reasonably map some of them to directories vs. files vs. symlinks
|
||||||
*/
|
*/
|
||||||
|
if ((fattr->cf_cifsattrs & ATTR_REPARSE) &&
|
||||||
|
cifs_reparse_point_to_fattr(cifs_sb, fattr, fattr->cf_cifstag))
|
||||||
|
goto out_reparse;
|
||||||
|
|
||||||
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||||
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
|
fattr->cf_mode = S_IFDIR | cifs_sb->ctx->dir_mode;
|
||||||
fattr->cf_dtype = DT_DIR;
|
fattr->cf_dtype = DT_DIR;
|
||||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_SYMLINK) {
|
} else {
|
||||||
fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
|
|
||||||
fattr->cf_dtype = DT_LNK;
|
|
||||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_FIFO) {
|
|
||||||
fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
|
|
||||||
fattr->cf_dtype = DT_FIFO;
|
|
||||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_AF_UNIX) {
|
|
||||||
fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
|
|
||||||
fattr->cf_dtype = DT_SOCK;
|
|
||||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_CHR) {
|
|
||||||
fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
|
|
||||||
fattr->cf_dtype = DT_CHR;
|
|
||||||
} else if (fattr->cf_cifstag == IO_REPARSE_TAG_LX_BLK) {
|
|
||||||
fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
|
|
||||||
fattr->cf_dtype = DT_BLK;
|
|
||||||
} else { /* TODO: should we mark some other reparse points (like DFSR) as directories? */
|
|
||||||
fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
|
fattr->cf_mode = S_IFREG | cifs_sb->ctx->file_mode;
|
||||||
fattr->cf_dtype = DT_REG;
|
fattr->cf_dtype = DT_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_reparse:
|
||||||
/*
|
/*
|
||||||
* We need to revalidate it further to make a decision about whether it
|
* We need to revalidate it further to make a decision about whether it
|
||||||
* is a symbolic link, DFS referral or a reparse point with a direct
|
* is a symbolic link, DFS referral or a reparse point with a direct
|
||||||
|
|
|
@ -542,6 +542,33 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_create_response(struct cifs_open_info_data *data,
|
||||||
|
struct cifs_sb_info *cifs_sb,
|
||||||
|
const struct kvec *iov)
|
||||||
|
{
|
||||||
|
struct smb2_create_rsp *rsp = iov->iov_base;
|
||||||
|
bool reparse_point = false;
|
||||||
|
u32 tag = 0;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
switch (rsp->hdr.Status) {
|
||||||
|
case STATUS_STOPPED_ON_SYMLINK:
|
||||||
|
rc = smb2_parse_symlink_response(cifs_sb, iov,
|
||||||
|
&data->symlink_target);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
tag = IO_REPARSE_TAG_SYMLINK;
|
||||||
|
reparse_point = true;
|
||||||
|
break;
|
||||||
|
case STATUS_SUCCESS:
|
||||||
|
reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
data->reparse_point = reparse_point;
|
||||||
|
data->reparse_tag = tag;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int smb2_query_path_info(const unsigned int xid,
|
int smb2_query_path_info(const unsigned int xid,
|
||||||
struct cifs_tcon *tcon,
|
struct cifs_tcon *tcon,
|
||||||
struct cifs_sb_info *cifs_sb,
|
struct cifs_sb_info *cifs_sb,
|
||||||
|
@ -551,6 +578,7 @@ int smb2_query_path_info(const unsigned int xid,
|
||||||
__u32 create_options = 0;
|
__u32 create_options = 0;
|
||||||
struct cifsFileInfo *cfile;
|
struct cifsFileInfo *cfile;
|
||||||
struct cached_fid *cfid = NULL;
|
struct cached_fid *cfid = NULL;
|
||||||
|
struct smb2_hdr *hdr;
|
||||||
struct kvec out_iov[3] = {};
|
struct kvec out_iov[3] = {};
|
||||||
int out_buftype[3] = {};
|
int out_buftype[3] = {};
|
||||||
bool islink;
|
bool islink;
|
||||||
|
@ -579,39 +607,43 @@ int smb2_query_path_info(const unsigned int xid,
|
||||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||||
create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
|
create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
|
||||||
NULL, NULL, out_iov, out_buftype);
|
NULL, NULL, out_iov, out_buftype);
|
||||||
if (rc) {
|
hdr = out_iov[0].iov_base;
|
||||||
struct smb2_hdr *hdr = out_iov[0].iov_base;
|
/*
|
||||||
|
* If first iov is unset, then SMB session was dropped or we've got a
|
||||||
|
* cached open file (@cfile).
|
||||||
|
*/
|
||||||
|
if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (unlikely(!hdr || out_buftype[0] == CIFS_NO_BUFFER))
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
case -EOPNOTSUPP:
|
||||||
|
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
|
||||||
|
if (rc || !data->reparse_point)
|
||||||
goto out;
|
goto out;
|
||||||
if (rc == -EOPNOTSUPP && hdr->Command == SMB2_CREATE &&
|
|
||||||
hdr->Status == STATUS_STOPPED_ON_SYMLINK) {
|
|
||||||
rc = smb2_parse_symlink_response(cifs_sb, out_iov,
|
|
||||||
&data->symlink_target);
|
|
||||||
if (rc)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
data->reparse_point = true;
|
create_options |= OPEN_REPARSE_POINT;
|
||||||
create_options |= OPEN_REPARSE_POINT;
|
/* Failed on a symbolic link - query a reparse point info */
|
||||||
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||||
/* Failed on a symbolic link - query a reparse point info */
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
create_options, ACL_NO_MODE, data,
|
||||||
FILE_READ_ATTRIBUTES, FILE_OPEN,
|
SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
|
||||||
create_options, ACL_NO_MODE, data,
|
NULL, NULL);
|
||||||
SMB2_OP_QUERY_INFO, cfile, NULL, NULL,
|
break;
|
||||||
NULL, NULL);
|
case -EREMOTE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
|
||||||
|
break;
|
||||||
|
rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
|
||||||
|
full_path, &islink);
|
||||||
|
if (rc2) {
|
||||||
|
rc = rc2;
|
||||||
goto out;
|
goto out;
|
||||||
} else if (rc != -EREMOTE && hdr->Status == STATUS_OBJECT_NAME_INVALID) {
|
|
||||||
rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
|
|
||||||
full_path, &islink);
|
|
||||||
if (rc2) {
|
|
||||||
rc = rc2;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (islink)
|
|
||||||
rc = -EREMOTE;
|
|
||||||
}
|
}
|
||||||
|
if (islink)
|
||||||
|
rc = -EREMOTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -653,26 +685,32 @@ int smb311_posix_query_path_info(const unsigned int xid,
|
||||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
|
||||||
create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
|
create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
|
||||||
&sidsbuf, &sidsbuflen, out_iov, out_buftype);
|
&sidsbuf, &sidsbuflen, out_iov, out_buftype);
|
||||||
if (rc == -EOPNOTSUPP) {
|
/*
|
||||||
/* BB TODO: When support for special files added to Samba re-verify this path */
|
* If first iov is unset, then SMB session was dropped or we've got a
|
||||||
if (out_iov[0].iov_base && out_buftype[0] != CIFS_NO_BUFFER &&
|
* cached open file (@cfile).
|
||||||
((struct smb2_hdr *)out_iov[0].iov_base)->Command == SMB2_CREATE &&
|
*/
|
||||||
((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_STOPPED_ON_SYMLINK) {
|
if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER)
|
||||||
rc = smb2_parse_symlink_response(cifs_sb, out_iov, &data->symlink_target);
|
goto out;
|
||||||
if (rc)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
data->reparse_point = true;
|
|
||||||
create_options |= OPEN_REPARSE_POINT;
|
|
||||||
|
|
||||||
|
switch (rc) {
|
||||||
|
case 0:
|
||||||
|
case -EOPNOTSUPP:
|
||||||
|
/* BB TODO: When support for special files added to Samba re-verify this path */
|
||||||
|
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
|
||||||
|
if (rc || !data->reparse_point)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
create_options |= OPEN_REPARSE_POINT;
|
||||||
/* Failed on a symbolic link - query a reparse point info */
|
/* Failed on a symbolic link - query a reparse point info */
|
||||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
|
||||||
FILE_OPEN, create_options, ACL_NO_MODE, data,
|
FILE_OPEN, create_options, ACL_NO_MODE, data,
|
||||||
SMB2_OP_POSIX_QUERY_INFO, cfile,
|
SMB2_OP_POSIX_QUERY_INFO, cfile,
|
||||||
&sidsbuf, &sidsbuflen, NULL, NULL);
|
&sidsbuf, &sidsbuflen, NULL, NULL);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
sidsbuf_end = sidsbuf + sidsbuflen;
|
sidsbuf_end = sidsbuf + sidsbuflen;
|
||||||
|
|
||||||
|
@ -692,7 +730,6 @@ int smb311_posix_query_path_info(const unsigned int xid,
|
||||||
memcpy(group, sidsbuf + owner_len, group_len);
|
memcpy(group, sidsbuf + owner_len, group_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
kfree(sidsbuf);
|
kfree(sidsbuf);
|
||||||
free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
|
free_rsp_buf(out_buftype[0], out_iov[0].iov_base);
|
||||||
free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
|
free_rsp_buf(out_buftype[1], out_iov[1].iov_base);
|
||||||
|
|
Loading…
Add table
Reference in a new issue