cifs: add support for ioctl on directories
We do not call cifs_open_file() for directories and thus we do not have a pSMBFile we can extract the FIDs from. Solve this by instead always using a compounded open/query/close for the passthrough ioctl. Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
3b7960cace
commit
8d8b26e584
|
@ -33,6 +33,7 @@
|
|||
|
||||
#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
|
||||
|
||||
#define SMB_PATH_MAX 260
|
||||
#define CIFS_PORT 445
|
||||
#define RFC1001_PORT 139
|
||||
|
||||
|
@ -467,7 +468,8 @@ struct smb_version_operations {
|
|||
int (*next_header)(char *);
|
||||
/* ioctl passthrough for query_info */
|
||||
int (*ioctl_query_info)(const unsigned int xid,
|
||||
struct cifsFileInfo *file,
|
||||
struct cifs_tcon *tcon,
|
||||
__le16 *path, int is_dir,
|
||||
unsigned long p);
|
||||
};
|
||||
|
||||
|
|
|
@ -32,24 +32,49 @@
|
|||
#include "cifs_debug.h"
|
||||
#include "cifsfs.h"
|
||||
#include "cifs_ioctl.h"
|
||||
#include "smb2proto.h"
|
||||
#include <linux/btrfs.h>
|
||||
|
||||
static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
|
||||
unsigned long p)
|
||||
{
|
||||
struct cifsFileInfo *pSMBFile = filep->private_data;
|
||||
struct cifs_tcon *tcon;
|
||||
struct inode *inode = file_inode(filep);
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
struct dentry *dentry = filep->f_path.dentry;
|
||||
unsigned char *path;
|
||||
__le16 *utf16_path = NULL, root_path;
|
||||
int rc = 0;
|
||||
|
||||
cifs_dbg(FYI, "%s %p\n", __func__, pSMBFile);
|
||||
if (pSMBFile == NULL)
|
||||
return -EISDIR;
|
||||
tcon = tlink_tcon(pSMBFile->tlink);
|
||||
path = build_path_from_dentry(dentry);
|
||||
if (path == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
cifs_dbg(FYI, "%s %s\n", __func__, path);
|
||||
|
||||
if (!path[0]) {
|
||||
root_path = 0;
|
||||
utf16_path = &root_path;
|
||||
} else {
|
||||
utf16_path = cifs_convert_path_to_utf16(path + 1, cifs_sb);
|
||||
if (!utf16_path) {
|
||||
rc = -ENOMEM;
|
||||
goto ici_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (tcon->ses->server->ops->ioctl_query_info)
|
||||
return tcon->ses->server->ops->ioctl_query_info(
|
||||
xid, pSMBFile, p);
|
||||
rc = tcon->ses->server->ops->ioctl_query_info(
|
||||
xid, tcon, utf16_path,
|
||||
filep->private_data ? 0 : 1, p);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
rc = -EOPNOTSUPP;
|
||||
|
||||
ici_exit:
|
||||
if (utf16_path != &root_path)
|
||||
kfree(utf16_path);
|
||||
kfree(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file,
|
||||
|
|
|
@ -1120,22 +1120,31 @@ SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
static int
|
||||
smb2_ioctl_query_info(const unsigned int xid,
|
||||
struct cifsFileInfo *file,
|
||||
struct cifs_tcon *tcon,
|
||||
__le16 *path, int is_dir,
|
||||
unsigned long p)
|
||||
{
|
||||
struct cifs_tcon *tcon = tlink_tcon(file->tlink);
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
char __user *arg = (char __user *)p;
|
||||
struct smb_query_info qi;
|
||||
struct smb_query_info __user *pqi;
|
||||
int rc = 0;
|
||||
int flags = 0;
|
||||
struct smb_rqst rqst;
|
||||
struct kvec iov[1];
|
||||
struct kvec rsp_iov;
|
||||
int resp_buftype = CIFS_NO_BUFFER;
|
||||
struct smb2_query_info_rsp *rsp = NULL;
|
||||
void *buffer;
|
||||
void *buffer = NULL;
|
||||
struct smb_rqst rqst[3];
|
||||
int resp_buftype[3];
|
||||
struct kvec rsp_iov[3];
|
||||
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
||||
struct cifs_open_parms oparms;
|
||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
struct cifs_fid fid;
|
||||
struct kvec qi_iov[1];
|
||||
struct kvec close_iov[1];
|
||||
|
||||
memset(rqst, 0, sizeof(rqst));
|
||||
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
||||
memset(rsp_iov, 0, sizeof(rsp_iov));
|
||||
|
||||
if (copy_from_user(&qi, arg, sizeof(struct smb_query_info)))
|
||||
return -EFAULT;
|
||||
|
@ -1155,31 +1164,62 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||
|
||||
if (copy_from_user(buffer, arg + sizeof(struct smb_query_info),
|
||||
qi.output_buffer_length)) {
|
||||
kfree(buffer);
|
||||
return -EFAULT;
|
||||
rc = -EFAULT;
|
||||
goto iqinf_exit;
|
||||
}
|
||||
|
||||
memset(&rqst, 0, sizeof(struct smb_rqst));
|
||||
memset(&iov, 0, sizeof(iov));
|
||||
rqst.rq_iov = iov;
|
||||
rqst.rq_nvec = 1;
|
||||
/* Open */
|
||||
memset(&open_iov, 0, sizeof(open_iov));
|
||||
rqst[0].rq_iov = open_iov;
|
||||
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
||||
|
||||
rc = SMB2_query_info_init(tcon, &rqst, file->fid.persistent_fid,
|
||||
file->fid.volatile_fid,
|
||||
memset(&oparms, 0, sizeof(oparms));
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = FILE_READ_ATTRIBUTES | READ_CONTROL;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
if (is_dir)
|
||||
oparms.create_options = CREATE_NOT_FILE;
|
||||
else
|
||||
oparms.create_options = CREATE_NOT_DIR;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
smb2_set_next_command(ses->server, &rqst[0]);
|
||||
|
||||
/* Query */
|
||||
memset(&qi_iov, 0, sizeof(qi_iov));
|
||||
rqst[1].rq_iov = qi_iov;
|
||||
rqst[1].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID,
|
||||
qi.file_info_class, qi.info_type,
|
||||
qi.additional_information,
|
||||
qi.input_buffer_length,
|
||||
qi.output_buffer_length, buffer);
|
||||
kfree(buffer);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
smb2_set_next_command(ses->server, &rqst[1]);
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
||||
/* Close */
|
||||
memset(&close_iov, 0, sizeof(close_iov));
|
||||
rqst[2].rq_iov = close_iov;
|
||||
rqst[2].rq_nvec = 1;
|
||||
|
||||
rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
smb2_set_related(&rqst[2]);
|
||||
|
||||
rc = compound_send_recv(xid, ses, flags, 3, rqst,
|
||||
resp_buftype, rsp_iov);
|
||||
if (rc)
|
||||
goto iqinf_exit;
|
||||
pqi = (struct smb_query_info __user *)arg;
|
||||
rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
|
||||
if (le32_to_cpu(rsp->OutputBufferLength) < qi.input_buffer_length)
|
||||
qi.input_buffer_length = le32_to_cpu(rsp->OutputBufferLength);
|
||||
if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length,
|
||||
|
@ -1193,8 +1233,13 @@ smb2_ioctl_query_info(const unsigned int xid,
|
|||
}
|
||||
|
||||
iqinf_exit:
|
||||
SMB2_query_info_free(&rqst);
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
kfree(buffer);
|
||||
SMB2_open_free(&rqst[0]);
|
||||
SMB2_query_info_free(&rqst[1]);
|
||||
SMB2_close_free(&rqst[2]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user