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