Linux Audio

Check our new training course

Loading...
v6.13.7
   1// SPDX-License-Identifier: LGPL-2.1
   2/*
   3 *
   4 *   Copyright (C) International Business Machines  Corp., 2002, 2011
   5 *                 Etersoft, 2012
   6 *   Author(s): Pavel Shilovsky (pshilovsky@samba.org),
   7 *              Steve French (sfrench@us.ibm.com)
   8 *
   9 */
  10#include <linux/fs.h>
  11#include <linux/stat.h>
  12#include <linux/slab.h>
  13#include <linux/pagemap.h>
  14#include <asm/div64.h>
  15#include "cifsfs.h"
  16#include "cifspdu.h"
  17#include "cifsglob.h"
  18#include "cifsproto.h"
  19#include "cifs_debug.h"
  20#include "cifs_fs_sb.h"
  21#include "cifs_unicode.h"
  22#include "fscache.h"
  23#include "smb2glob.h"
  24#include "smb2pdu.h"
  25#include "smb2proto.h"
  26#include "cached_dir.h"
  27#include "../common/smb2status.h"
  28
  29static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
  30{
  31	struct reparse_data_buffer *buf;
  32	struct smb2_ioctl_rsp *io = iov->iov_base;
  33	u32 off, count, len;
  34
  35	count = le32_to_cpu(io->OutputCount);
  36	off = le32_to_cpu(io->OutputOffset);
  37	if (check_add_overflow(off, count, &len) || len > iov->iov_len)
  38		return ERR_PTR(-EIO);
  39
  40	buf = (struct reparse_data_buffer *)((u8 *)io + off);
  41	len = sizeof(*buf);
  42	if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
  43		return ERR_PTR(-EIO);
  44	return buf;
  45}
  46
  47static inline __u32 file_create_options(struct dentry *dentry)
  48{
  49	struct cifsInodeInfo *ci;
  50
  51	if (dentry) {
  52		ci = CIFS_I(d_inode(dentry));
  53		if (ci->cifsAttrs & ATTR_REPARSE)
  54			return OPEN_REPARSE_POINT;
  55	}
  56	return 0;
  57}
  58
  59/* Parse owner and group from SMB3.1.1 POSIX query info */
  60static int parse_posix_sids(struct cifs_open_info_data *data,
  61			    struct kvec *rsp_iov)
  62{
  63	struct smb2_query_info_rsp *qi = rsp_iov->iov_base;
  64	unsigned int out_len = le32_to_cpu(qi->OutputBufferLength);
  65	unsigned int qi_len = sizeof(data->posix_fi);
  66	int owner_len, group_len;
  67	u8 *sidsbuf, *sidsbuf_end;
  68
  69	if (out_len <= qi_len)
  70		return -EINVAL;
  71
  72	sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
  73	sidsbuf_end = sidsbuf + out_len - qi_len;
  74
  75	owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
  76	if (owner_len == -1)
  77		return -EINVAL;
  78
  79	memcpy(&data->posix_owner, sidsbuf, owner_len);
  80	group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end);
  81	if (group_len == -1)
  82		return -EINVAL;
  83
  84	memcpy(&data->posix_group, sidsbuf + owner_len, group_len);
  85	return 0;
  86}
  87
  88struct wsl_query_ea {
  89	__le32	next;
  90	__u8	name_len;
  91	__u8	name[SMB2_WSL_XATTR_NAME_LEN + 1];
  92} __packed;
  93
  94#define NEXT_OFF cpu_to_le32(sizeof(struct wsl_query_ea))
  95
  96static const struct wsl_query_ea wsl_query_eas[] = {
  97	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_UID, },
  98	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_GID, },
  99	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_MODE, },
 100	{ .next = 0,        .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_DEV, },
 101};
 102
 103static int check_wsl_eas(struct kvec *rsp_iov)
 104{
 105	struct smb2_file_full_ea_info *ea;
 106	struct smb2_query_info_rsp *rsp = rsp_iov->iov_base;
 107	unsigned long addr;
 108	u32 outlen, next;
 109	u16 vlen;
 110	u8 nlen;
 111	u8 *end;
 112
 113	outlen = le32_to_cpu(rsp->OutputBufferLength);
 114	if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
 115	    outlen > SMB2_WSL_MAX_QUERY_EA_RESP_SIZE)
 116		return -EINVAL;
 117
 118	ea = (void *)((u8 *)rsp_iov->iov_base +
 119		      le16_to_cpu(rsp->OutputBufferOffset));
 120	end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
 121	for (;;) {
 122		if ((u8 *)ea > end - sizeof(*ea))
 123			return -EINVAL;
 124
 125		nlen = ea->ea_name_length;
 126		vlen = le16_to_cpu(ea->ea_value_length);
 127		if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
 128		    (u8 *)ea + nlen + 1 + vlen > end)
 129			return -EINVAL;
 130
 131		switch (vlen) {
 132		case 4:
 133			if (strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) &&
 134			    strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) &&
 135			    strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen))
 136				return -EINVAL;
 137			break;
 138		case 8:
 139			if (strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
 140				return -EINVAL;
 141			break;
 142		case 0:
 143			if (!strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) ||
 144			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) ||
 145			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen) ||
 146			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
 147				break;
 148			fallthrough;
 149		default:
 150			return -EINVAL;
 151		}
 152
 153		next = le32_to_cpu(ea->next_entry_offset);
 154		if (!next)
 155			break;
 156		if (!IS_ALIGNED(next, 4) ||
 157		    check_add_overflow((unsigned long)ea, next, &addr))
 158			return -EINVAL;
 159		ea = (void *)addr;
 160	}
 161	return 0;
 162}
 163
 164/*
 165 * note: If cfile is passed, the reference to it is dropped here.
 166 * So make sure that you do not reuse cfile after return from this func.
 167 *
 168 * If passing @out_iov and @out_buftype, ensure to make them both large enough
 169 * (>= 3) to hold all compounded responses.  Caller is also responsible for
 170 * freeing them up with free_rsp_buf().
 171 */
 172static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 173			    struct cifs_sb_info *cifs_sb, const char *full_path,
 174			    struct cifs_open_parms *oparms, struct kvec *in_iov,
 
 175			    int *cmds, int num_cmds, struct cifsFileInfo *cfile,
 176			    struct kvec *out_iov, int *out_buftype, struct dentry *dentry)
 177{
 178
 179	struct smb2_query_info_rsp *qi_rsp = NULL;
 180	struct smb2_compound_vars *vars = NULL;
 181	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 182	struct cifs_open_info_data *idata;
 183	struct cifs_ses *ses = tcon->ses;
 184	struct reparse_data_buffer *rbuf;
 185	struct TCP_Server_Info *server;
 186	int resp_buftype[MAX_COMPOUND];
 187	int retries = 0, cur_sleep = 1;
 188	__u8 delete_pending[8] = {1,};
 189	struct kvec *rsp_iov, *iov;
 190	struct inode *inode = NULL;
 191	__le16 *utf16_path = NULL;
 192	struct smb_rqst *rqst;
 193	unsigned int size[2];
 
 
 194	struct cifs_fid fid;
 
 
 195	int num_rqst = 0, i;
 196	unsigned int len;
 197	int tmp_rc, rc;
 
 198	int flags = 0;
 
 
 199	void *data[2];
 
 
 200
 201replay_again:
 202	/* reinitialize for possible replay */
 203	flags = 0;
 204	oplock = SMB2_OPLOCK_LEVEL_NONE;
 205	num_rqst = 0;
 206	server = cifs_pick_channel(ses);
 207
 208	vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
 209	if (vars == NULL)
 210		return -ENOMEM;
 211	rqst = &vars->rqst[0];
 212	rsp_iov = &vars->rsp_iov[0];
 213
 214	if (smb3_encryption_required(tcon))
 215		flags |= CIFS_TRANSFORM_REQ;
 216
 217	for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)
 218		resp_buftype[i] = CIFS_NO_BUFFER;
 219
 220	/* We already have a handle so we can skip the open */
 221	if (cfile)
 222		goto after_open;
 223
 224	/* Open */
 225	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
 226	if (!utf16_path) {
 227		rc = -ENOMEM;
 228		goto finished;
 229	}
 230
 231	/* if there is an existing lease, reuse it */
 232
 233	/*
 234	 * note: files with hardlinks cause unexpected behaviour. As per MS-SMB2,
 235	 * lease keys are associated with the filepath. We are maintaining lease keys
 236	 * with the inode on the client. If the file has hardlinks, it is possible
 237	 * that the lease for a file be reused for an operation on its hardlink or
 238	 * vice versa.
 239	 * As a workaround, send request using an existing lease key and if the server
 240	 * returns STATUS_INVALID_PARAMETER, which maps to EINVAL, send the request
 241	 * again without the lease.
 242	 */
 243	if (dentry) {
 244		inode = d_inode(dentry);
 245		if (CIFS_I(inode)->lease_granted && server->ops->get_lease_key) {
 246			oplock = SMB2_OPLOCK_LEVEL_LEASE;
 247			server->ops->get_lease_key(inode, &fid);
 248		}
 249	}
 250
 251	vars->oparms = *oparms;
 252	vars->oparms.fid = &fid;
 253
 254	rqst[num_rqst].rq_iov = &vars->open_iov[0];
 255	rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
 256	rc = SMB2_open_init(tcon, server,
 257			    &rqst[num_rqst], &oplock, &vars->oparms,
 258			    utf16_path);
 259	kfree(utf16_path);
 260	if (rc)
 261		goto finished;
 262
 263	smb2_set_next_command(tcon, &rqst[num_rqst]);
 264 after_open:
 265	num_rqst++;
 266	rc = 0;
 267
 268	for (i = 0; i < num_cmds; i++) {
 269		/* Operation */
 270		switch (cmds[i]) {
 271		case SMB2_OP_QUERY_INFO:
 272			rqst[num_rqst].rq_iov = &vars->qi_iov;
 273			rqst[num_rqst].rq_nvec = 1;
 274
 275			if (cfile) {
 276				rc = SMB2_query_info_init(tcon, server,
 277							  &rqst[num_rqst],
 278							  cfile->fid.persistent_fid,
 279							  cfile->fid.volatile_fid,
 280							  FILE_ALL_INFORMATION,
 281							  SMB2_O_INFO_FILE, 0,
 282							  sizeof(struct smb2_file_all_info) +
 283							  PATH_MAX * 2, 0, NULL);
 284			} else {
 285				rc = SMB2_query_info_init(tcon, server,
 286							  &rqst[num_rqst],
 287							  COMPOUND_FID,
 288							  COMPOUND_FID,
 289							  FILE_ALL_INFORMATION,
 290							  SMB2_O_INFO_FILE, 0,
 291							  sizeof(struct smb2_file_all_info) +
 292							  PATH_MAX * 2, 0, NULL);
 
 
 
 
 293			}
 294			if (!rc && (!cfile || num_rqst > 1)) {
 295				smb2_set_next_command(tcon, &rqst[num_rqst]);
 296				smb2_set_related(&rqst[num_rqst]);
 297			} else if (rc) {
 298				goto finished;
 299			}
 300			num_rqst++;
 301			trace_smb3_query_info_compound_enter(xid, tcon->tid,
 302							     ses->Suid, full_path);
 303			break;
 304		case SMB2_OP_POSIX_QUERY_INFO:
 305			rqst[num_rqst].rq_iov = &vars->qi_iov;
 306			rqst[num_rqst].rq_nvec = 1;
 307
 308			if (cfile) {
 309				/* TBD: fix following to allow for longer SIDs */
 310				rc = SMB2_query_info_init(tcon, server,
 311							  &rqst[num_rqst],
 312							  cfile->fid.persistent_fid,
 313							  cfile->fid.volatile_fid,
 314							  SMB_FIND_FILE_POSIX_INFO,
 315							  SMB2_O_INFO_FILE, 0,
 316							  sizeof(struct smb311_posix_qinfo *) +
 317							  (PATH_MAX * 2) +
 318							  (sizeof(struct smb_sid) * 2), 0, NULL);
 319			} else {
 320				rc = SMB2_query_info_init(tcon, server,
 321							  &rqst[num_rqst],
 322							  COMPOUND_FID,
 323							  COMPOUND_FID,
 324							  SMB_FIND_FILE_POSIX_INFO,
 325							  SMB2_O_INFO_FILE, 0,
 326							  sizeof(struct smb311_posix_qinfo *) +
 327							  (PATH_MAX * 2) +
 328							  (sizeof(struct smb_sid) * 2), 0, NULL);
 
 
 
 
 329			}
 330			if (!rc && (!cfile || num_rqst > 1)) {
 331				smb2_set_next_command(tcon, &rqst[num_rqst]);
 332				smb2_set_related(&rqst[num_rqst]);
 333			} else if (rc) {
 334				goto finished;
 335			}
 336			num_rqst++;
 337			trace_smb3_posix_query_info_compound_enter(xid, tcon->tid,
 338								   ses->Suid, full_path);
 339			break;
 340		case SMB2_OP_DELETE:
 341			trace_smb3_delete_enter(xid, tcon->tid, ses->Suid, full_path);
 342			break;
 343		case SMB2_OP_MKDIR:
 344			/*
 345			 * Directories are created through parameters in the
 346			 * SMB2_open() call.
 347			 */
 348			trace_smb3_mkdir_enter(xid, tcon->tid, ses->Suid, full_path);
 349			break;
 350		case SMB2_OP_RMDIR:
 351			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 352			rqst[num_rqst].rq_nvec = 1;
 353
 354			size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
 355			data[0] = &delete_pending[0];
 356
 357			rc = SMB2_set_info_init(tcon, server,
 358						&rqst[num_rqst], COMPOUND_FID,
 359						COMPOUND_FID, current->tgid,
 360						FILE_DISPOSITION_INFORMATION,
 361						SMB2_O_INFO_FILE, 0, data, size);
 362			if (rc)
 363				goto finished;
 364			smb2_set_next_command(tcon, &rqst[num_rqst]);
 365			smb2_set_related(&rqst[num_rqst++]);
 366			trace_smb3_rmdir_enter(xid, tcon->tid, ses->Suid, full_path);
 367			break;
 368		case SMB2_OP_SET_EOF:
 369			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 370			rqst[num_rqst].rq_nvec = 1;
 371
 372			size[0] = in_iov[i].iov_len;
 373			data[0] = in_iov[i].iov_base;
 374
 375			if (cfile) {
 376				rc = SMB2_set_info_init(tcon, server,
 377							&rqst[num_rqst],
 378							cfile->fid.persistent_fid,
 379							cfile->fid.volatile_fid,
 380							current->tgid,
 381							FILE_END_OF_FILE_INFORMATION,
 382							SMB2_O_INFO_FILE, 0,
 383							data, size);
 384			} else {
 385				rc = SMB2_set_info_init(tcon, server,
 386							&rqst[num_rqst],
 387							COMPOUND_FID,
 388							COMPOUND_FID,
 389							current->tgid,
 390							FILE_END_OF_FILE_INFORMATION,
 391							SMB2_O_INFO_FILE, 0,
 392							data, size);
 
 
 
 
 393			}
 394			if (!rc && (!cfile || num_rqst > 1)) {
 395				smb2_set_next_command(tcon, &rqst[num_rqst]);
 396				smb2_set_related(&rqst[num_rqst]);
 397			} else if (rc) {
 398				goto finished;
 399			}
 400			num_rqst++;
 401			trace_smb3_set_eof_enter(xid, tcon->tid, ses->Suid, full_path);
 402			break;
 403		case SMB2_OP_SET_INFO:
 404			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 405			rqst[num_rqst].rq_nvec = 1;
 406
 407			size[0] = in_iov[i].iov_len;
 408			data[0] = in_iov[i].iov_base;
 409
 410			if (cfile) {
 411				rc = SMB2_set_info_init(tcon, server,
 412							&rqst[num_rqst],
 413							cfile->fid.persistent_fid,
 414							cfile->fid.volatile_fid, current->tgid,
 415							FILE_BASIC_INFORMATION,
 416							SMB2_O_INFO_FILE, 0, data, size);
 417			} else {
 418				rc = SMB2_set_info_init(tcon, server,
 419							&rqst[num_rqst],
 420							COMPOUND_FID,
 421							COMPOUND_FID, current->tgid,
 422							FILE_BASIC_INFORMATION,
 423							SMB2_O_INFO_FILE, 0, data, size);
 
 
 
 
 424			}
 425			if (!rc && (!cfile || num_rqst > 1)) {
 426				smb2_set_next_command(tcon, &rqst[num_rqst]);
 427				smb2_set_related(&rqst[num_rqst]);
 428			} else if (rc) {
 429				goto finished;
 430			}
 431			num_rqst++;
 432			trace_smb3_set_info_compound_enter(xid, tcon->tid,
 433							   ses->Suid, full_path);
 434			break;
 435		case SMB2_OP_RENAME:
 436			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 437			rqst[num_rqst].rq_nvec = 2;
 438
 439			len = in_iov[i].iov_len;
 440
 441			vars->rename_info.ReplaceIfExists = 1;
 442			vars->rename_info.RootDirectory = 0;
 443			vars->rename_info.FileNameLength = cpu_to_le32(len);
 444
 445			size[0] = sizeof(struct smb2_file_rename_info);
 446			data[0] = &vars->rename_info;
 447
 448			size[1] = len + 2 /* null */;
 449			data[1] = in_iov[i].iov_base;
 450
 451			if (cfile) {
 452				rc = SMB2_set_info_init(tcon, server,
 453							&rqst[num_rqst],
 454							cfile->fid.persistent_fid,
 455							cfile->fid.volatile_fid,
 456							current->tgid, FILE_RENAME_INFORMATION,
 457							SMB2_O_INFO_FILE, 0, data, size);
 458			} else {
 459				rc = SMB2_set_info_init(tcon, server,
 460							&rqst[num_rqst],
 461							COMPOUND_FID, COMPOUND_FID,
 462							current->tgid, FILE_RENAME_INFORMATION,
 463							SMB2_O_INFO_FILE, 0, data, size);
 
 
 
 
 464			}
 465			if (!rc && (!cfile || num_rqst > 1)) {
 466				smb2_set_next_command(tcon, &rqst[num_rqst]);
 467				smb2_set_related(&rqst[num_rqst]);
 468			} else if (rc) {
 469				goto finished;
 470			}
 471			num_rqst++;
 472			trace_smb3_rename_enter(xid, tcon->tid, ses->Suid, full_path);
 473			break;
 474		case SMB2_OP_HARDLINK:
 475			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 476			rqst[num_rqst].rq_nvec = 2;
 477
 478			len = in_iov[i].iov_len;
 479
 480			vars->link_info.ReplaceIfExists = 0;
 481			vars->link_info.RootDirectory = 0;
 482			vars->link_info.FileNameLength = cpu_to_le32(len);
 483
 484			size[0] = sizeof(struct smb2_file_link_info);
 485			data[0] = &vars->link_info;
 486
 487			size[1] = len + 2 /* null */;
 488			data[1] = in_iov[i].iov_base;
 489
 490			rc = SMB2_set_info_init(tcon, server,
 491						&rqst[num_rqst], COMPOUND_FID,
 492						COMPOUND_FID, current->tgid,
 493						FILE_LINK_INFORMATION,
 494						SMB2_O_INFO_FILE, 0, data, size);
 495			if (rc)
 496				goto finished;
 497			smb2_set_next_command(tcon, &rqst[num_rqst]);
 498			smb2_set_related(&rqst[num_rqst++]);
 499			trace_smb3_hardlink_enter(xid, tcon->tid, ses->Suid, full_path);
 500			break;
 501		case SMB2_OP_SET_REPARSE:
 502			rqst[num_rqst].rq_iov = vars->io_iov;
 503			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
 504
 505			if (cfile) {
 506				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
 507						     cfile->fid.persistent_fid,
 508						     cfile->fid.volatile_fid,
 509						     FSCTL_SET_REPARSE_POINT,
 510						     in_iov[i].iov_base,
 511						     in_iov[i].iov_len, 0);
 512			} else {
 513				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
 514						     COMPOUND_FID, COMPOUND_FID,
 515						     FSCTL_SET_REPARSE_POINT,
 516						     in_iov[i].iov_base,
 517						     in_iov[i].iov_len, 0);
 518			}
 519			if (!rc && (!cfile || num_rqst > 1)) {
 520				smb2_set_next_command(tcon, &rqst[num_rqst]);
 521				smb2_set_related(&rqst[num_rqst]);
 522			} else if (rc) {
 523				goto finished;
 524			}
 525			num_rqst++;
 526			trace_smb3_set_reparse_compound_enter(xid, tcon->tid,
 527							      ses->Suid, full_path);
 528			break;
 529		case SMB2_OP_GET_REPARSE:
 530			rqst[num_rqst].rq_iov = vars->io_iov;
 531			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
 532
 533			if (cfile) {
 534				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
 535						     cfile->fid.persistent_fid,
 536						     cfile->fid.volatile_fid,
 537						     FSCTL_GET_REPARSE_POINT,
 538						     NULL, 0, CIFSMaxBufSize);
 539			} else {
 540				rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
 541						     COMPOUND_FID, COMPOUND_FID,
 542						     FSCTL_GET_REPARSE_POINT,
 543						     NULL, 0, CIFSMaxBufSize);
 544			}
 545			if (!rc && (!cfile || num_rqst > 1)) {
 546				smb2_set_next_command(tcon, &rqst[num_rqst]);
 547				smb2_set_related(&rqst[num_rqst]);
 548			} else if (rc) {
 549				goto finished;
 550			}
 551			num_rqst++;
 552			trace_smb3_get_reparse_compound_enter(xid, tcon->tid,
 553							      ses->Suid, full_path);
 554			break;
 555		case SMB2_OP_QUERY_WSL_EA:
 556			rqst[num_rqst].rq_iov = &vars->ea_iov;
 557			rqst[num_rqst].rq_nvec = 1;
 558
 559			if (cfile) {
 560				rc = SMB2_query_info_init(tcon, server,
 561							  &rqst[num_rqst],
 562							  cfile->fid.persistent_fid,
 563							  cfile->fid.volatile_fid,
 564							  FILE_FULL_EA_INFORMATION,
 565							  SMB2_O_INFO_FILE, 0,
 566							  SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
 567							  sizeof(wsl_query_eas),
 568							  (void *)wsl_query_eas);
 569			} else {
 570				rc = SMB2_query_info_init(tcon, server,
 571							  &rqst[num_rqst],
 572							  COMPOUND_FID,
 573							  COMPOUND_FID,
 574							  FILE_FULL_EA_INFORMATION,
 575							  SMB2_O_INFO_FILE, 0,
 576							  SMB2_WSL_MAX_QUERY_EA_RESP_SIZE,
 577							  sizeof(wsl_query_eas),
 578							  (void *)wsl_query_eas);
 579			}
 580			if (!rc && (!cfile || num_rqst > 1)) {
 581				smb2_set_next_command(tcon, &rqst[num_rqst]);
 582				smb2_set_related(&rqst[num_rqst]);
 583			} else if (rc) {
 584				goto finished;
 585			}
 586			num_rqst++;
 
 
 587			break;
 588		default:
 589			cifs_dbg(VFS, "Invalid command\n");
 590			rc = -EINVAL;
 591		}
 592	}
 593	if (rc)
 594		goto finished;
 595
 596	/* We already have a handle so we can skip the close */
 597	if (cfile)
 598		goto after_close;
 599	/* Close */
 600	flags |= CIFS_CP_CREATE_CLOSE_OP;
 601	rqst[num_rqst].rq_iov = &vars->close_iov;
 602	rqst[num_rqst].rq_nvec = 1;
 603	rc = SMB2_close_init(tcon, server,
 604			     &rqst[num_rqst], COMPOUND_FID,
 605			     COMPOUND_FID, false);
 606	smb2_set_related(&rqst[num_rqst]);
 607	if (rc)
 608		goto finished;
 609 after_close:
 610	num_rqst++;
 611
 612	if (cfile) {
 613		if (retries)
 614			for (i = 1; i < num_rqst - 2; i++)
 615				smb2_set_replay(server, &rqst[i]);
 616
 617		rc = compound_send_recv(xid, ses, server,
 618					flags, num_rqst - 2,
 619					&rqst[1], &resp_buftype[1],
 620					&rsp_iov[1]);
 621	} else {
 622		if (retries)
 623			for (i = 0; i < num_rqst; i++)
 624				smb2_set_replay(server, &rqst[i]);
 625
 626		rc = compound_send_recv(xid, ses, server,
 627					flags, num_rqst,
 628					rqst, resp_buftype,
 629					rsp_iov);
 630	}
 631
 632finished:
 633	num_rqst = 0;
 634	SMB2_open_free(&rqst[num_rqst++]);
 635	if (rc == -EREMCHG) {
 636		pr_warn_once("server share %s deleted\n", tcon->tree_name);
 637		tcon->need_reconnect = true;
 638	}
 639
 640	tmp_rc = rc;
 641	for (i = 0; i < num_cmds; i++) {
 642		char *buf = rsp_iov[i + i].iov_base;
 643
 644		if (buf && resp_buftype[i + 1] != CIFS_NO_BUFFER)
 645			rc = server->ops->map_error(buf, false);
 646		else
 647			rc = tmp_rc;
 648		switch (cmds[i]) {
 649		case SMB2_OP_QUERY_INFO:
 650			idata = in_iov[i].iov_base;
 651			idata->contains_posix_file_info = false;
 652			if (rc == 0 && cfile && cfile->symlink_target) {
 653				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
 654				if (!idata->symlink_target)
 655					rc = -ENOMEM;
 656			}
 657			if (rc == 0) {
 658				qi_rsp = (struct smb2_query_info_rsp *)
 659					rsp_iov[i + 1].iov_base;
 660				rc = smb2_validate_and_copy_iov(
 661					le16_to_cpu(qi_rsp->OutputBufferOffset),
 662					le32_to_cpu(qi_rsp->OutputBufferLength),
 663					&rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
 664			}
 665			SMB2_query_info_free(&rqst[num_rqst++]);
 666			if (rc)
 667				trace_smb3_query_info_compound_err(xid,  tcon->tid,
 668								   ses->Suid, rc);
 669			else
 670				trace_smb3_query_info_compound_done(xid, tcon->tid,
 671								    ses->Suid);
 672			break;
 673		case SMB2_OP_POSIX_QUERY_INFO:
 674			idata = in_iov[i].iov_base;
 675			idata->contains_posix_file_info = true;
 676			if (rc == 0 && cfile && cfile->symlink_target) {
 677				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
 678				if (!idata->symlink_target)
 679					rc = -ENOMEM;
 680			}
 681			if (rc == 0) {
 682				qi_rsp = (struct smb2_query_info_rsp *)
 683					rsp_iov[i + 1].iov_base;
 684				rc = smb2_validate_and_copy_iov(
 685					le16_to_cpu(qi_rsp->OutputBufferOffset),
 686					le32_to_cpu(qi_rsp->OutputBufferLength),
 687					&rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
 688					(char *)&idata->posix_fi);
 689			}
 690			if (rc == 0)
 691				rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
 692
 693			SMB2_query_info_free(&rqst[num_rqst++]);
 694			if (rc)
 695				trace_smb3_posix_query_info_compound_err(xid,  tcon->tid,
 696									 ses->Suid, rc);
 697			else
 698				trace_smb3_posix_query_info_compound_done(xid, tcon->tid,
 699									  ses->Suid);
 700			break;
 701		case SMB2_OP_DELETE:
 702			if (rc)
 703				trace_smb3_delete_err(xid, tcon->tid, ses->Suid, rc);
 704			else {
 705				/*
 706				 * If dentry (hence, inode) is NULL, lease break is going to
 707				 * take care of degrading leases on handles for deleted files.
 708				 */
 709				if (inode)
 710					cifs_mark_open_handles_for_deleted_file(inode, full_path);
 711				trace_smb3_delete_done(xid, tcon->tid, ses->Suid);
 712			}
 713			break;
 714		case SMB2_OP_MKDIR:
 715			if (rc)
 716				trace_smb3_mkdir_err(xid, tcon->tid, ses->Suid, rc);
 717			else
 718				trace_smb3_mkdir_done(xid, tcon->tid, ses->Suid);
 719			break;
 720		case SMB2_OP_HARDLINK:
 721			if (rc)
 722				trace_smb3_hardlink_err(xid,  tcon->tid, ses->Suid, rc);
 723			else
 724				trace_smb3_hardlink_done(xid, tcon->tid, ses->Suid);
 725			SMB2_set_info_free(&rqst[num_rqst++]);
 726			break;
 727		case SMB2_OP_RENAME:
 728			if (rc)
 729				trace_smb3_rename_err(xid, tcon->tid, ses->Suid, rc);
 730			else
 731				trace_smb3_rename_done(xid, tcon->tid, ses->Suid);
 732			SMB2_set_info_free(&rqst[num_rqst++]);
 733			break;
 734		case SMB2_OP_RMDIR:
 735			if (rc)
 736				trace_smb3_rmdir_err(xid, tcon->tid, ses->Suid, rc);
 737			else
 738				trace_smb3_rmdir_done(xid, tcon->tid, ses->Suid);
 739			SMB2_set_info_free(&rqst[num_rqst++]);
 740			break;
 741		case SMB2_OP_SET_EOF:
 742			if (rc)
 743				trace_smb3_set_eof_err(xid, tcon->tid, ses->Suid, rc);
 744			else
 745				trace_smb3_set_eof_done(xid, tcon->tid, ses->Suid);
 746			SMB2_set_info_free(&rqst[num_rqst++]);
 747			break;
 748		case SMB2_OP_SET_INFO:
 749			if (rc)
 750				trace_smb3_set_info_compound_err(xid,  tcon->tid,
 751								 ses->Suid, rc);
 752			else
 753				trace_smb3_set_info_compound_done(xid, tcon->tid,
 754								  ses->Suid);
 755			SMB2_set_info_free(&rqst[num_rqst++]);
 756			break;
 757		case SMB2_OP_SET_REPARSE:
 758			if (rc) {
 759				trace_smb3_set_reparse_compound_err(xid, tcon->tid,
 760								    ses->Suid, rc);
 761			} else {
 762				trace_smb3_set_reparse_compound_done(xid, tcon->tid,
 763								     ses->Suid);
 764			}
 765			SMB2_ioctl_free(&rqst[num_rqst++]);
 766			break;
 767		case SMB2_OP_GET_REPARSE:
 768			if (!rc) {
 769				iov = &rsp_iov[i + 1];
 770				idata = in_iov[i].iov_base;
 771				idata->reparse.io.iov = *iov;
 772				idata->reparse.io.buftype = resp_buftype[i + 1];
 773				idata->contains_posix_file_info = false; /* BB VERIFY */
 774				rbuf = reparse_buf_ptr(iov);
 775				if (IS_ERR(rbuf)) {
 776					rc = PTR_ERR(rbuf);
 777					trace_smb3_get_reparse_compound_err(xid, tcon->tid,
 778									    ses->Suid, rc);
 779				} else {
 780					idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
 781					trace_smb3_get_reparse_compound_done(xid, tcon->tid,
 782									     ses->Suid);
 783				}
 784				memset(iov, 0, sizeof(*iov));
 785				resp_buftype[i + 1] = CIFS_NO_BUFFER;
 786			} else {
 787				trace_smb3_get_reparse_compound_err(xid, tcon->tid,
 788								    ses->Suid, rc);
 789			}
 790			SMB2_ioctl_free(&rqst[num_rqst++]);
 791			break;
 792		case SMB2_OP_QUERY_WSL_EA:
 793			if (!rc) {
 794				idata = in_iov[i].iov_base;
 795				idata->contains_posix_file_info = false;
 796				qi_rsp = rsp_iov[i + 1].iov_base;
 797				data[0] = (u8 *)qi_rsp + le16_to_cpu(qi_rsp->OutputBufferOffset);
 798				size[0] = le32_to_cpu(qi_rsp->OutputBufferLength);
 799				rc = check_wsl_eas(&rsp_iov[i + 1]);
 800				if (!rc) {
 801					memcpy(idata->wsl.eas, data[0], size[0]);
 802					idata->wsl.eas_len = size[0];
 803				}
 804			}
 805			if (!rc) {
 806				trace_smb3_query_wsl_ea_compound_done(xid, tcon->tid,
 807								      ses->Suid);
 808			} else {
 809				trace_smb3_query_wsl_ea_compound_err(xid, tcon->tid,
 810								     ses->Suid, rc);
 811			}
 812			SMB2_query_info_free(&rqst[num_rqst++]);
 813			break;
 814		}
 815	}
 816	SMB2_close_free(&rqst[num_rqst]);
 817	rc = tmp_rc;
 818
 819	num_cmds += 2;
 820	if (out_iov && out_buftype) {
 821		memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
 822		memcpy(out_buftype, resp_buftype,
 823		       num_cmds * sizeof(*out_buftype));
 824	} else {
 825		for (i = 0; i < num_cmds; i++)
 826			free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
 827	}
 828	num_cmds -= 2; /* correct num_cmds as there could be a retry */
 829	kfree(vars);
 830
 831	if (is_replayable_error(rc) &&
 832	    smb2_should_replay(tcon, &retries, &cur_sleep))
 833		goto replay_again;
 834
 835	if (cfile)
 836		cifsFileInfo_put(cfile);
 837
 838	return rc;
 839}
 840
 841static int parse_create_response(struct cifs_open_info_data *data,
 842				 struct cifs_sb_info *cifs_sb,
 843				 const char *full_path,
 844				 const struct kvec *iov)
 845{
 846	struct smb2_create_rsp *rsp = iov->iov_base;
 847	bool reparse_point = false;
 848	u32 tag = 0;
 849	int rc = 0;
 850
 851	switch (rsp->hdr.Status) {
 852	case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
 853		reparse_point = true;
 854		break;
 855	case STATUS_STOPPED_ON_SYMLINK:
 856		rc = smb2_parse_symlink_response(cifs_sb, iov,
 857						 full_path,
 858						 &data->symlink_target);
 859		if (rc)
 860			return rc;
 861		tag = IO_REPARSE_TAG_SYMLINK;
 862		reparse_point = true;
 863		break;
 864	case STATUS_SUCCESS:
 865		reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
 866		break;
 867	}
 868	data->reparse_point = reparse_point;
 869	data->reparse.tag = tag;
 870	return rc;
 871}
 872
 873/* Check only if SMB2_OP_QUERY_WSL_EA command failed in the compound chain */
 874static bool ea_unsupported(int *cmds, int num_cmds,
 875			   struct kvec *out_iov, int *out_buftype)
 876{
 877	int i;
 878
 879	if (cmds[num_cmds - 1] != SMB2_OP_QUERY_WSL_EA)
 880		return false;
 881
 882	for (i = 1; i < num_cmds - 1; i++) {
 883		struct smb2_hdr *hdr = out_iov[i].iov_base;
 884
 885		if (out_buftype[i] == CIFS_NO_BUFFER || !hdr ||
 886		    hdr->Status != STATUS_SUCCESS)
 887			return false;
 888	}
 889	return true;
 890}
 891
 892static inline void free_rsp_iov(struct kvec *iovs, int *buftype, int count)
 893{
 894	int i;
 895
 896	for (i = 0; i < count; i++) {
 897		free_rsp_buf(buftype[i], iovs[i].iov_base);
 898		memset(&iovs[i], 0, sizeof(*iovs));
 899		buftype[i] = CIFS_NO_BUFFER;
 900	}
 901}
 902
 903int smb2_query_path_info(const unsigned int xid,
 904			 struct cifs_tcon *tcon,
 905			 struct cifs_sb_info *cifs_sb,
 906			 const char *full_path,
 907			 struct cifs_open_info_data *data)
 908{
 909	struct kvec in_iov[3], out_iov[5] = {};
 910	struct cached_fid *cfid = NULL;
 911	struct cifs_open_parms oparms;
 912	struct cifsFileInfo *cfile;
 913	__u32 create_options = 0;
 914	int out_buftype[5] = {};
 
 915	struct smb2_hdr *hdr;
 916	int num_cmds = 0;
 917	int cmds[3];
 
 918	bool islink;
 
 919	int rc, rc2;
 920
 921	data->adjust_tz = false;
 922	data->reparse_point = false;
 923
 924	/*
 925	 * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
 926	 * Create SMB2_query_posix_info worker function to do non-compounded
 927	 * query when we already have an open file handle for this. For now this
 928	 * is fast enough (always using the compounded version).
 929	 */
 930	if (!tcon->posix_extensions) {
 931		if (*full_path) {
 932			rc = -ENOENT;
 933		} else {
 934			rc = open_cached_dir(xid, tcon, full_path,
 935					     cifs_sb, false, &cfid);
 936		}
 937		/* If it is a root and its handle is cached then use it */
 938		if (!rc) {
 939			if (cfid->file_all_info_is_valid) {
 940				memcpy(&data->fi, &cfid->file_all_info,
 941				       sizeof(data->fi));
 942			} else {
 943				rc = SMB2_query_info(xid, tcon,
 944						     cfid->fid.persistent_fid,
 945						     cfid->fid.volatile_fid,
 946						     &data->fi);
 947			}
 948			close_cached_dir(cfid);
 949			return rc;
 950		}
 951		cmds[num_cmds++] = SMB2_OP_QUERY_INFO;
 952	} else {
 953		cmds[num_cmds++] = SMB2_OP_POSIX_QUERY_INFO;
 954	}
 955
 956	in_iov[0].iov_base = data;
 957	in_iov[0].iov_len = sizeof(*data);
 958	in_iov[1] = in_iov[0];
 959	in_iov[2] = in_iov[0];
 960
 961	cifs_get_readable_path(tcon, full_path, &cfile);
 962	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
 963			     FILE_OPEN, create_options, ACL_NO_MODE);
 964	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 965			      &oparms, in_iov, cmds, num_cmds,
 966			      cfile, out_iov, out_buftype, NULL);
 
 967	hdr = out_iov[0].iov_base;
 968	/*
 969	 * If first iov is unset, then SMB session was dropped or we've got a
 970	 * cached open file (@cfile).
 971	 */
 972	if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
 973		goto out;
 974
 975	switch (rc) {
 976	case 0:
 977		rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
 978		break;
 979	case -EOPNOTSUPP:
 980		/*
 981		 * BB TODO: When support for special files added to Samba
 982		 * re-verify this path.
 983		 */
 984		rc = parse_create_response(data, cifs_sb, full_path, &out_iov[0]);
 985		if (rc || !data->reparse_point)
 986			goto out;
 987
 988		/*
 989		 * Skip SMB2_OP_GET_REPARSE if symlink already parsed in create
 990		 * response.
 991		 */
 992		if (data->reparse.tag != IO_REPARSE_TAG_SYMLINK)
 993			cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
 994		if (!tcon->posix_extensions)
 995			cmds[num_cmds++] = SMB2_OP_QUERY_WSL_EA;
 996
 997		oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
 998				     FILE_READ_ATTRIBUTES |
 999				     FILE_READ_EA | SYNCHRONIZE,
1000				     FILE_OPEN, create_options |
1001				     OPEN_REPARSE_POINT, ACL_NO_MODE);
1002		cifs_get_readable_path(tcon, full_path, &cfile);
1003		free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
1004		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1005				      &oparms, in_iov, cmds, num_cmds,
1006				      cfile, out_iov, out_buftype, NULL);
1007		if (rc && ea_unsupported(cmds, num_cmds,
1008					 out_iov, out_buftype)) {
1009			if (data->reparse.tag != IO_REPARSE_TAG_LX_BLK &&
1010			    data->reparse.tag != IO_REPARSE_TAG_LX_CHR)
1011				rc = 0;
1012			else
1013				rc = -EOPNOTSUPP;
1014		}
1015		break;
1016	case -EREMOTE:
1017		break;
1018	default:
1019		if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
1020			break;
1021		rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
1022						     full_path, &islink);
1023		if (rc2) {
1024			rc = rc2;
1025			goto out;
1026		}
1027		if (islink)
1028			rc = -EREMOTE;
1029	}
1030
1031out:
1032	free_rsp_iov(out_iov, out_buftype, ARRAY_SIZE(out_iov));
 
1033	return rc;
1034}
1035
1036int
1037smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
1038	   struct cifs_tcon *tcon, const char *name,
1039	   struct cifs_sb_info *cifs_sb)
1040{
1041	struct cifs_open_parms oparms;
1042
1043	oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1044			     FILE_CREATE, CREATE_NOT_FILE, mode);
1045	return smb2_compound_op(xid, tcon, cifs_sb,
1046				name, &oparms, NULL,
1047				&(int){SMB2_OP_MKDIR}, 1,
1048				NULL, NULL, NULL, NULL);
1049}
1050
1051void
1052smb2_mkdir_setinfo(struct inode *inode, const char *name,
1053		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
1054		   const unsigned int xid)
1055{
1056	struct cifs_open_parms oparms;
1057	FILE_BASIC_INFO data = {};
1058	struct cifsInodeInfo *cifs_i;
1059	struct cifsFileInfo *cfile;
1060	struct kvec in_iov;
1061	u32 dosattrs;
1062	int tmprc;
1063
1064	in_iov.iov_base = &data;
1065	in_iov.iov_len = sizeof(data);
1066	cifs_i = CIFS_I(inode);
1067	dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
1068	data.Attributes = cpu_to_le32(dosattrs);
1069	cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
1070	oparms = CIFS_OPARMS(cifs_sb, tcon, name, FILE_WRITE_ATTRIBUTES,
1071			     FILE_CREATE, CREATE_NOT_FILE, ACL_NO_MODE);
1072	tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
1073				 &oparms, &in_iov,
 
1074				 &(int){SMB2_OP_SET_INFO}, 1,
1075				 cfile, NULL, NULL, NULL);
1076	if (tmprc == 0)
1077		cifs_i->cifsAttrs = dosattrs;
1078}
1079
1080int
1081smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1082	   struct cifs_sb_info *cifs_sb)
1083{
1084	struct cifs_open_parms oparms;
1085
1086	drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
1087	oparms = CIFS_OPARMS(cifs_sb, tcon, name, DELETE,
1088			     FILE_OPEN, CREATE_NOT_FILE, ACL_NO_MODE);
1089	return smb2_compound_op(xid, tcon, cifs_sb,
1090				name, &oparms, NULL,
1091				&(int){SMB2_OP_RMDIR}, 1,
1092				NULL, NULL, NULL, NULL);
1093}
1094
1095int
1096smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
1097	    struct cifs_sb_info *cifs_sb, struct dentry *dentry)
1098{
1099	struct cifs_open_parms oparms;
1100
1101	oparms = CIFS_OPARMS(cifs_sb, tcon, name,
1102			     DELETE, FILE_OPEN,
1103			     CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
1104			     ACL_NO_MODE);
1105	int rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1106				  NULL, &(int){SMB2_OP_DELETE}, 1,
1107				  NULL, NULL, NULL, dentry);
1108	if (rc == -EINVAL) {
1109		cifs_dbg(FYI, "invalid lease key, resending request without lease");
1110		rc = smb2_compound_op(xid, tcon, cifs_sb, name, &oparms,
1111				      NULL, &(int){SMB2_OP_DELETE}, 1,
1112				      NULL, NULL, NULL, NULL);
1113	}
1114	return rc;
1115}
1116
1117static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
1118			      const char *from_name, const char *to_name,
1119			      struct cifs_sb_info *cifs_sb,
1120			      __u32 create_options, __u32 access,
1121			      int command, struct cifsFileInfo *cfile,
1122				  struct dentry *dentry)
1123{
1124	struct cifs_open_parms oparms;
1125	struct kvec in_iov;
1126	__le16 *smb2_to_name = NULL;
1127	int rc;
1128
1129	smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
1130	if (smb2_to_name == NULL) {
1131		rc = -ENOMEM;
1132		goto smb2_rename_path;
1133	}
1134	in_iov.iov_base = smb2_to_name;
1135	in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
1136	oparms = CIFS_OPARMS(cifs_sb, tcon, from_name, access, FILE_OPEN,
1137			     create_options, ACL_NO_MODE);
1138	rc = smb2_compound_op(xid, tcon, cifs_sb, from_name,
1139			      &oparms, &in_iov, &command, 1,
1140			      cfile, NULL, NULL, dentry);
1141smb2_rename_path:
1142	kfree(smb2_to_name);
1143	return rc;
1144}
1145
1146int smb2_rename_path(const unsigned int xid,
1147		     struct cifs_tcon *tcon,
1148		     struct dentry *source_dentry,
1149		     const char *from_name, const char *to_name,
1150		     struct cifs_sb_info *cifs_sb)
1151{
1152	struct cifsFileInfo *cfile;
1153	__u32 co = file_create_options(source_dentry);
1154
1155	drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
1156	cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
1157
1158	int rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1159				  co, DELETE, SMB2_OP_RENAME, cfile, source_dentry);
1160	if (rc == -EINVAL) {
1161		cifs_dbg(FYI, "invalid lease key, resending request without lease");
1162		cifs_get_writable_path(tcon, from_name,
1163				       FIND_WR_WITH_DELETE, &cfile);
1164		rc = smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
1165				  co, DELETE, SMB2_OP_RENAME, cfile, NULL);
1166	}
1167	return rc;
1168}
1169
1170int smb2_create_hardlink(const unsigned int xid,
1171			 struct cifs_tcon *tcon,
1172			 struct dentry *source_dentry,
1173			 const char *from_name, const char *to_name,
1174			 struct cifs_sb_info *cifs_sb)
1175{
1176	__u32 co = file_create_options(source_dentry);
1177
1178	return smb2_set_path_attr(xid, tcon, from_name, to_name,
1179				  cifs_sb, co, FILE_READ_ATTRIBUTES,
1180				  SMB2_OP_HARDLINK, NULL, NULL);
1181}
1182
1183int
1184smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
1185		   const char *full_path, __u64 size,
1186		   struct cifs_sb_info *cifs_sb, bool set_alloc,
1187		   struct dentry *dentry)
1188{
1189	struct cifs_open_parms oparms;
1190	struct cifsFileInfo *cfile;
1191	struct kvec in_iov;
1192	__le64 eof = cpu_to_le64(size);
1193	int rc;
1194
1195	in_iov.iov_base = &eof;
1196	in_iov.iov_len = sizeof(eof);
1197	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1198
1199	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_DATA,
1200			     FILE_OPEN, 0, ACL_NO_MODE);
1201	rc = smb2_compound_op(xid, tcon, cifs_sb,
1202			      full_path, &oparms, &in_iov,
1203			      &(int){SMB2_OP_SET_EOF}, 1,
1204			      cfile, NULL, NULL, dentry);
1205	if (rc == -EINVAL) {
1206		cifs_dbg(FYI, "invalid lease key, resending request without lease");
1207		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1208		rc = smb2_compound_op(xid, tcon, cifs_sb,
1209				      full_path, &oparms, &in_iov,
1210				      &(int){SMB2_OP_SET_EOF}, 1,
1211				      cfile, NULL, NULL, NULL);
1212	}
1213	return rc;
1214}
1215
1216int
1217smb2_set_file_info(struct inode *inode, const char *full_path,
1218		   FILE_BASIC_INFO *buf, const unsigned int xid)
1219{
1220	struct cifs_open_parms oparms;
1221	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1222	struct tcon_link *tlink;
1223	struct cifs_tcon *tcon;
1224	struct cifsFileInfo *cfile;
1225	struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
1226	int rc;
1227
1228	if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
1229	    (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
1230	    (buf->Attributes == 0))
1231		return 0; /* would be a no op, no sense sending this */
1232
1233	tlink = cifs_sb_tlink(cifs_sb);
1234	if (IS_ERR(tlink))
1235		return PTR_ERR(tlink);
1236	tcon = tlink_tcon(tlink);
1237
1238	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1239	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_WRITE_ATTRIBUTES,
1240			     FILE_OPEN, 0, ACL_NO_MODE);
1241	rc = smb2_compound_op(xid, tcon, cifs_sb,
1242			      full_path, &oparms, &in_iov,
1243			      &(int){SMB2_OP_SET_INFO}, 1,
1244			      cfile, NULL, NULL, NULL);
1245	cifs_put_tlink(tlink);
1246	return rc;
1247}
1248
1249struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
1250				     struct super_block *sb,
1251				     const unsigned int xid,
1252				     struct cifs_tcon *tcon,
1253				     const char *full_path,
1254				     bool directory,
1255				     struct kvec *reparse_iov,
1256				     struct kvec *xattr_iov)
1257{
1258	struct cifs_open_parms oparms;
1259	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1260	struct cifsFileInfo *cfile;
1261	struct inode *new = NULL;
1262	int out_buftype[4] = {};
1263	struct kvec out_iov[4] = {};
1264	struct kvec in_iov[2];
1265	int cmds[2];
 
1266	int rc;
1267	int i;
1268
1269	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1270			     SYNCHRONIZE | DELETE |
1271			     FILE_READ_ATTRIBUTES |
1272			     FILE_WRITE_ATTRIBUTES,
1273			     FILE_CREATE,
1274			     (directory ? CREATE_NOT_FILE : CREATE_NOT_DIR) | OPEN_REPARSE_POINT,
1275			     ACL_NO_MODE);
1276	if (xattr_iov)
1277		oparms.ea_cctx = xattr_iov;
1278
 
 
 
 
 
1279	cmds[0] = SMB2_OP_SET_REPARSE;
1280	in_iov[0] = *reparse_iov;
1281	in_iov[1].iov_base = data;
1282	in_iov[1].iov_len = sizeof(*data);
1283
1284	if (tcon->posix_extensions) {
1285		cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
1286		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1287		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1288				      in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
 
1289		if (!rc) {
1290			rc = smb311_posix_get_inode_info(&new, full_path,
1291							 data, sb, xid);
1292		}
1293	} else {
1294		cmds[1] = SMB2_OP_QUERY_INFO;
1295		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1296		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, &oparms,
1297				      in_iov, cmds, 2, cfile, out_iov, out_buftype, NULL);
 
1298		if (!rc) {
1299			rc = cifs_get_inode_info(&new, full_path,
1300						 data, sb, xid, NULL);
1301		}
1302	}
1303
1304
1305	/*
1306	 * If CREATE was successful but SMB2_OP_SET_REPARSE failed then
1307	 * remove the intermediate object created by CREATE. Otherwise
1308	 * empty object stay on the server when reparse call failed.
1309	 */
1310	if (rc &&
1311	    out_iov[0].iov_base != NULL && out_buftype[0] != CIFS_NO_BUFFER &&
1312	    ((struct smb2_hdr *)out_iov[0].iov_base)->Status == STATUS_SUCCESS &&
1313	    (out_iov[1].iov_base == NULL || out_buftype[1] == CIFS_NO_BUFFER ||
1314	     ((struct smb2_hdr *)out_iov[1].iov_base)->Status != STATUS_SUCCESS))
1315		smb2_unlink(xid, tcon, full_path, cifs_sb, NULL);
1316
1317	for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
1318		free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
1319
1320	return rc ? ERR_PTR(rc) : new;
1321}
1322
1323int smb2_query_reparse_point(const unsigned int xid,
1324			     struct cifs_tcon *tcon,
1325			     struct cifs_sb_info *cifs_sb,
1326			     const char *full_path,
1327			     u32 *tag, struct kvec *rsp,
1328			     int *rsp_buftype)
1329{
1330	struct cifs_open_parms oparms;
1331	struct cifs_open_info_data data = {};
1332	struct cifsFileInfo *cfile;
1333	struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1334	int rc;
1335
1336	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1337
1338	cifs_get_readable_path(tcon, full_path, &cfile);
1339	oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
1340			     FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
1341			     FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
1342	rc = smb2_compound_op(xid, tcon, cifs_sb,
1343			      full_path, &oparms, &in_iov,
1344			      &(int){SMB2_OP_GET_REPARSE}, 1,
1345			      cfile, NULL, NULL, NULL);
1346	if (rc)
1347		goto out;
1348
1349	*tag = data.reparse.tag;
1350	*rsp = data.reparse.io.iov;
1351	*rsp_buftype = data.reparse.io.buftype;
1352	memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1353	data.reparse.io.buftype = CIFS_NO_BUFFER;
1354out:
1355	cifs_free_open_info(&data);
1356	return rc;
1357}
v6.8
   1// SPDX-License-Identifier: LGPL-2.1
   2/*
   3 *
   4 *   Copyright (C) International Business Machines  Corp., 2002, 2011
   5 *                 Etersoft, 2012
   6 *   Author(s): Pavel Shilovsky (pshilovsky@samba.org),
   7 *              Steve French (sfrench@us.ibm.com)
   8 *
   9 */
  10#include <linux/fs.h>
  11#include <linux/stat.h>
  12#include <linux/slab.h>
  13#include <linux/pagemap.h>
  14#include <asm/div64.h>
  15#include "cifsfs.h"
  16#include "cifspdu.h"
  17#include "cifsglob.h"
  18#include "cifsproto.h"
  19#include "cifs_debug.h"
  20#include "cifs_fs_sb.h"
  21#include "cifs_unicode.h"
  22#include "fscache.h"
  23#include "smb2glob.h"
  24#include "smb2pdu.h"
  25#include "smb2proto.h"
  26#include "cached_dir.h"
  27#include "smb2status.h"
  28
  29static struct reparse_data_buffer *reparse_buf_ptr(struct kvec *iov)
  30{
  31	struct reparse_data_buffer *buf;
  32	struct smb2_ioctl_rsp *io = iov->iov_base;
  33	u32 off, count, len;
  34
  35	count = le32_to_cpu(io->OutputCount);
  36	off = le32_to_cpu(io->OutputOffset);
  37	if (check_add_overflow(off, count, &len) || len > iov->iov_len)
  38		return ERR_PTR(-EIO);
  39
  40	buf = (struct reparse_data_buffer *)((u8 *)io + off);
  41	len = sizeof(*buf);
  42	if (count < len || count < le16_to_cpu(buf->ReparseDataLength) + len)
  43		return ERR_PTR(-EIO);
  44	return buf;
  45}
  46
  47static inline __u32 file_create_options(struct dentry *dentry)
  48{
  49	struct cifsInodeInfo *ci;
  50
  51	if (dentry) {
  52		ci = CIFS_I(d_inode(dentry));
  53		if (ci->cifsAttrs & ATTR_REPARSE)
  54			return OPEN_REPARSE_POINT;
  55	}
  56	return 0;
  57}
  58
  59/* Parse owner and group from SMB3.1.1 POSIX query info */
  60static int parse_posix_sids(struct cifs_open_info_data *data,
  61			    struct kvec *rsp_iov)
  62{
  63	struct smb2_query_info_rsp *qi = rsp_iov->iov_base;
  64	unsigned int out_len = le32_to_cpu(qi->OutputBufferLength);
  65	unsigned int qi_len = sizeof(data->posix_fi);
  66	int owner_len, group_len;
  67	u8 *sidsbuf, *sidsbuf_end;
  68
  69	if (out_len <= qi_len)
  70		return -EINVAL;
  71
  72	sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len;
  73	sidsbuf_end = sidsbuf + out_len - qi_len;
  74
  75	owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
  76	if (owner_len == -1)
  77		return -EINVAL;
  78
  79	memcpy(&data->posix_owner, sidsbuf, owner_len);
  80	group_len = posix_info_sid_size(sidsbuf + owner_len, sidsbuf_end);
  81	if (group_len == -1)
  82		return -EINVAL;
  83
  84	memcpy(&data->posix_group, sidsbuf + owner_len, group_len);
  85	return 0;
  86}
  87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  88/*
  89 * note: If cfile is passed, the reference to it is dropped here.
  90 * So make sure that you do not reuse cfile after return from this func.
  91 *
  92 * If passing @out_iov and @out_buftype, ensure to make them both large enough
  93 * (>= 3) to hold all compounded responses.  Caller is also responsible for
  94 * freeing them up with free_rsp_buf().
  95 */
  96static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
  97			    struct cifs_sb_info *cifs_sb, const char *full_path,
  98			    __u32 desired_access, __u32 create_disposition,
  99			    __u32 create_options, umode_t mode, struct kvec *in_iov,
 100			    int *cmds, int num_cmds, struct cifsFileInfo *cfile,
 101			    struct kvec *out_iov, int *out_buftype)
 102{
 103
 
 
 
 
 
 104	struct reparse_data_buffer *rbuf;
 105	struct smb2_compound_vars *vars = NULL;
 
 
 
 106	struct kvec *rsp_iov, *iov;
 
 
 107	struct smb_rqst *rqst;
 108	int rc;
 109	__le16 *utf16_path = NULL;
 110	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 111	struct cifs_fid fid;
 112	struct cifs_ses *ses = tcon->ses;
 113	struct TCP_Server_Info *server;
 114	int num_rqst = 0, i;
 115	int resp_buftype[MAX_COMPOUND];
 116	struct smb2_query_info_rsp *qi_rsp = NULL;
 117	struct cifs_open_info_data *idata;
 118	int flags = 0;
 119	__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
 120	unsigned int size[2];
 121	void *data[2];
 122	int len;
 123	int retries = 0, cur_sleep = 1;
 124
 125replay_again:
 126	/* reinitialize for possible replay */
 127	flags = 0;
 128	oplock = SMB2_OPLOCK_LEVEL_NONE;
 129	num_rqst = 0;
 130	server = cifs_pick_channel(ses);
 131
 132	vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
 133	if (vars == NULL)
 134		return -ENOMEM;
 135	rqst = &vars->rqst[0];
 136	rsp_iov = &vars->rsp_iov[0];
 137
 138	if (smb3_encryption_required(tcon))
 139		flags |= CIFS_TRANSFORM_REQ;
 140
 141	for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)
 142		resp_buftype[i] = CIFS_NO_BUFFER;
 143
 144	/* We already have a handle so we can skip the open */
 145	if (cfile)
 146		goto after_open;
 147
 148	/* Open */
 149	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
 150	if (!utf16_path) {
 151		rc = -ENOMEM;
 152		goto finished;
 153	}
 154
 155	vars->oparms = (struct cifs_open_parms) {
 156		.tcon = tcon,
 157		.path = full_path,
 158		.desired_access = desired_access,
 159		.disposition = create_disposition,
 160		.create_options = cifs_create_options(cifs_sb, create_options),
 161		.fid = &fid,
 162		.mode = mode,
 163		.cifs_sb = cifs_sb,
 164	};
 
 
 
 
 
 
 
 
 
 
 
 
 165
 166	rqst[num_rqst].rq_iov = &vars->open_iov[0];
 167	rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
 168	rc = SMB2_open_init(tcon, server,
 169			    &rqst[num_rqst], &oplock, &vars->oparms,
 170			    utf16_path);
 171	kfree(utf16_path);
 172	if (rc)
 173		goto finished;
 174
 175	smb2_set_next_command(tcon, &rqst[num_rqst]);
 176 after_open:
 177	num_rqst++;
 178	rc = 0;
 179
 180	for (i = 0; i < num_cmds; i++) {
 181		/* Operation */
 182		switch (cmds[i]) {
 183		case SMB2_OP_QUERY_INFO:
 184			rqst[num_rqst].rq_iov = &vars->qi_iov;
 185			rqst[num_rqst].rq_nvec = 1;
 186
 187			if (cfile) {
 188				rc = SMB2_query_info_init(tcon, server,
 189							  &rqst[num_rqst],
 190							  cfile->fid.persistent_fid,
 191							  cfile->fid.volatile_fid,
 192							  FILE_ALL_INFORMATION,
 193							  SMB2_O_INFO_FILE, 0,
 194							  sizeof(struct smb2_file_all_info) +
 195							  PATH_MAX * 2, 0, NULL);
 196			} else {
 197				rc = SMB2_query_info_init(tcon, server,
 198							  &rqst[num_rqst],
 199							  COMPOUND_FID,
 200							  COMPOUND_FID,
 201							  FILE_ALL_INFORMATION,
 202							  SMB2_O_INFO_FILE, 0,
 203							  sizeof(struct smb2_file_all_info) +
 204							  PATH_MAX * 2, 0, NULL);
 205				if (!rc) {
 206					smb2_set_next_command(tcon, &rqst[num_rqst]);
 207					smb2_set_related(&rqst[num_rqst]);
 208				}
 209			}
 210
 211			if (rc)
 
 
 212				goto finished;
 
 213			num_rqst++;
 214			trace_smb3_query_info_compound_enter(xid, ses->Suid,
 215							     tcon->tid, full_path);
 216			break;
 217		case SMB2_OP_POSIX_QUERY_INFO:
 218			rqst[num_rqst].rq_iov = &vars->qi_iov;
 219			rqst[num_rqst].rq_nvec = 1;
 220
 221			if (cfile) {
 222				/* TBD: fix following to allow for longer SIDs */
 223				rc = SMB2_query_info_init(tcon, server,
 224							  &rqst[num_rqst],
 225							  cfile->fid.persistent_fid,
 226							  cfile->fid.volatile_fid,
 227							  SMB_FIND_FILE_POSIX_INFO,
 228							  SMB2_O_INFO_FILE, 0,
 229							  sizeof(struct smb311_posix_qinfo *) +
 230							  (PATH_MAX * 2) +
 231							  (sizeof(struct cifs_sid) * 2), 0, NULL);
 232			} else {
 233				rc = SMB2_query_info_init(tcon, server,
 234							  &rqst[num_rqst],
 235							  COMPOUND_FID,
 236							  COMPOUND_FID,
 237							  SMB_FIND_FILE_POSIX_INFO,
 238							  SMB2_O_INFO_FILE, 0,
 239							  sizeof(struct smb311_posix_qinfo *) +
 240							  (PATH_MAX * 2) +
 241							  (sizeof(struct cifs_sid) * 2), 0, NULL);
 242				if (!rc) {
 243					smb2_set_next_command(tcon, &rqst[num_rqst]);
 244					smb2_set_related(&rqst[num_rqst]);
 245				}
 246			}
 247
 248			if (rc)
 
 
 249				goto finished;
 
 250			num_rqst++;
 251			trace_smb3_posix_query_info_compound_enter(xid, ses->Suid,
 252								   tcon->tid, full_path);
 253			break;
 254		case SMB2_OP_DELETE:
 255			trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
 256			break;
 257		case SMB2_OP_MKDIR:
 258			/*
 259			 * Directories are created through parameters in the
 260			 * SMB2_open() call.
 261			 */
 262			trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
 263			break;
 264		case SMB2_OP_RMDIR:
 265			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 266			rqst[num_rqst].rq_nvec = 1;
 267
 268			size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
 269			data[0] = &delete_pending[0];
 270
 271			rc = SMB2_set_info_init(tcon, server,
 272						&rqst[num_rqst], COMPOUND_FID,
 273						COMPOUND_FID, current->tgid,
 274						FILE_DISPOSITION_INFORMATION,
 275						SMB2_O_INFO_FILE, 0, data, size);
 276			if (rc)
 277				goto finished;
 278			smb2_set_next_command(tcon, &rqst[num_rqst]);
 279			smb2_set_related(&rqst[num_rqst++]);
 280			trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
 281			break;
 282		case SMB2_OP_SET_EOF:
 283			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 284			rqst[num_rqst].rq_nvec = 1;
 285
 286			size[0] = in_iov[i].iov_len;
 287			data[0] = in_iov[i].iov_base;
 288
 289			if (cfile) {
 290				rc = SMB2_set_info_init(tcon, server,
 291							&rqst[num_rqst],
 292							cfile->fid.persistent_fid,
 293							cfile->fid.volatile_fid,
 294							current->tgid,
 295							FILE_END_OF_FILE_INFORMATION,
 296							SMB2_O_INFO_FILE, 0,
 297							data, size);
 298			} else {
 299				rc = SMB2_set_info_init(tcon, server,
 300							&rqst[num_rqst],
 301							COMPOUND_FID,
 302							COMPOUND_FID,
 303							current->tgid,
 304							FILE_END_OF_FILE_INFORMATION,
 305							SMB2_O_INFO_FILE, 0,
 306							data, size);
 307				if (!rc) {
 308					smb2_set_next_command(tcon, &rqst[num_rqst]);
 309					smb2_set_related(&rqst[num_rqst]);
 310				}
 311			}
 312			if (rc)
 
 
 
 313				goto finished;
 
 314			num_rqst++;
 315			trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
 316			break;
 317		case SMB2_OP_SET_INFO:
 318			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 319			rqst[num_rqst].rq_nvec = 1;
 320
 321			size[0] = in_iov[i].iov_len;
 322			data[0] = in_iov[i].iov_base;
 323
 324			if (cfile) {
 325				rc = SMB2_set_info_init(tcon, server,
 326							&rqst[num_rqst],
 327							cfile->fid.persistent_fid,
 328							cfile->fid.volatile_fid, current->tgid,
 329							FILE_BASIC_INFORMATION,
 330							SMB2_O_INFO_FILE, 0, data, size);
 331			} else {
 332				rc = SMB2_set_info_init(tcon, server,
 333							&rqst[num_rqst],
 334							COMPOUND_FID,
 335							COMPOUND_FID, current->tgid,
 336							FILE_BASIC_INFORMATION,
 337							SMB2_O_INFO_FILE, 0, data, size);
 338				if (!rc) {
 339					smb2_set_next_command(tcon, &rqst[num_rqst]);
 340					smb2_set_related(&rqst[num_rqst]);
 341				}
 342			}
 343
 344			if (rc)
 
 
 345				goto finished;
 
 346			num_rqst++;
 347			trace_smb3_set_info_compound_enter(xid, ses->Suid,
 348							   tcon->tid, full_path);
 349			break;
 350		case SMB2_OP_RENAME:
 351			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 352			rqst[num_rqst].rq_nvec = 2;
 353
 354			len = in_iov[i].iov_len;
 355
 356			vars->rename_info.ReplaceIfExists = 1;
 357			vars->rename_info.RootDirectory = 0;
 358			vars->rename_info.FileNameLength = cpu_to_le32(len);
 359
 360			size[0] = sizeof(struct smb2_file_rename_info);
 361			data[0] = &vars->rename_info;
 362
 363			size[1] = len + 2 /* null */;
 364			data[1] = in_iov[i].iov_base;
 365
 366			if (cfile) {
 367				rc = SMB2_set_info_init(tcon, server,
 368							&rqst[num_rqst],
 369							cfile->fid.persistent_fid,
 370							cfile->fid.volatile_fid,
 371							current->tgid, FILE_RENAME_INFORMATION,
 372							SMB2_O_INFO_FILE, 0, data, size);
 373			} else {
 374				rc = SMB2_set_info_init(tcon, server,
 375							&rqst[num_rqst],
 376							COMPOUND_FID, COMPOUND_FID,
 377							current->tgid, FILE_RENAME_INFORMATION,
 378							SMB2_O_INFO_FILE, 0, data, size);
 379				if (!rc) {
 380					smb2_set_next_command(tcon, &rqst[num_rqst]);
 381					smb2_set_related(&rqst[num_rqst]);
 382				}
 383			}
 384			if (rc)
 
 
 
 385				goto finished;
 
 386			num_rqst++;
 387			trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
 388			break;
 389		case SMB2_OP_HARDLINK:
 390			rqst[num_rqst].rq_iov = &vars->si_iov[0];
 391			rqst[num_rqst].rq_nvec = 2;
 392
 393			len = in_iov[i].iov_len;
 394
 395			vars->link_info.ReplaceIfExists = 0;
 396			vars->link_info.RootDirectory = 0;
 397			vars->link_info.FileNameLength = cpu_to_le32(len);
 398
 399			size[0] = sizeof(struct smb2_file_link_info);
 400			data[0] = &vars->link_info;
 401
 402			size[1] = len + 2 /* null */;
 403			data[1] = in_iov[i].iov_base;
 404
 405			rc = SMB2_set_info_init(tcon, server,
 406						&rqst[num_rqst], COMPOUND_FID,
 407						COMPOUND_FID, current->tgid,
 408						FILE_LINK_INFORMATION,
 409						SMB2_O_INFO_FILE, 0, data, size);
 410			if (rc)
 411				goto finished;
 412			smb2_set_next_command(tcon, &rqst[num_rqst]);
 413			smb2_set_related(&rqst[num_rqst++]);
 414			trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
 415			break;
 416		case SMB2_OP_SET_REPARSE:
 417			rqst[num_rqst].rq_iov = vars->io_iov;
 418			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
 419
 420			rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
 421					     COMPOUND_FID, COMPOUND_FID,
 422					     FSCTL_SET_REPARSE_POINT,
 423					     in_iov[i].iov_base,
 424					     in_iov[i].iov_len, 0);
 425			if (rc)
 
 
 
 
 
 
 
 
 
 
 
 
 426				goto finished;
 427			smb2_set_next_command(tcon, &rqst[num_rqst]);
 428			smb2_set_related(&rqst[num_rqst++]);
 429			trace_smb3_set_reparse_compound_enter(xid, ses->Suid,
 430							      tcon->tid, full_path);
 431			break;
 432		case SMB2_OP_GET_REPARSE:
 433			rqst[num_rqst].rq_iov = vars->io_iov;
 434			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
 435
 436			rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
 437					     COMPOUND_FID, COMPOUND_FID,
 438					     FSCTL_GET_REPARSE_POINT,
 439					     NULL, 0, CIFSMaxBufSize);
 440			if (rc)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 441				goto finished;
 442			smb2_set_next_command(tcon, &rqst[num_rqst]);
 443			smb2_set_related(&rqst[num_rqst++]);
 444			trace_smb3_get_reparse_compound_enter(xid, ses->Suid,
 445							      tcon->tid, full_path);
 446			break;
 447		default:
 448			cifs_dbg(VFS, "Invalid command\n");
 449			rc = -EINVAL;
 450		}
 451	}
 452	if (rc)
 453		goto finished;
 454
 455	/* We already have a handle so we can skip the close */
 456	if (cfile)
 457		goto after_close;
 458	/* Close */
 459	flags |= CIFS_CP_CREATE_CLOSE_OP;
 460	rqst[num_rqst].rq_iov = &vars->close_iov;
 461	rqst[num_rqst].rq_nvec = 1;
 462	rc = SMB2_close_init(tcon, server,
 463			     &rqst[num_rqst], COMPOUND_FID,
 464			     COMPOUND_FID, false);
 465	smb2_set_related(&rqst[num_rqst]);
 466	if (rc)
 467		goto finished;
 468 after_close:
 469	num_rqst++;
 470
 471	if (cfile) {
 472		if (retries)
 473			for (i = 1; i < num_rqst - 2; i++)
 474				smb2_set_replay(server, &rqst[i]);
 475
 476		rc = compound_send_recv(xid, ses, server,
 477					flags, num_rqst - 2,
 478					&rqst[1], &resp_buftype[1],
 479					&rsp_iov[1]);
 480	} else {
 481		if (retries)
 482			for (i = 0; i < num_rqst; i++)
 483				smb2_set_replay(server, &rqst[i]);
 484
 485		rc = compound_send_recv(xid, ses, server,
 486					flags, num_rqst,
 487					rqst, resp_buftype,
 488					rsp_iov);
 489	}
 490
 491finished:
 492	num_rqst = 0;
 493	SMB2_open_free(&rqst[num_rqst++]);
 494	if (rc == -EREMCHG) {
 495		pr_warn_once("server share %s deleted\n", tcon->tree_name);
 496		tcon->need_reconnect = true;
 497	}
 498
 
 499	for (i = 0; i < num_cmds; i++) {
 
 
 
 
 
 
 500		switch (cmds[i]) {
 501		case SMB2_OP_QUERY_INFO:
 502			idata = in_iov[i].iov_base;
 
 503			if (rc == 0 && cfile && cfile->symlink_target) {
 504				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
 505				if (!idata->symlink_target)
 506					rc = -ENOMEM;
 507			}
 508			if (rc == 0) {
 509				qi_rsp = (struct smb2_query_info_rsp *)
 510					rsp_iov[i + 1].iov_base;
 511				rc = smb2_validate_and_copy_iov(
 512					le16_to_cpu(qi_rsp->OutputBufferOffset),
 513					le32_to_cpu(qi_rsp->OutputBufferLength),
 514					&rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
 515			}
 516			SMB2_query_info_free(&rqst[num_rqst++]);
 517			if (rc)
 518				trace_smb3_query_info_compound_err(xid,  ses->Suid,
 519								   tcon->tid, rc);
 520			else
 521				trace_smb3_query_info_compound_done(xid, ses->Suid,
 522								    tcon->tid);
 523			break;
 524		case SMB2_OP_POSIX_QUERY_INFO:
 525			idata = in_iov[i].iov_base;
 
 526			if (rc == 0 && cfile && cfile->symlink_target) {
 527				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
 528				if (!idata->symlink_target)
 529					rc = -ENOMEM;
 530			}
 531			if (rc == 0) {
 532				qi_rsp = (struct smb2_query_info_rsp *)
 533					rsp_iov[i + 1].iov_base;
 534				rc = smb2_validate_and_copy_iov(
 535					le16_to_cpu(qi_rsp->OutputBufferOffset),
 536					le32_to_cpu(qi_rsp->OutputBufferLength),
 537					&rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
 538					(char *)&idata->posix_fi);
 539			}
 540			if (rc == 0)
 541				rc = parse_posix_sids(idata, &rsp_iov[i + 1]);
 542
 543			SMB2_query_info_free(&rqst[num_rqst++]);
 544			if (rc)
 545				trace_smb3_posix_query_info_compound_err(xid,  ses->Suid,
 546									 tcon->tid, rc);
 547			else
 548				trace_smb3_posix_query_info_compound_done(xid, ses->Suid,
 549									  tcon->tid);
 550			break;
 551		case SMB2_OP_DELETE:
 552			if (rc)
 553				trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
 554			else
 555				trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
 
 
 
 
 
 
 
 556			break;
 557		case SMB2_OP_MKDIR:
 558			if (rc)
 559				trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
 560			else
 561				trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
 562			break;
 563		case SMB2_OP_HARDLINK:
 564			if (rc)
 565				trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);
 566			else
 567				trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
 568			SMB2_set_info_free(&rqst[num_rqst++]);
 569			break;
 570		case SMB2_OP_RENAME:
 571			if (rc)
 572				trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);
 573			else
 574				trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
 575			SMB2_set_info_free(&rqst[num_rqst++]);
 576			break;
 577		case SMB2_OP_RMDIR:
 578			if (rc)
 579				trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);
 580			else
 581				trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
 582			SMB2_set_info_free(&rqst[num_rqst++]);
 583			break;
 584		case SMB2_OP_SET_EOF:
 585			if (rc)
 586				trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
 587			else
 588				trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
 589			SMB2_set_info_free(&rqst[num_rqst++]);
 590			break;
 591		case SMB2_OP_SET_INFO:
 592			if (rc)
 593				trace_smb3_set_info_compound_err(xid,  ses->Suid,
 594								 tcon->tid, rc);
 595			else
 596				trace_smb3_set_info_compound_done(xid, ses->Suid,
 597								  tcon->tid);
 598			SMB2_set_info_free(&rqst[num_rqst++]);
 599			break;
 600		case SMB2_OP_SET_REPARSE:
 601			if (rc) {
 602				trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
 603								    tcon->tid, rc);
 604			} else {
 605				trace_smb3_set_reparse_compound_done(xid, ses->Suid,
 606								     tcon->tid);
 607			}
 608			SMB2_ioctl_free(&rqst[num_rqst++]);
 609			break;
 610		case SMB2_OP_GET_REPARSE:
 611			if (!rc) {
 612				iov = &rsp_iov[i + 1];
 613				idata = in_iov[i].iov_base;
 614				idata->reparse.io.iov = *iov;
 615				idata->reparse.io.buftype = resp_buftype[i + 1];
 
 616				rbuf = reparse_buf_ptr(iov);
 617				if (IS_ERR(rbuf)) {
 618					rc = PTR_ERR(rbuf);
 619					trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
 620									    tcon->tid, rc);
 621				} else {
 622					idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
 623					trace_smb3_set_reparse_compound_done(xid, ses->Suid,
 624									     tcon->tid);
 625				}
 626				memset(iov, 0, sizeof(*iov));
 627				resp_buftype[i + 1] = CIFS_NO_BUFFER;
 628			} else {
 629				trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
 630								    tcon->tid, rc);
 631			}
 632			SMB2_ioctl_free(&rqst[num_rqst++]);
 633			break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 634		}
 635	}
 636	SMB2_close_free(&rqst[num_rqst]);
 
 637
 638	num_cmds += 2;
 639	if (out_iov && out_buftype) {
 640		memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
 641		memcpy(out_buftype, resp_buftype,
 642		       num_cmds * sizeof(*out_buftype));
 643	} else {
 644		for (i = 0; i < num_cmds; i++)
 645			free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
 646	}
 647	num_cmds -= 2; /* correct num_cmds as there could be a retry */
 648	kfree(vars);
 649
 650	if (is_replayable_error(rc) &&
 651	    smb2_should_replay(tcon, &retries, &cur_sleep))
 652		goto replay_again;
 653
 654	if (cfile)
 655		cifsFileInfo_put(cfile);
 656
 657	return rc;
 658}
 659
 660static int parse_create_response(struct cifs_open_info_data *data,
 661				 struct cifs_sb_info *cifs_sb,
 
 662				 const struct kvec *iov)
 663{
 664	struct smb2_create_rsp *rsp = iov->iov_base;
 665	bool reparse_point = false;
 666	u32 tag = 0;
 667	int rc = 0;
 668
 669	switch (rsp->hdr.Status) {
 670	case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
 671		reparse_point = true;
 672		break;
 673	case STATUS_STOPPED_ON_SYMLINK:
 674		rc = smb2_parse_symlink_response(cifs_sb, iov,
 
 675						 &data->symlink_target);
 676		if (rc)
 677			return rc;
 678		tag = IO_REPARSE_TAG_SYMLINK;
 679		reparse_point = true;
 680		break;
 681	case STATUS_SUCCESS:
 682		reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
 683		break;
 684	}
 685	data->reparse_point = reparse_point;
 686	data->reparse.tag = tag;
 687	return rc;
 688}
 689
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 690int smb2_query_path_info(const unsigned int xid,
 691			 struct cifs_tcon *tcon,
 692			 struct cifs_sb_info *cifs_sb,
 693			 const char *full_path,
 694			 struct cifs_open_info_data *data)
 695{
 
 
 
 
 696	__u32 create_options = 0;
 697	struct cifsFileInfo *cfile;
 698	struct cached_fid *cfid = NULL;
 699	struct smb2_hdr *hdr;
 700	struct kvec in_iov[2], out_iov[3] = {};
 701	int out_buftype[3] = {};
 702	int cmds[2];
 703	bool islink;
 704	int i, num_cmds;
 705	int rc, rc2;
 706
 707	data->adjust_tz = false;
 708	data->reparse_point = false;
 709
 710	/*
 711	 * BB TODO: Add support for using cached root handle in SMB3.1.1 POSIX.
 712	 * Create SMB2_query_posix_info worker function to do non-compounded
 713	 * query when we already have an open file handle for this. For now this
 714	 * is fast enough (always using the compounded version).
 715	 */
 716	if (!tcon->posix_extensions) {
 717		if (*full_path) {
 718			rc = -ENOENT;
 719		} else {
 720			rc = open_cached_dir(xid, tcon, full_path,
 721					     cifs_sb, false, &cfid);
 722		}
 723		/* If it is a root and its handle is cached then use it */
 724		if (!rc) {
 725			if (cfid->file_all_info_is_valid) {
 726				memcpy(&data->fi, &cfid->file_all_info,
 727				       sizeof(data->fi));
 728			} else {
 729				rc = SMB2_query_info(xid, tcon,
 730						     cfid->fid.persistent_fid,
 731						     cfid->fid.volatile_fid,
 732						     &data->fi);
 733			}
 734			close_cached_dir(cfid);
 735			return rc;
 736		}
 737		cmds[0] = SMB2_OP_QUERY_INFO;
 738	} else {
 739		cmds[0] = SMB2_OP_POSIX_QUERY_INFO;
 740	}
 741
 742	in_iov[0].iov_base = data;
 743	in_iov[0].iov_len = sizeof(*data);
 744	in_iov[1] = in_iov[0];
 
 745
 746	cifs_get_readable_path(tcon, full_path, &cfile);
 
 
 747	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 748			      FILE_READ_ATTRIBUTES, FILE_OPEN,
 749			      create_options, ACL_NO_MODE, in_iov,
 750			      cmds, 1, cfile, out_iov, out_buftype);
 751	hdr = out_iov[0].iov_base;
 752	/*
 753	 * If first iov is unset, then SMB session was dropped or we've got a
 754	 * cached open file (@cfile).
 755	 */
 756	if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
 757		goto out;
 758
 759	switch (rc) {
 760	case 0:
 
 
 761	case -EOPNOTSUPP:
 762		/*
 763		 * BB TODO: When support for special files added to Samba
 764		 * re-verify this path.
 765		 */
 766		rc = parse_create_response(data, cifs_sb, &out_iov[0]);
 767		if (rc || !data->reparse_point)
 768			goto out;
 769
 770		if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) {
 771			/* symlink already parsed in create response */
 772			num_cmds = 1;
 773		} else {
 774			cmds[1] = SMB2_OP_GET_REPARSE;
 775			num_cmds = 2;
 776		}
 777		create_options |= OPEN_REPARSE_POINT;
 
 
 
 
 
 
 778		cifs_get_readable_path(tcon, full_path, &cfile);
 
 779		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 780				      FILE_READ_ATTRIBUTES, FILE_OPEN,
 781				      create_options, ACL_NO_MODE, in_iov,
 782				      cmds, num_cmds, cfile, NULL, NULL);
 
 
 
 
 
 
 
 783		break;
 784	case -EREMOTE:
 785		break;
 786	default:
 787		if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
 788			break;
 789		rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
 790						     full_path, &islink);
 791		if (rc2) {
 792			rc = rc2;
 793			goto out;
 794		}
 795		if (islink)
 796			rc = -EREMOTE;
 797	}
 798
 799out:
 800	for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
 801		free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
 802	return rc;
 803}
 804
 805int
 806smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
 807	   struct cifs_tcon *tcon, const char *name,
 808	   struct cifs_sb_info *cifs_sb)
 809{
 810	return smb2_compound_op(xid, tcon, cifs_sb, name,
 811				FILE_WRITE_ATTRIBUTES, FILE_CREATE,
 812				CREATE_NOT_FILE, mode,
 813				NULL, &(int){SMB2_OP_MKDIR}, 1,
 814				NULL, NULL, NULL);
 
 
 
 815}
 816
 817void
 818smb2_mkdir_setinfo(struct inode *inode, const char *name,
 819		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
 820		   const unsigned int xid)
 821{
 
 822	FILE_BASIC_INFO data = {};
 823	struct cifsInodeInfo *cifs_i;
 824	struct cifsFileInfo *cfile;
 825	struct kvec in_iov;
 826	u32 dosattrs;
 827	int tmprc;
 828
 829	in_iov.iov_base = &data;
 830	in_iov.iov_len = sizeof(data);
 831	cifs_i = CIFS_I(inode);
 832	dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
 833	data.Attributes = cpu_to_le32(dosattrs);
 834	cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
 
 
 835	tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
 836				 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
 837				 CREATE_NOT_FILE, ACL_NO_MODE, &in_iov,
 838				 &(int){SMB2_OP_SET_INFO}, 1,
 839				 cfile, NULL, NULL);
 840	if (tmprc == 0)
 841		cifs_i->cifsAttrs = dosattrs;
 842}
 843
 844int
 845smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 846	   struct cifs_sb_info *cifs_sb)
 847{
 
 
 848	drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
 849	return smb2_compound_op(xid, tcon, cifs_sb, name,
 850				DELETE, FILE_OPEN, CREATE_NOT_FILE,
 851				ACL_NO_MODE, NULL,
 
 852				&(int){SMB2_OP_RMDIR}, 1,
 853				NULL, NULL, NULL);
 854}
 855
 856int
 857smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 858	    struct cifs_sb_info *cifs_sb)
 859{
 860	return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
 861				CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
 862				ACL_NO_MODE, NULL,
 863				&(int){SMB2_OP_DELETE}, 1,
 864				NULL, NULL, NULL);
 
 
 
 
 
 
 
 
 
 
 
 865}
 866
 867static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
 868			      const char *from_name, const char *to_name,
 869			      struct cifs_sb_info *cifs_sb,
 870			      __u32 create_options, __u32 access,
 871			      int command, struct cifsFileInfo *cfile)
 
 872{
 
 873	struct kvec in_iov;
 874	__le16 *smb2_to_name = NULL;
 875	int rc;
 876
 877	smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
 878	if (smb2_to_name == NULL) {
 879		rc = -ENOMEM;
 880		goto smb2_rename_path;
 881	}
 882	in_iov.iov_base = smb2_to_name;
 883	in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
 884	rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
 885			      FILE_OPEN, create_options, ACL_NO_MODE,
 886			      &in_iov, &command, 1, cfile, NULL, NULL);
 
 
 887smb2_rename_path:
 888	kfree(smb2_to_name);
 889	return rc;
 890}
 891
 892int smb2_rename_path(const unsigned int xid,
 893		     struct cifs_tcon *tcon,
 894		     struct dentry *source_dentry,
 895		     const char *from_name, const char *to_name,
 896		     struct cifs_sb_info *cifs_sb)
 897{
 898	struct cifsFileInfo *cfile;
 899	__u32 co = file_create_options(source_dentry);
 900
 901	drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
 902	cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
 903
 904	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
 905				  co, DELETE, SMB2_OP_RENAME, cfile);
 
 
 
 
 
 
 
 
 906}
 907
 908int smb2_create_hardlink(const unsigned int xid,
 909			 struct cifs_tcon *tcon,
 910			 struct dentry *source_dentry,
 911			 const char *from_name, const char *to_name,
 912			 struct cifs_sb_info *cifs_sb)
 913{
 914	__u32 co = file_create_options(source_dentry);
 915
 916	return smb2_set_path_attr(xid, tcon, from_name, to_name,
 917				  cifs_sb, co, FILE_READ_ATTRIBUTES,
 918				  SMB2_OP_HARDLINK, NULL);
 919}
 920
 921int
 922smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
 923		   const char *full_path, __u64 size,
 924		   struct cifs_sb_info *cifs_sb, bool set_alloc)
 
 925{
 
 926	struct cifsFileInfo *cfile;
 927	struct kvec in_iov;
 928	__le64 eof = cpu_to_le64(size);
 
 929
 930	in_iov.iov_base = &eof;
 931	in_iov.iov_len = sizeof(eof);
 932	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
 933	return smb2_compound_op(xid, tcon, cifs_sb, full_path,
 934				FILE_WRITE_DATA, FILE_OPEN,
 935				0, ACL_NO_MODE, &in_iov,
 936				&(int){SMB2_OP_SET_EOF}, 1,
 937				cfile, NULL, NULL);
 
 
 
 
 
 
 
 
 
 
 
 938}
 939
 940int
 941smb2_set_file_info(struct inode *inode, const char *full_path,
 942		   FILE_BASIC_INFO *buf, const unsigned int xid)
 943{
 
 944	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 945	struct tcon_link *tlink;
 946	struct cifs_tcon *tcon;
 947	struct cifsFileInfo *cfile;
 948	struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
 949	int rc;
 950
 951	if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
 952	    (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
 953	    (buf->Attributes == 0))
 954		return 0; /* would be a no op, no sense sending this */
 955
 956	tlink = cifs_sb_tlink(cifs_sb);
 957	if (IS_ERR(tlink))
 958		return PTR_ERR(tlink);
 959	tcon = tlink_tcon(tlink);
 960
 961	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
 962	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
 963			      FILE_WRITE_ATTRIBUTES, FILE_OPEN,
 964			      0, ACL_NO_MODE, &in_iov,
 
 965			      &(int){SMB2_OP_SET_INFO}, 1,
 966			      cfile, NULL, NULL);
 967	cifs_put_tlink(tlink);
 968	return rc;
 969}
 970
 971struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
 972				     struct super_block *sb,
 973				     const unsigned int xid,
 974				     struct cifs_tcon *tcon,
 975				     const char *full_path,
 976				     struct kvec *iov)
 
 
 977{
 
 978	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
 979	struct cifsFileInfo *cfile;
 980	struct inode *new = NULL;
 
 
 981	struct kvec in_iov[2];
 982	int cmds[2];
 983	int da, co, cd;
 984	int rc;
 
 
 
 
 
 
 
 
 
 
 
 985
 986	da = SYNCHRONIZE | DELETE |
 987		FILE_READ_ATTRIBUTES |
 988		FILE_WRITE_ATTRIBUTES;
 989	co = CREATE_NOT_DIR | OPEN_REPARSE_POINT;
 990	cd = FILE_CREATE;
 991	cmds[0] = SMB2_OP_SET_REPARSE;
 992	in_iov[0] = *iov;
 993	in_iov[1].iov_base = data;
 994	in_iov[1].iov_len = sizeof(*data);
 995
 996	if (tcon->posix_extensions) {
 997		cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
 998		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
 999		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1000				      da, cd, co, ACL_NO_MODE, in_iov,
1001				      cmds, 2, cfile, NULL, NULL);
1002		if (!rc) {
1003			rc = smb311_posix_get_inode_info(&new, full_path,
1004							 data, sb, xid);
1005		}
1006	} else {
1007		cmds[1] = SMB2_OP_QUERY_INFO;
1008		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1009		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1010				      da, cd, co, ACL_NO_MODE, in_iov,
1011				      cmds, 2, cfile, NULL, NULL);
1012		if (!rc) {
1013			rc = cifs_get_inode_info(&new, full_path,
1014						 data, sb, xid, NULL);
1015		}
1016	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1017	return rc ? ERR_PTR(rc) : new;
1018}
1019
1020int smb2_query_reparse_point(const unsigned int xid,
1021			     struct cifs_tcon *tcon,
1022			     struct cifs_sb_info *cifs_sb,
1023			     const char *full_path,
1024			     u32 *tag, struct kvec *rsp,
1025			     int *rsp_buftype)
1026{
 
1027	struct cifs_open_info_data data = {};
1028	struct cifsFileInfo *cfile;
1029	struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1030	int rc;
1031
1032	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1033
1034	cifs_get_readable_path(tcon, full_path, &cfile);
1035	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1036			      FILE_READ_ATTRIBUTES, FILE_OPEN,
1037			      OPEN_REPARSE_POINT, ACL_NO_MODE, &in_iov,
 
 
1038			      &(int){SMB2_OP_GET_REPARSE}, 1,
1039			      cfile, NULL, NULL);
1040	if (rc)
1041		goto out;
1042
1043	*tag = data.reparse.tag;
1044	*rsp = data.reparse.io.iov;
1045	*rsp_buftype = data.reparse.io.buftype;
1046	memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1047	data.reparse.io.buftype = CIFS_NO_BUFFER;
1048out:
1049	cifs_free_open_info(&data);
1050	return rc;
1051}