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