xref: /linux/fs/smb/client/smb2inode.c (revision 08df80a3c51674ab73ae770885a383ca553fbbbf)
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 
29 static 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 
47 static 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 /*
60  * note: If cfile is passed, the reference to it is dropped here.
61  * So make sure that you do not reuse cfile after return from this func.
62  *
63  * If passing @out_iov and @out_buftype, ensure to make them both large enough
64  * (>= 3) to hold all compounded responses.  Caller is also responsible for
65  * freeing them up with free_rsp_buf().
66  */
67 static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
68 			    struct cifs_sb_info *cifs_sb, const char *full_path,
69 			    __u32 desired_access, __u32 create_disposition,
70 			    __u32 create_options, umode_t mode, struct kvec *in_iov,
71 			    int *cmds, int num_cmds, struct cifsFileInfo *cfile,
72 			    __u8 **extbuf, size_t *extbuflen,
73 			    struct kvec *out_iov, int *out_buftype)
74 {
75 
76 	struct reparse_data_buffer *rbuf;
77 	struct smb2_compound_vars *vars = NULL;
78 	struct kvec *rsp_iov, *iov;
79 	struct smb_rqst *rqst;
80 	int rc;
81 	__le16 *utf16_path = NULL;
82 	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
83 	struct cifs_fid fid;
84 	struct cifs_ses *ses = tcon->ses;
85 	struct TCP_Server_Info *server;
86 	int num_rqst = 0, i;
87 	int resp_buftype[MAX_COMPOUND];
88 	struct smb2_query_info_rsp *qi_rsp = NULL;
89 	struct cifs_open_info_data *idata;
90 	int flags = 0;
91 	__u8 delete_pending[8] = {1, 0, 0, 0, 0, 0, 0, 0};
92 	unsigned int size[2];
93 	void *data[2];
94 	int len;
95 
96 	vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
97 	if (vars == NULL)
98 		return -ENOMEM;
99 	rqst = &vars->rqst[0];
100 	rsp_iov = &vars->rsp_iov[0];
101 
102 	server = cifs_pick_channel(ses);
103 
104 	if (smb3_encryption_required(tcon))
105 		flags |= CIFS_TRANSFORM_REQ;
106 
107 	for (i = 0; i < ARRAY_SIZE(resp_buftype); i++)
108 		resp_buftype[i] = CIFS_NO_BUFFER;
109 
110 	/* We already have a handle so we can skip the open */
111 	if (cfile)
112 		goto after_open;
113 
114 	/* Open */
115 	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
116 	if (!utf16_path) {
117 		rc = -ENOMEM;
118 		goto finished;
119 	}
120 
121 	vars->oparms = (struct cifs_open_parms) {
122 		.tcon = tcon,
123 		.path = full_path,
124 		.desired_access = desired_access,
125 		.disposition = create_disposition,
126 		.create_options = cifs_create_options(cifs_sb, create_options),
127 		.fid = &fid,
128 		.mode = mode,
129 		.cifs_sb = cifs_sb,
130 	};
131 
132 	rqst[num_rqst].rq_iov = &vars->open_iov[0];
133 	rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
134 	rc = SMB2_open_init(tcon, server,
135 			    &rqst[num_rqst], &oplock, &vars->oparms,
136 			    utf16_path);
137 	kfree(utf16_path);
138 	if (rc)
139 		goto finished;
140 
141 	smb2_set_next_command(tcon, &rqst[num_rqst]);
142  after_open:
143 	num_rqst++;
144 	rc = 0;
145 
146 	for (i = 0; i < num_cmds; i++) {
147 		/* Operation */
148 		switch (cmds[i]) {
149 		case SMB2_OP_QUERY_INFO:
150 			rqst[num_rqst].rq_iov = &vars->qi_iov;
151 			rqst[num_rqst].rq_nvec = 1;
152 
153 			if (cfile) {
154 				rc = SMB2_query_info_init(tcon, server,
155 							  &rqst[num_rqst],
156 							  cfile->fid.persistent_fid,
157 							  cfile->fid.volatile_fid,
158 							  FILE_ALL_INFORMATION,
159 							  SMB2_O_INFO_FILE, 0,
160 							  sizeof(struct smb2_file_all_info) +
161 							  PATH_MAX * 2, 0, NULL);
162 			} else {
163 				rc = SMB2_query_info_init(tcon, server,
164 							  &rqst[num_rqst],
165 							  COMPOUND_FID,
166 							  COMPOUND_FID,
167 							  FILE_ALL_INFORMATION,
168 							  SMB2_O_INFO_FILE, 0,
169 							  sizeof(struct smb2_file_all_info) +
170 							  PATH_MAX * 2, 0, NULL);
171 				if (!rc) {
172 					smb2_set_next_command(tcon, &rqst[num_rqst]);
173 					smb2_set_related(&rqst[num_rqst]);
174 				}
175 			}
176 
177 			if (rc)
178 				goto finished;
179 			num_rqst++;
180 			trace_smb3_query_info_compound_enter(xid, ses->Suid,
181 							     tcon->tid, full_path);
182 			break;
183 		case SMB2_OP_POSIX_QUERY_INFO:
184 			rqst[num_rqst].rq_iov = &vars->qi_iov;
185 			rqst[num_rqst].rq_nvec = 1;
186 
187 			if (cfile) {
188 				/* TBD: fix following to allow for longer SIDs */
189 				rc = SMB2_query_info_init(tcon, server,
190 							  &rqst[num_rqst],
191 							  cfile->fid.persistent_fid,
192 							  cfile->fid.volatile_fid,
193 							  SMB_FIND_FILE_POSIX_INFO,
194 							  SMB2_O_INFO_FILE, 0,
195 							  sizeof(struct smb311_posix_qinfo *) +
196 							  (PATH_MAX * 2) +
197 							  (sizeof(struct cifs_sid) * 2), 0, NULL);
198 			} else {
199 				rc = SMB2_query_info_init(tcon, server,
200 							  &rqst[num_rqst],
201 							  COMPOUND_FID,
202 							  COMPOUND_FID,
203 							  SMB_FIND_FILE_POSIX_INFO,
204 							  SMB2_O_INFO_FILE, 0,
205 							  sizeof(struct smb311_posix_qinfo *) +
206 							  (PATH_MAX * 2) +
207 							  (sizeof(struct cifs_sid) * 2), 0, NULL);
208 				if (!rc) {
209 					smb2_set_next_command(tcon, &rqst[num_rqst]);
210 					smb2_set_related(&rqst[num_rqst]);
211 				}
212 			}
213 
214 			if (rc)
215 				goto finished;
216 			num_rqst++;
217 			trace_smb3_posix_query_info_compound_enter(xid, ses->Suid,
218 								   tcon->tid, full_path);
219 			break;
220 		case SMB2_OP_DELETE:
221 			trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
222 			break;
223 		case SMB2_OP_MKDIR:
224 			/*
225 			 * Directories are created through parameters in the
226 			 * SMB2_open() call.
227 			 */
228 			trace_smb3_mkdir_enter(xid, ses->Suid, tcon->tid, full_path);
229 			break;
230 		case SMB2_OP_RMDIR:
231 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
232 			rqst[num_rqst].rq_nvec = 1;
233 
234 			size[0] = 1; /* sizeof __u8 See MS-FSCC section 2.4.11 */
235 			data[0] = &delete_pending[0];
236 
237 			rc = SMB2_set_info_init(tcon, server,
238 						&rqst[num_rqst], COMPOUND_FID,
239 						COMPOUND_FID, current->tgid,
240 						FILE_DISPOSITION_INFORMATION,
241 						SMB2_O_INFO_FILE, 0, data, size);
242 			if (rc)
243 				goto finished;
244 			smb2_set_next_command(tcon, &rqst[num_rqst]);
245 			smb2_set_related(&rqst[num_rqst++]);
246 			trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
247 			break;
248 		case SMB2_OP_SET_EOF:
249 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
250 			rqst[num_rqst].rq_nvec = 1;
251 
252 			size[0] = in_iov[i].iov_len;
253 			data[0] = in_iov[i].iov_base;
254 
255 			if (cfile) {
256 				rc = SMB2_set_info_init(tcon, server,
257 							&rqst[num_rqst],
258 							cfile->fid.persistent_fid,
259 							cfile->fid.volatile_fid,
260 							current->tgid,
261 							FILE_END_OF_FILE_INFORMATION,
262 							SMB2_O_INFO_FILE, 0,
263 							data, size);
264 			} else {
265 				rc = SMB2_set_info_init(tcon, server,
266 							&rqst[num_rqst],
267 							COMPOUND_FID,
268 							COMPOUND_FID,
269 							current->tgid,
270 							FILE_END_OF_FILE_INFORMATION,
271 							SMB2_O_INFO_FILE, 0,
272 							data, size);
273 				if (!rc) {
274 					smb2_set_next_command(tcon, &rqst[num_rqst]);
275 					smb2_set_related(&rqst[num_rqst]);
276 				}
277 			}
278 			if (rc)
279 				goto finished;
280 			num_rqst++;
281 			trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
282 			break;
283 		case SMB2_OP_SET_INFO:
284 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
285 			rqst[num_rqst].rq_nvec = 1;
286 
287 			size[0] = in_iov[i].iov_len;
288 			data[0] = in_iov[i].iov_base;
289 
290 			if (cfile) {
291 				rc = SMB2_set_info_init(tcon, server,
292 							&rqst[num_rqst],
293 							cfile->fid.persistent_fid,
294 							cfile->fid.volatile_fid, current->tgid,
295 							FILE_BASIC_INFORMATION,
296 							SMB2_O_INFO_FILE, 0, data, size);
297 			} else {
298 				rc = SMB2_set_info_init(tcon, server,
299 							&rqst[num_rqst],
300 							COMPOUND_FID,
301 							COMPOUND_FID, current->tgid,
302 							FILE_BASIC_INFORMATION,
303 							SMB2_O_INFO_FILE, 0, data, size);
304 				if (!rc) {
305 					smb2_set_next_command(tcon, &rqst[num_rqst]);
306 					smb2_set_related(&rqst[num_rqst]);
307 				}
308 			}
309 
310 			if (rc)
311 				goto finished;
312 			num_rqst++;
313 			trace_smb3_set_info_compound_enter(xid, ses->Suid,
314 							   tcon->tid, full_path);
315 			break;
316 		case SMB2_OP_RENAME:
317 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
318 			rqst[num_rqst].rq_nvec = 2;
319 
320 			len = in_iov[i].iov_len;
321 
322 			vars->rename_info.ReplaceIfExists = 1;
323 			vars->rename_info.RootDirectory = 0;
324 			vars->rename_info.FileNameLength = cpu_to_le32(len);
325 
326 			size[0] = sizeof(struct smb2_file_rename_info);
327 			data[0] = &vars->rename_info;
328 
329 			size[1] = len + 2 /* null */;
330 			data[1] = in_iov[i].iov_base;
331 
332 			if (cfile) {
333 				rc = SMB2_set_info_init(tcon, server,
334 							&rqst[num_rqst],
335 							cfile->fid.persistent_fid,
336 							cfile->fid.volatile_fid,
337 							current->tgid, FILE_RENAME_INFORMATION,
338 							SMB2_O_INFO_FILE, 0, data, size);
339 			} else {
340 				rc = SMB2_set_info_init(tcon, server,
341 							&rqst[num_rqst],
342 							COMPOUND_FID, COMPOUND_FID,
343 							current->tgid, FILE_RENAME_INFORMATION,
344 							SMB2_O_INFO_FILE, 0, data, size);
345 				if (!rc) {
346 					smb2_set_next_command(tcon, &rqst[num_rqst]);
347 					smb2_set_related(&rqst[num_rqst]);
348 				}
349 			}
350 			if (rc)
351 				goto finished;
352 			num_rqst++;
353 			trace_smb3_rename_enter(xid, ses->Suid, tcon->tid, full_path);
354 			break;
355 		case SMB2_OP_HARDLINK:
356 			rqst[num_rqst].rq_iov = &vars->si_iov[0];
357 			rqst[num_rqst].rq_nvec = 2;
358 
359 			len = in_iov[i].iov_len;
360 
361 			vars->link_info.ReplaceIfExists = 0;
362 			vars->link_info.RootDirectory = 0;
363 			vars->link_info.FileNameLength = cpu_to_le32(len);
364 
365 			size[0] = sizeof(struct smb2_file_link_info);
366 			data[0] = &vars->link_info;
367 
368 			size[1] = len + 2 /* null */;
369 			data[1] = in_iov[i].iov_base;
370 
371 			rc = SMB2_set_info_init(tcon, server,
372 						&rqst[num_rqst], COMPOUND_FID,
373 						COMPOUND_FID, current->tgid,
374 						FILE_LINK_INFORMATION,
375 						SMB2_O_INFO_FILE, 0, data, size);
376 			if (rc)
377 				goto finished;
378 			smb2_set_next_command(tcon, &rqst[num_rqst]);
379 			smb2_set_related(&rqst[num_rqst++]);
380 			trace_smb3_hardlink_enter(xid, ses->Suid, tcon->tid, full_path);
381 			break;
382 		case SMB2_OP_SET_REPARSE:
383 			rqst[num_rqst].rq_iov = vars->io_iov;
384 			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
385 
386 			rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
387 					     COMPOUND_FID, COMPOUND_FID,
388 					     FSCTL_SET_REPARSE_POINT,
389 					     in_iov[i].iov_base,
390 					     in_iov[i].iov_len, 0);
391 			if (rc)
392 				goto finished;
393 			smb2_set_next_command(tcon, &rqst[num_rqst]);
394 			smb2_set_related(&rqst[num_rqst++]);
395 			trace_smb3_set_reparse_compound_enter(xid, ses->Suid,
396 							      tcon->tid, full_path);
397 			break;
398 		case SMB2_OP_GET_REPARSE:
399 			rqst[num_rqst].rq_iov = vars->io_iov;
400 			rqst[num_rqst].rq_nvec = ARRAY_SIZE(vars->io_iov);
401 
402 			rc = SMB2_ioctl_init(tcon, server, &rqst[num_rqst],
403 					     COMPOUND_FID, COMPOUND_FID,
404 					     FSCTL_GET_REPARSE_POINT,
405 					     NULL, 0, CIFSMaxBufSize);
406 			if (rc)
407 				goto finished;
408 			smb2_set_next_command(tcon, &rqst[num_rqst]);
409 			smb2_set_related(&rqst[num_rqst++]);
410 			trace_smb3_get_reparse_compound_enter(xid, ses->Suid,
411 							      tcon->tid, full_path);
412 			break;
413 		default:
414 			cifs_dbg(VFS, "Invalid command\n");
415 			rc = -EINVAL;
416 		}
417 	}
418 	if (rc)
419 		goto finished;
420 
421 	/* We already have a handle so we can skip the close */
422 	if (cfile)
423 		goto after_close;
424 	/* Close */
425 	flags |= CIFS_CP_CREATE_CLOSE_OP;
426 	rqst[num_rqst].rq_iov = &vars->close_iov;
427 	rqst[num_rqst].rq_nvec = 1;
428 	rc = SMB2_close_init(tcon, server,
429 			     &rqst[num_rqst], COMPOUND_FID,
430 			     COMPOUND_FID, false);
431 	smb2_set_related(&rqst[num_rqst]);
432 	if (rc)
433 		goto finished;
434  after_close:
435 	num_rqst++;
436 
437 	if (cfile) {
438 		rc = compound_send_recv(xid, ses, server,
439 					flags, num_rqst - 2,
440 					&rqst[1], &resp_buftype[1],
441 					&rsp_iov[1]);
442 	} else
443 		rc = compound_send_recv(xid, ses, server,
444 					flags, num_rqst,
445 					rqst, resp_buftype,
446 					rsp_iov);
447 
448 finished:
449 	num_rqst = 0;
450 	SMB2_open_free(&rqst[num_rqst++]);
451 	if (rc == -EREMCHG) {
452 		pr_warn_once("server share %s deleted\n", tcon->tree_name);
453 		tcon->need_reconnect = true;
454 	}
455 
456 	for (i = 0; i < num_cmds; i++) {
457 		switch (cmds[i]) {
458 		case SMB2_OP_QUERY_INFO:
459 			idata = in_iov[i].iov_base;
460 			if (rc == 0 && cfile && cfile->symlink_target) {
461 				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
462 				if (!idata->symlink_target)
463 					rc = -ENOMEM;
464 			}
465 			if (rc == 0) {
466 				qi_rsp = (struct smb2_query_info_rsp *)
467 					rsp_iov[i + 1].iov_base;
468 				rc = smb2_validate_and_copy_iov(
469 					le16_to_cpu(qi_rsp->OutputBufferOffset),
470 					le32_to_cpu(qi_rsp->OutputBufferLength),
471 					&rsp_iov[i + 1], sizeof(idata->fi), (char *)&idata->fi);
472 			}
473 			SMB2_query_info_free(&rqst[num_rqst++]);
474 			if (rc)
475 				trace_smb3_query_info_compound_err(xid,  ses->Suid,
476 								   tcon->tid, rc);
477 			else
478 				trace_smb3_query_info_compound_done(xid, ses->Suid,
479 								    tcon->tid);
480 			break;
481 		case SMB2_OP_POSIX_QUERY_INFO:
482 			idata = in_iov[i].iov_base;
483 			if (rc == 0 && cfile && cfile->symlink_target) {
484 				idata->symlink_target = kstrdup(cfile->symlink_target, GFP_KERNEL);
485 				if (!idata->symlink_target)
486 					rc = -ENOMEM;
487 			}
488 			if (rc == 0) {
489 				qi_rsp = (struct smb2_query_info_rsp *)
490 					rsp_iov[i + 1].iov_base;
491 				rc = smb2_validate_and_copy_iov(
492 					le16_to_cpu(qi_rsp->OutputBufferOffset),
493 					le32_to_cpu(qi_rsp->OutputBufferLength),
494 					&rsp_iov[i + 1], sizeof(idata->posix_fi) /* add SIDs */,
495 					(char *)&idata->posix_fi);
496 			}
497 			if (rc == 0) {
498 				unsigned int length = le32_to_cpu(qi_rsp->OutputBufferLength);
499 
500 				if (length > sizeof(idata->posix_fi)) {
501 					char *base = (char *)rsp_iov[i + 1].iov_base +
502 						le16_to_cpu(qi_rsp->OutputBufferOffset) +
503 						sizeof(idata->posix_fi);
504 					*extbuflen = length - sizeof(idata->posix_fi);
505 					*extbuf = kmemdup(base, *extbuflen, GFP_KERNEL);
506 					if (!*extbuf)
507 						rc = -ENOMEM;
508 				} else {
509 					rc = -EINVAL;
510 				}
511 			}
512 			SMB2_query_info_free(&rqst[num_rqst++]);
513 			if (rc)
514 				trace_smb3_posix_query_info_compound_err(xid,  ses->Suid,
515 									 tcon->tid, rc);
516 			else
517 				trace_smb3_posix_query_info_compound_done(xid, ses->Suid,
518 									  tcon->tid);
519 			break;
520 		case SMB2_OP_DELETE:
521 			if (rc)
522 				trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
523 			else
524 				trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
525 			break;
526 		case SMB2_OP_MKDIR:
527 			if (rc)
528 				trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
529 			else
530 				trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
531 			break;
532 		case SMB2_OP_HARDLINK:
533 			if (rc)
534 				trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);
535 			else
536 				trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
537 			SMB2_set_info_free(&rqst[num_rqst++]);
538 			break;
539 		case SMB2_OP_RENAME:
540 			if (rc)
541 				trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);
542 			else
543 				trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
544 			SMB2_set_info_free(&rqst[num_rqst++]);
545 			break;
546 		case SMB2_OP_RMDIR:
547 			if (rc)
548 				trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);
549 			else
550 				trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
551 			SMB2_set_info_free(&rqst[num_rqst++]);
552 			break;
553 		case SMB2_OP_SET_EOF:
554 			if (rc)
555 				trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
556 			else
557 				trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
558 			SMB2_set_info_free(&rqst[num_rqst++]);
559 			break;
560 		case SMB2_OP_SET_INFO:
561 			if (rc)
562 				trace_smb3_set_info_compound_err(xid,  ses->Suid,
563 								 tcon->tid, rc);
564 			else
565 				trace_smb3_set_info_compound_done(xid, ses->Suid,
566 								  tcon->tid);
567 			SMB2_set_info_free(&rqst[num_rqst++]);
568 			break;
569 		case SMB2_OP_SET_REPARSE:
570 			if (rc) {
571 				trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
572 								    tcon->tid, rc);
573 			} else {
574 				trace_smb3_set_reparse_compound_done(xid, ses->Suid,
575 								     tcon->tid);
576 			}
577 			SMB2_ioctl_free(&rqst[num_rqst++]);
578 			break;
579 		case SMB2_OP_GET_REPARSE:
580 			if (!rc) {
581 				iov = &rsp_iov[i + 1];
582 				idata = in_iov[i].iov_base;
583 				idata->reparse.io.iov = *iov;
584 				idata->reparse.io.buftype = resp_buftype[i + 1];
585 				rbuf = reparse_buf_ptr(iov);
586 				if (IS_ERR(rbuf)) {
587 					rc = PTR_ERR(rbuf);
588 					trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
589 									    tcon->tid, rc);
590 				} else {
591 					idata->reparse.tag = le32_to_cpu(rbuf->ReparseTag);
592 					trace_smb3_set_reparse_compound_done(xid, ses->Suid,
593 									     tcon->tid);
594 				}
595 				memset(iov, 0, sizeof(*iov));
596 				resp_buftype[i + 1] = CIFS_NO_BUFFER;
597 			} else {
598 				trace_smb3_set_reparse_compound_err(xid,  ses->Suid,
599 								    tcon->tid, rc);
600 			}
601 			SMB2_ioctl_free(&rqst[num_rqst++]);
602 			break;
603 		}
604 	}
605 	SMB2_close_free(&rqst[num_rqst]);
606 
607 	if (cfile)
608 		cifsFileInfo_put(cfile);
609 
610 	num_cmds += 2;
611 	if (out_iov && out_buftype) {
612 		memcpy(out_iov, rsp_iov, num_cmds * sizeof(*out_iov));
613 		memcpy(out_buftype, resp_buftype,
614 		       num_cmds * sizeof(*out_buftype));
615 	} else {
616 		for (i = 0; i < num_cmds; i++)
617 			free_rsp_buf(resp_buftype[i], rsp_iov[i].iov_base);
618 	}
619 	kfree(vars);
620 	return rc;
621 }
622 
623 static int parse_create_response(struct cifs_open_info_data *data,
624 				 struct cifs_sb_info *cifs_sb,
625 				 const struct kvec *iov)
626 {
627 	struct smb2_create_rsp *rsp = iov->iov_base;
628 	bool reparse_point = false;
629 	u32 tag = 0;
630 	int rc = 0;
631 
632 	switch (rsp->hdr.Status) {
633 	case STATUS_IO_REPARSE_TAG_NOT_HANDLED:
634 		reparse_point = true;
635 		break;
636 	case STATUS_STOPPED_ON_SYMLINK:
637 		rc = smb2_parse_symlink_response(cifs_sb, iov,
638 						 &data->symlink_target);
639 		if (rc)
640 			return rc;
641 		tag = IO_REPARSE_TAG_SYMLINK;
642 		reparse_point = true;
643 		break;
644 	case STATUS_SUCCESS:
645 		reparse_point = !!(rsp->Flags & SMB2_CREATE_FLAG_REPARSEPOINT);
646 		break;
647 	}
648 	data->reparse_point = reparse_point;
649 	data->reparse.tag = tag;
650 	return rc;
651 }
652 
653 int smb2_query_path_info(const unsigned int xid,
654 			 struct cifs_tcon *tcon,
655 			 struct cifs_sb_info *cifs_sb,
656 			 const char *full_path,
657 			 struct cifs_open_info_data *data)
658 {
659 	__u32 create_options = 0;
660 	struct cifsFileInfo *cfile;
661 	struct cached_fid *cfid = NULL;
662 	struct smb2_hdr *hdr;
663 	struct kvec in_iov[2], out_iov[3] = {};
664 	int out_buftype[3] = {};
665 	int cmds[2] = { SMB2_OP_QUERY_INFO,  };
666 	bool islink;
667 	int i, num_cmds;
668 	int rc, rc2;
669 
670 	data->adjust_tz = false;
671 	data->reparse_point = false;
672 
673 	if (strcmp(full_path, ""))
674 		rc = -ENOENT;
675 	else
676 		rc = open_cached_dir(xid, tcon, full_path, cifs_sb, false, &cfid);
677 	/* If it is a root and its handle is cached then use it */
678 	if (!rc) {
679 		if (cfid->file_all_info_is_valid) {
680 			memcpy(&data->fi, &cfid->file_all_info, sizeof(data->fi));
681 		} else {
682 			rc = SMB2_query_info(xid, tcon, cfid->fid.persistent_fid,
683 					     cfid->fid.volatile_fid, &data->fi);
684 		}
685 		close_cached_dir(cfid);
686 		return rc;
687 	}
688 
689 	in_iov[0].iov_base = data;
690 	in_iov[0].iov_len = sizeof(*data);
691 	in_iov[1] = in_iov[0];
692 
693 	cifs_get_readable_path(tcon, full_path, &cfile);
694 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
695 			      FILE_READ_ATTRIBUTES, FILE_OPEN,
696 			      create_options, ACL_NO_MODE,
697 			      in_iov, cmds, 1, cfile,
698 			      NULL, NULL, out_iov, out_buftype);
699 	hdr = out_iov[0].iov_base;
700 	/*
701 	 * If first iov is unset, then SMB session was dropped or we've got a
702 	 * cached open file (@cfile).
703 	 */
704 	if (!hdr || out_buftype[0] == CIFS_NO_BUFFER)
705 		goto out;
706 
707 	switch (rc) {
708 	case 0:
709 	case -EOPNOTSUPP:
710 		rc = parse_create_response(data, cifs_sb, &out_iov[0]);
711 		if (rc || !data->reparse_point)
712 			goto out;
713 
714 		if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) {
715 			/* symlink already parsed in create response */
716 			num_cmds = 1;
717 		} else {
718 			cmds[1] = SMB2_OP_GET_REPARSE;
719 			num_cmds = 2;
720 		}
721 		create_options |= OPEN_REPARSE_POINT;
722 		cifs_get_readable_path(tcon, full_path, &cfile);
723 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
724 				      FILE_READ_ATTRIBUTES, FILE_OPEN,
725 				      create_options, ACL_NO_MODE, in_iov, cmds,
726 				      num_cmds, cfile, NULL, NULL, NULL, NULL);
727 		break;
728 	case -EREMOTE:
729 		break;
730 	default:
731 		if (hdr->Status != STATUS_OBJECT_NAME_INVALID)
732 			break;
733 		rc2 = cifs_inval_name_dfs_link_error(xid, tcon, cifs_sb,
734 						     full_path, &islink);
735 		if (rc2) {
736 			rc = rc2;
737 			goto out;
738 		}
739 		if (islink)
740 			rc = -EREMOTE;
741 	}
742 
743 out:
744 	for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
745 		free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
746 	return rc;
747 }
748 
749 int smb311_posix_query_path_info(const unsigned int xid,
750 				 struct cifs_tcon *tcon,
751 				 struct cifs_sb_info *cifs_sb,
752 				 const char *full_path,
753 				 struct cifs_open_info_data *data,
754 				 struct cifs_sid *owner,
755 				 struct cifs_sid *group)
756 {
757 	int rc;
758 	__u32 create_options = 0;
759 	struct cifsFileInfo *cfile;
760 	struct kvec in_iov[2], out_iov[3] = {};
761 	int out_buftype[3] = {};
762 	__u8 *sidsbuf = NULL;
763 	__u8 *sidsbuf_end = NULL;
764 	size_t sidsbuflen = 0;
765 	size_t owner_len, group_len;
766 	int cmds[2] = { SMB2_OP_POSIX_QUERY_INFO,  };
767 	int i, num_cmds;
768 
769 	data->adjust_tz = false;
770 	data->reparse_point = false;
771 
772 	/*
773 	 * BB TODO: Add support for using the cached root handle.
774 	 * Create SMB2_query_posix_info worker function to do non-compounded query
775 	 * when we already have an open file handle for this. For now this is fast enough
776 	 * (always using the compounded version).
777 	 */
778 	in_iov[0].iov_base = data;
779 	in_iov[0].iov_len = sizeof(*data);
780 	in_iov[1] = in_iov[0];
781 
782 	cifs_get_readable_path(tcon, full_path, &cfile);
783 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
784 			      FILE_READ_ATTRIBUTES, FILE_OPEN,
785 			      create_options, ACL_NO_MODE, in_iov, cmds, 1,
786 			      cfile, &sidsbuf, &sidsbuflen, out_iov, out_buftype);
787 	/*
788 	 * If first iov is unset, then SMB session was dropped or we've got a
789 	 * cached open file (@cfile).
790 	 */
791 	if (!out_iov[0].iov_base || out_buftype[0] == CIFS_NO_BUFFER)
792 		goto out;
793 
794 	switch (rc) {
795 	case 0:
796 	case -EOPNOTSUPP:
797 		/* BB TODO: When support for special files added to Samba re-verify this path */
798 		rc = parse_create_response(data, cifs_sb, &out_iov[0]);
799 		if (rc || !data->reparse_point)
800 			goto out;
801 
802 		if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK) {
803 			/* symlink already parsed in create response */
804 			num_cmds = 1;
805 		} else {
806 			cmds[1] = SMB2_OP_GET_REPARSE;
807 			num_cmds = 2;
808 		}
809 		create_options |= OPEN_REPARSE_POINT;
810 		cifs_get_readable_path(tcon, full_path, &cfile);
811 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
812 				      FILE_READ_ATTRIBUTES, FILE_OPEN,
813 				      create_options, ACL_NO_MODE, in_iov, cmds,
814 				      num_cmds, cfile, &sidsbuf, &sidsbuflen, NULL, NULL);
815 		break;
816 	}
817 
818 out:
819 	if (rc == 0) {
820 		sidsbuf_end = sidsbuf + sidsbuflen;
821 
822 		owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
823 		if (owner_len == -1) {
824 			rc = -EINVAL;
825 			goto out;
826 		}
827 		memcpy(owner, sidsbuf, owner_len);
828 
829 		group_len = posix_info_sid_size(
830 			sidsbuf + owner_len, sidsbuf_end);
831 		if (group_len == -1) {
832 			rc = -EINVAL;
833 			goto out;
834 		}
835 		memcpy(group, sidsbuf + owner_len, group_len);
836 	}
837 
838 	kfree(sidsbuf);
839 	for (i = 0; i < ARRAY_SIZE(out_buftype); i++)
840 		free_rsp_buf(out_buftype[i], out_iov[i].iov_base);
841 	return rc;
842 }
843 
844 int
845 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
846 	   struct cifs_tcon *tcon, const char *name,
847 	   struct cifs_sb_info *cifs_sb)
848 {
849 	return smb2_compound_op(xid, tcon, cifs_sb, name,
850 				FILE_WRITE_ATTRIBUTES, FILE_CREATE,
851 				CREATE_NOT_FILE, mode, NULL,
852 				&(int){SMB2_OP_MKDIR}, 1,
853 				NULL, NULL, NULL, NULL, NULL);
854 }
855 
856 void
857 smb2_mkdir_setinfo(struct inode *inode, const char *name,
858 		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
859 		   const unsigned int xid)
860 {
861 	FILE_BASIC_INFO data = {};
862 	struct cifsInodeInfo *cifs_i;
863 	struct cifsFileInfo *cfile;
864 	struct kvec in_iov;
865 	u32 dosattrs;
866 	int tmprc;
867 
868 	in_iov.iov_base = &data;
869 	in_iov.iov_len = sizeof(data);
870 	cifs_i = CIFS_I(inode);
871 	dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
872 	data.Attributes = cpu_to_le32(dosattrs);
873 	cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
874 	tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
875 				 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
876 				 CREATE_NOT_FILE, ACL_NO_MODE, &in_iov,
877 				 &(int){SMB2_OP_SET_INFO}, 1,
878 				 cfile, NULL, NULL, NULL, NULL);
879 	if (tmprc == 0)
880 		cifs_i->cifsAttrs = dosattrs;
881 }
882 
883 int
884 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
885 	   struct cifs_sb_info *cifs_sb)
886 {
887 	drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
888 	return smb2_compound_op(xid, tcon, cifs_sb, name,
889 				DELETE, FILE_OPEN, CREATE_NOT_FILE,
890 				ACL_NO_MODE, NULL, &(int){SMB2_OP_RMDIR}, 1,
891 				NULL, NULL, NULL, NULL, NULL);
892 }
893 
894 int
895 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
896 	    struct cifs_sb_info *cifs_sb)
897 {
898 	return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
899 				CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
900 				ACL_NO_MODE, NULL, &(int){SMB2_OP_DELETE}, 1,
901 				NULL, NULL, NULL, NULL, NULL);
902 }
903 
904 static int smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
905 			      const char *from_name, const char *to_name,
906 			      struct cifs_sb_info *cifs_sb,
907 			      __u32 create_options, __u32 access,
908 			      int command, struct cifsFileInfo *cfile)
909 {
910 	struct kvec in_iov;
911 	__le16 *smb2_to_name = NULL;
912 	int rc;
913 
914 	smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
915 	if (smb2_to_name == NULL) {
916 		rc = -ENOMEM;
917 		goto smb2_rename_path;
918 	}
919 	in_iov.iov_base = smb2_to_name;
920 	in_iov.iov_len = 2 * UniStrnlen((wchar_t *)smb2_to_name, PATH_MAX);
921 	rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
922 			      FILE_OPEN, create_options, ACL_NO_MODE, &in_iov,
923 			      &command, 1, cfile, NULL, NULL, NULL, NULL);
924 smb2_rename_path:
925 	kfree(smb2_to_name);
926 	return rc;
927 }
928 
929 int smb2_rename_path(const unsigned int xid,
930 		     struct cifs_tcon *tcon,
931 		     struct dentry *source_dentry,
932 		     const char *from_name, const char *to_name,
933 		     struct cifs_sb_info *cifs_sb)
934 {
935 	struct cifsFileInfo *cfile;
936 	__u32 co = file_create_options(source_dentry);
937 
938 	drop_cached_dir_by_name(xid, tcon, from_name, cifs_sb);
939 	cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
940 
941 	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
942 				  co, DELETE, SMB2_OP_RENAME, cfile);
943 }
944 
945 int smb2_create_hardlink(const unsigned int xid,
946 			 struct cifs_tcon *tcon,
947 			 struct dentry *source_dentry,
948 			 const char *from_name, const char *to_name,
949 			 struct cifs_sb_info *cifs_sb)
950 {
951 	__u32 co = file_create_options(source_dentry);
952 
953 	return smb2_set_path_attr(xid, tcon, from_name, to_name,
954 				  cifs_sb, co, FILE_READ_ATTRIBUTES,
955 				  SMB2_OP_HARDLINK, NULL);
956 }
957 
958 int
959 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
960 		   const char *full_path, __u64 size,
961 		   struct cifs_sb_info *cifs_sb, bool set_alloc)
962 {
963 	struct cifsFileInfo *cfile;
964 	struct kvec in_iov;
965 	__le64 eof = cpu_to_le64(size);
966 
967 	in_iov.iov_base = &eof;
968 	in_iov.iov_len = sizeof(eof);
969 	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
970 	return smb2_compound_op(xid, tcon, cifs_sb, full_path,
971 				FILE_WRITE_DATA, FILE_OPEN,
972 				0, ACL_NO_MODE, &in_iov,
973 				&(int){SMB2_OP_SET_EOF}, 1,
974 				cfile, NULL, NULL, NULL, NULL);
975 }
976 
977 int
978 smb2_set_file_info(struct inode *inode, const char *full_path,
979 		   FILE_BASIC_INFO *buf, const unsigned int xid)
980 {
981 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
982 	struct tcon_link *tlink;
983 	struct cifs_tcon *tcon;
984 	struct cifsFileInfo *cfile;
985 	struct kvec in_iov = { .iov_base = buf, .iov_len = sizeof(*buf), };
986 	int rc;
987 
988 	if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
989 	    (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
990 	    (buf->Attributes == 0))
991 		return 0; /* would be a no op, no sense sending this */
992 
993 	tlink = cifs_sb_tlink(cifs_sb);
994 	if (IS_ERR(tlink))
995 		return PTR_ERR(tlink);
996 	tcon = tlink_tcon(tlink);
997 
998 	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
999 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1000 			      FILE_WRITE_ATTRIBUTES, FILE_OPEN,
1001 			      0, ACL_NO_MODE, &in_iov,
1002 			      &(int){SMB2_OP_SET_INFO}, 1, cfile,
1003 			      NULL, NULL, NULL, NULL);
1004 	cifs_put_tlink(tlink);
1005 	return rc;
1006 }
1007 
1008 struct inode *smb2_get_reparse_inode(struct cifs_open_info_data *data,
1009 				     struct super_block *sb,
1010 				     const unsigned int xid,
1011 				     struct cifs_tcon *tcon,
1012 				     const char *full_path,
1013 				     struct kvec *iov)
1014 {
1015 	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
1016 	struct cifsFileInfo *cfile;
1017 	struct inode *new = NULL;
1018 	struct kvec in_iov[2];
1019 	int cmds[2];
1020 	int da, co, cd;
1021 	int rc;
1022 
1023 	da = SYNCHRONIZE | DELETE |
1024 		FILE_READ_ATTRIBUTES |
1025 		FILE_WRITE_ATTRIBUTES;
1026 	co = CREATE_NOT_DIR | OPEN_REPARSE_POINT;
1027 	cd = FILE_CREATE;
1028 	cmds[0] = SMB2_OP_SET_REPARSE;
1029 	in_iov[0] = *iov;
1030 	in_iov[1].iov_base = data;
1031 	in_iov[1].iov_len = sizeof(*data);
1032 
1033 	if (tcon->posix_extensions) {
1034 		cmds[1] = SMB2_OP_POSIX_QUERY_INFO;
1035 		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1036 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1037 				      da, cd, co, ACL_NO_MODE, in_iov,
1038 				      cmds, 2, cfile, NULL, NULL, NULL, NULL);
1039 		if (!rc) {
1040 			rc = smb311_posix_get_inode_info(&new, full_path,
1041 							 data, sb, xid);
1042 		}
1043 	} else {
1044 		cmds[1] = SMB2_OP_QUERY_INFO;
1045 		cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
1046 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1047 				      da, cd, co, ACL_NO_MODE, in_iov,
1048 				      cmds, 2, cfile, NULL, NULL, NULL, NULL);
1049 		if (!rc) {
1050 			rc = cifs_get_inode_info(&new, full_path,
1051 						 data, sb, xid, NULL);
1052 		}
1053 	}
1054 	return rc ? ERR_PTR(rc) : new;
1055 }
1056 
1057 int smb2_query_reparse_point(const unsigned int xid,
1058 			     struct cifs_tcon *tcon,
1059 			     struct cifs_sb_info *cifs_sb,
1060 			     const char *full_path,
1061 			     u32 *tag, struct kvec *rsp,
1062 			     int *rsp_buftype)
1063 {
1064 	struct cifs_open_info_data data = {};
1065 	struct cifsFileInfo *cfile;
1066 	struct kvec in_iov = { .iov_base = &data, .iov_len = sizeof(data), };
1067 	int rc;
1068 
1069 	cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
1070 
1071 	cifs_get_readable_path(tcon, full_path, &cfile);
1072 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
1073 			      FILE_READ_ATTRIBUTES, FILE_OPEN,
1074 			      OPEN_REPARSE_POINT, ACL_NO_MODE, &in_iov,
1075 			      &(int){SMB2_OP_GET_REPARSE}, 1, cfile,
1076 			      NULL, NULL, NULL, NULL);
1077 	if (rc)
1078 		goto out;
1079 
1080 	*tag = data.reparse.tag;
1081 	*rsp = data.reparse.io.iov;
1082 	*rsp_buftype = data.reparse.io.buftype;
1083 	memset(&data.reparse.io.iov, 0, sizeof(data.reparse.io.iov));
1084 	data.reparse.io.buftype = CIFS_NO_BUFFER;
1085 out:
1086 	cifs_free_open_info(&data);
1087 	return rc;
1088 }
1089