Commit 3ded18a9 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French
Browse files

smb: client: cleanup smb2_query_reparse_point()



Use smb2_compound_op() with SMB2_OP_GET_REPARSE to get reparse point.

Signed-off-by: default avatarPaulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 514d793e
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -1053,3 +1053,36 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
	}
	return rc ? ERR_PTR(rc) : new;
}

int smb2_query_reparse_point(const unsigned int xid,
			     struct cifs_tcon *tcon,
			     struct cifs_sb_info *cifs_sb,
			     const char *full_path,
			     u32 *tag, struct kvec *rsp,
			     int *rsp_buftype)
{
	struct cifs_open_info_data data = {};
	struct cifsFileInfo *cfile;
	struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
	int rc;

	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);

	cifs_get_readable_path(tcon, full_path, &cfile);
	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
			      FILE_READ_ATTRIBUTES, FILE_OPEN,
			      OPEN_REPARSE_POINT, ACL_NO_MODE, &in_iov,
			      &(int){SMB2_OP_GET_REPARSE}, 1, cfile,
			      NULL, NULL, NULL, NULL);
	if (rc)
		goto out;

	*tag = data.reparse.tag;
	*rsp = data.reparse.io.iov;
	*rsp_buftype = data.reparse.io.buftype;
	memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
	data.reparse.io.buftype = CIFS_NO_BUFFER;
out:
	cifs_free_open_info(&data);
	return rc;
}
+0 −139
Original line number Diff line number Diff line
@@ -2997,145 +2997,6 @@ static int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
	return parse_reparse_point(buf, plen, cifs_sb, true, data);
}

static int smb2_query_reparse_point(const unsigned int xid,
				    struct cifs_tcon *tcon,
				    struct cifs_sb_info *cifs_sb,
				    const char *full_path,
				    u32 *tag, struct kvec *rsp,
				    int *rsp_buftype)
{
	struct smb2_compound_vars *vars;
	int rc;
	__le16 *utf16_path = NULL;
	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
	struct cifs_open_parms oparms;
	struct cifs_fid fid;
	struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
	int flags = CIFS_CP_CREATE_CLOSE_OP;
	struct smb_rqst *rqst;
	int resp_buftype[3];
	struct kvec *rsp_iov;
	struct smb2_ioctl_rsp *ioctl_rsp;
	struct reparse_data_buffer *reparse_buf;
	u32 off, count, len;

	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);

	if (smb3_encryption_required(tcon))
		flags |= CIFS_TRANSFORM_REQ;

	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
	if (!utf16_path)
		return -ENOMEM;

	resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
	vars = kzalloc(sizeof(*vars), GFP_KERNEL);
	if (!vars) {
		rc = -ENOMEM;
		goto out_free_path;
	}
	rqst = vars->rqst;
	rsp_iov = vars->rsp_iov;

	/*
	 * setup smb2open - TODO add optimization to call cifs_get_readable_path
	 * to see if there is a handle already open that we can use
	 */
	rqst[0].rq_iov = vars->open_iov;
	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;

	oparms = (struct cifs_open_parms) {
		.tcon = tcon,
		.path = full_path,
		.desired_access = FILE_READ_ATTRIBUTES,
		.disposition = FILE_OPEN,
		.create_options = cifs_create_options(cifs_sb, OPEN_REPARSE_POINT),
		.fid = &fid,
	};

	rc = SMB2_open_init(tcon, server,
			    &rqst[0], &oplock, &oparms, utf16_path);
	if (rc)
		goto query_rp_exit;
	smb2_set_next_command(tcon, &rqst[0]);


	/* IOCTL */
	rqst[1].rq_iov = vars->io_iov;
	rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;

	rc = SMB2_ioctl_init(tcon, server,
			     &rqst[1], COMPOUND_FID,
			     COMPOUND_FID, FSCTL_GET_REPARSE_POINT, NULL, 0,
			     CIFSMaxBufSize -
			     MAX_SMB2_CREATE_RESPONSE_SIZE -
			     MAX_SMB2_CLOSE_RESPONSE_SIZE);
	if (rc)
		goto query_rp_exit;

	smb2_set_next_command(tcon, &rqst[1]);
	smb2_set_related(&rqst[1]);

	/* Close */
	rqst[2].rq_iov = &vars->close_iov;
	rqst[2].rq_nvec = 1;

	rc = SMB2_close_init(tcon, server,
			     &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
	if (rc)
		goto query_rp_exit;

	smb2_set_related(&rqst[2]);

	rc = compound_send_recv(xid, tcon->ses, server,
				flags, 3, rqst,
				resp_buftype, rsp_iov);

	ioctl_rsp = rsp_iov[1].iov_base;

	/*
	 * Open was successful and we got an ioctl response.
	 */
	if (rc == 0) {
		/* See MS-FSCC 2.3.23 */
		off = le32_to_cpu(ioctl_rsp->OutputOffset);
		count = le32_to_cpu(ioctl_rsp->OutputCount);
		if (check_add_overflow(off, count, &len) ||
		    len > rsp_iov[1].iov_len) {
			cifs_tcon_dbg(VFS, "%s: invalid ioctl: off=%d count=%d\n",
				      __func__, off, count);
			rc = -EIO;
			goto query_rp_exit;
		}

		reparse_buf = (void *)((u8 *)ioctl_rsp + off);
		len = sizeof(*reparse_buf);
		if (count < len ||
		    count < le16_to_cpu(reparse_buf->ReparseDataLength) + len) {
			cifs_tcon_dbg(VFS, "%s: invalid ioctl: off=%d count=%d\n",
				      __func__, off, count);
			rc = -EIO;
			goto query_rp_exit;
		}
		*tag = le32_to_cpu(reparse_buf->ReparseTag);
		*rsp = rsp_iov[1];
		*rsp_buftype = resp_buftype[1];
		resp_buftype[1] = CIFS_NO_BUFFER;
	}

 query_rp_exit:
	SMB2_open_free(&rqst[0]);
	SMB2_ioctl_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);
	kfree(vars);
out_free_path:
	kfree(utf16_path);
	return rc;
}

static struct cifs_ntsd *
get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
		    const struct cifs_fid *cifsfid, u32 *pacllen, u32 info)
+6 −0
Original line number Diff line number Diff line
@@ -62,6 +62,12 @@ struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
				     struct cifs_tcon *tcon,
				     const char *full_path,
				     struct kvec *iov);
int smb2_query_reparse_point(const unsigned int xid,
			     struct cifs_tcon *tcon,
			     struct cifs_sb_info *cifs_sb,
			     const char *full_path,
			     u32 *tag, struct kvec *rsp,
			     int *rsp_buftype);
int smb2_query_path_info(const unsigned int xid,
			 struct cifs_tcon *tcon,
			 struct cifs_sb_info *cifs_sb,