mirror of https://github.com/torvalds/linux.git
smb: client: handle lack of EA support in smb2_query_path_info()
If the server doesn't support both EAs and reparse point in a file, the SMB2_QUERY_INFO request will fail with either STATUS_NO_EAS_ON_FILE or STATUS_EAS_NOT_SUPPORT in the compound chain, so ignore it as long as reparse point isn't IO_REPARSE_TAG_LX_(CHR|BLK), which would require the EAs to know about major/minor numbers. Reported-by: Pali Rohár <pali@kernel.org> Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
056e91cbc9
commit
3681c74d34
|
|
@ -176,27 +176,27 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
|
struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct reparse_data_buffer *rbuf;
|
|
||||||
struct smb2_compound_vars *vars = NULL;
|
|
||||||
struct kvec *rsp_iov, *iov;
|
|
||||||
struct smb_rqst *rqst;
|
|
||||||
int rc;
|
|
||||||
__le16 *utf16_path = NULL;
|
|
||||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
||||||
struct cifs_fid fid;
|
|
||||||
struct cifs_ses *ses = tcon->ses;
|
|
||||||
struct TCP_Server_Info *server;
|
|
||||||
int num_rqst = 0, i;
|
|
||||||
int resp_buftype[MAX_COMPOUND];
|
|
||||||
struct smb2_query_info_rsp *qi_rsp = NULL;
|
struct smb2_query_info_rsp *qi_rsp = NULL;
|
||||||
|
struct smb2_compound_vars *vars = NULL;
|
||||||
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||||
struct cifs_open_info_data *idata;
|
struct cifs_open_info_data *idata;
|
||||||
struct inode *inode = NULL;
|
struct cifs_ses *ses = tcon->ses;
|
||||||
int flags = 0;
|
struct reparse_data_buffer *rbuf;
|
||||||
__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
|
struct TCP_Server_Info *server;
|
||||||
unsigned int size[2];
|
int resp_buftype[MAX_COMPOUND];
|
||||||
void *data[2];
|
|
||||||
unsigned int len;
|
|
||||||
int retries = 0, cur_sleep = 1;
|
int retries = 0, cur_sleep = 1;
|
||||||
|
__u8 delete_pending[8] = {1,};
|
||||||
|
struct kvec *rsp_iov, *iov;
|
||||||
|
struct inode *inode = NULL;
|
||||||
|
__le16 *utf16_path = NULL;
|
||||||
|
struct smb_rqst *rqst;
|
||||||
|
unsigned int size[2];
|
||||||
|
struct cifs_fid fid;
|
||||||
|
int num_rqst = 0, i;
|
||||||
|
unsigned int len;
|
||||||
|
int tmp_rc, rc;
|
||||||
|
int flags = 0;
|
||||||
|
void *data[2];
|
||||||
|
|
||||||
replay_again:
|
replay_again:
|
||||||
/* reinitialize for possible replay */
|
/* reinitialize for possible replay */
|
||||||
|
|
@ -639,7 +639,14 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
tcon->need_reconnect = true;
|
tcon->need_reconnect = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmp_rc = rc;
|
||||||
for (i = 0; i < num_cmds; i++) {
|
for (i = 0; i < num_cmds; i++) {
|
||||||
|
char *buf = rsp_iov[i + i].iov_base;
|
||||||
|
|
||||||
|
if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER)
|
||||||
|
rc = server->ops->map_error(buf, false);
|
||||||
|
else
|
||||||
|
rc = tmp_rc;
|
||||||
switch (cmds[i]) {
|
switch (cmds[i]) {
|
||||||
case SMB2_OP_QUERY_INFO:
|
case SMB2_OP_QUERY_INFO:
|
||||||
idata = in_iov[i].iov_base;
|
idata = in_iov[i].iov_base;
|
||||||
|
|
@ -805,6 +812,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SMB2_close_free(&rqst[num_rqst]);
|
SMB2_close_free(&rqst[num_rqst]);
|
||||||
|
rc = tmp_rc;
|
||||||
|
|
||||||
num_cmds += 2;
|
num_cmds += 2;
|
||||||
if (out_iov && out_buftype) {
|
if (out_iov && out_buftype) {
|
||||||
|
|
@ -860,22 +868,52 @@ static int parse_create_response(struct cifs_open_info_data *data,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check only if SMB2_OP_QUERY_WSL_EA command failed in the compound chain */
|
||||||
|
static bool ea_unsupported(int *cmds, int num_cmds,
|
||||||
|
struct kvec *out_iov, int *out_buftype)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (cmds[num_cmds - 1] != SMB2_OP_QUERY_WSL_EA)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (i = 1; i < num_cmds - 1; i++) {
|
||||||
|
struct smb2_hdr *hdr = out_iov[i].iov_base;
|
||||||
|
|
||||||
|
if (out_buftype[i] == CIFS_NO_BUFFER || !hdr ||
|
||||||
|
hdr->Status != STATUS_SUCCESS)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void free_rsp_iov(struct kvec *iovs, int *buftype, int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
free_rsp_buf(buftype[i], iovs[i].iov_base);
|
||||||
|
memset(&iovs[i], 0, sizeof(*iovs));
|
||||||
|
buftype[i] = CIFS_NO_BUFFER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
const char *full_path,
|
const char *full_path,
|
||||||
struct cifs_open_info_data *data)
|
struct cifs_open_info_data *data)
|
||||||
{
|
{
|
||||||
struct cifs_open_parms oparms;
|
struct kvec in_iov[3], out_iov[5] = {};
|
||||||
__u32 create_options = 0;
|
|
||||||
struct cifsFileInfo *cfile;
|
|
||||||
struct cached_fid *cfid = NULL;
|
struct cached_fid *cfid = NULL;
|
||||||
|
struct cifs_open_parms oparms;
|
||||||
|
struct cifsFileInfo *cfile;
|
||||||
|
__u32 create_options = 0;
|
||||||
|
int out_buftype[5] = {};
|
||||||
struct smb2_hdr *hdr;
|
struct smb2_hdr *hdr;
|
||||||
struct kvec in_iov[3], out_iov[3] = {};
|
int num_cmds = 0;
|
||||||
int out_buftype[3] = {};
|
|
||||||
int cmds[3];
|
int cmds[3];
|
||||||
bool islink;
|
bool islink;
|
||||||
int i, num_cmds = 0;
|
|
||||||
int rc, rc2;
|
int rc, rc2;
|
||||||
|
|
||||||
data->adjust_tz = false;
|
data->adjust_tz = false;
|
||||||
|
|
@ -945,14 +983,14 @@ int smb2_query_path_info(const unsigned int xid,
|
||||||
if (rc || !data->reparse_point)
|
if (rc || !data->reparse_point)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!tcon->posix_extensions)
|
|
||||||
cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
|
|
||||||
/*
|
/*
|
||||||
* Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
|
* Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
|
||||||
* response.
|
* response.
|
||||||
*/
|
*/
|
||||||
if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
|
if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
|
||||||
cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
|
cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
|
||||||
|
if (!tcon->posix_extensions)
|
||||||
|
cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
|
||||||
|
|
||||||
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
|
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
|
||||||
FILE_READ_ATTRIBUTES |
|
FILE_READ_ATTRIBUTES |
|
||||||
|
|
@ -960,9 +998,18 @@ int smb2_query_path_info(const unsigned int xid,
|
||||||
FILE_OPEN, create_options |
|
FILE_OPEN, create_options |
|
||||||
OPEN_REPARSE_POINT, ACL_NO_MODE);
|
OPEN_REPARSE_POINT, ACL_NO_MODE);
|
||||||
cifs_get_readable_path(tcon, full_path, &cfile);
|
cifs_get_readable_path(tcon, full_path, &cfile);
|
||||||
|
free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
|
||||||
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
|
||||||
&oparms, in_iov, cmds, num_cmds,
|
&oparms, in_iov, cmds, num_cmds,
|
||||||
cfile, NULL, NULL, NULL);
|
cfile, out_iov, out_buftype, NULL);
|
||||||
|
if (rc && ea_unsupported(cmds, num_cmds,
|
||||||
|
out_iov, out_buftype)) {
|
||||||
|
if (data->reparse.tag != IO_REPARSE_TAG_LX_BLK &&
|
||||||
|
data->reparse.tag != IO_REPARSE_TAG_LX_CHR)
|
||||||
|
rc = 0;
|
||||||
|
else
|
||||||
|
rc = -EOPNOTSUPP;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case -EREMOTE:
|
case -EREMOTE:
|
||||||
break;
|
break;
|
||||||
|
|
@ -980,8 +1027,7 @@ int smb2_query_path_info(const unsigned int xid,
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
|
free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
|
||||||
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue