mirror of
https://github.com/torvalds/linux.git
synced 2025-12-01 07:26:02 +07:00
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:
committed by
Steve French
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 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_compound_vars *vars = NULL;
|
||||
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_open_info_data *idata;
|
||||
struct inode *inode = NULL;
|
||||
int flags = 0;
|
||||
__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
|
||||
unsigned int size[2];
|
||||
void *data[2];
|
||||
unsigned int len;
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct reparse_data_buffer *rbuf;
|
||||
struct TCP_Server_Info *server;
|
||||
int resp_buftype[MAX_COMPOUND];
|
||||
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:
|
||||
/* reinitialize for possible replay */
|
||||
@@ -639,7 +639,14 @@ finished:
|
||||
tcon->need_reconnect = true;
|
||||
}
|
||||
|
||||
tmp_rc = rc;
|
||||
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]) {
|
||||
case SMB2_OP_QUERY_INFO:
|
||||
idata = in_iov[i].iov_base;
|
||||
@@ -805,6 +812,7 @@ finished:
|
||||
}
|
||||
}
|
||||
SMB2_close_free(&rqst[num_rqst]);
|
||||
rc = tmp_rc;
|
||||
|
||||
num_cmds += 2;
|
||||
if (out_iov && out_buftype) {
|
||||
@@ -860,22 +868,52 @@ static int parse_create_response(struct cifs_open_info_data *data,
|
||||
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,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
struct cifs_open_parms oparms;
|
||||
__u32 create_options = 0;
|
||||
struct cifsFileInfo *cfile;
|
||||
struct kvec in_iov[3], out_iov[5] = {};
|
||||
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 kvec in_iov[3], out_iov[3] = {};
|
||||
int out_buftype[3] = {};
|
||||
int num_cmds = 0;
|
||||
int cmds[3];
|
||||
bool islink;
|
||||
int i, num_cmds = 0;
|
||||
int rc, rc2;
|
||||
|
||||
data->adjust_tz = false;
|
||||
@@ -945,14 +983,14 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
if (rc || !data->reparse_point)
|
||||
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
|
||||
* response.
|
||||
*/
|
||||
if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
|
||||
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,
|
||||
FILE_READ_ATTRIBUTES |
|
||||
@@ -960,9 +998,18 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
FILE_OPEN, create_options |
|
||||
OPEN_REPARSE_POINT, ACL_NO_MODE);
|
||||
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,
|
||||
&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;
|
||||
case -EREMOTE:
|
||||
break;
|
||||
@@ -980,8 +1027,7 @@ int smb2_query_path_info(const unsigned int xid,
|
||||
}
|
||||
|
||||
out:
|
||||
for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
|
||||
free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
|
||||
free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user