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 		rc = compound_send_recv(xid, ses, server,
366 					flags, num_rqst - 2,
367 					&rqst[1], &resp_buftype[1],
368 					&rsp_iov[1]);
369 	} else
370 		rc = compound_send_recv(xid, ses, server,
371 					flags, num_rqst,
372 					rqst, resp_buftype,
373 					rsp_iov);
374 
375  finished:
376 	if (cfile)
377 		cifsFileInfo_put(cfile);
378 
379 	SMB2_open_free(&rqst[0]);
380 	if (rc == -EREMCHG) {
381 		pr_warn_once("server share %s deleted\n", tcon->treeName);
382 		tcon->need_reconnect = true;
383 	}
384 
385 	switch (command) {
386 	case SMB2_OP_QUERY_INFO:
387 		if (rc == 0) {
388 			qi_rsp = (struct smb2_query_info_rsp *)
389 				rsp_iov[1].iov_base;
390 			rc = smb2_validate_and_copy_iov(
391 				le16_to_cpu(qi_rsp->OutputBufferOffset),
392 				le32_to_cpu(qi_rsp->OutputBufferLength),
393 				&rsp_iov[1], sizeof(struct smb2_file_all_info),
394 				ptr);
395 		}
396 		if (rqst[1].rq_iov)
397 			SMB2_query_info_free(&rqst[1]);
398 		if (rqst[2].rq_iov)
399 			SMB2_close_free(&rqst[2]);
400 		if (rc)
401 			trace_smb3_query_info_compound_err(xid,  ses->Suid,
402 						tcon->tid, rc);
403 		else
404 			trace_smb3_query_info_compound_done(xid, ses->Suid,
405 						tcon->tid);
406 		break;
407 	case SMB2_OP_POSIX_QUERY_INFO:
408 		if (rc == 0) {
409 			qi_rsp = (struct smb2_query_info_rsp *)
410 				rsp_iov[1].iov_base;
411 			rc = smb2_validate_and_copy_iov(
412 				le16_to_cpu(qi_rsp->OutputBufferOffset),
413 				le32_to_cpu(qi_rsp->OutputBufferLength),
414 				&rsp_iov[1], sizeof(struct smb311_posix_qinfo) /* add SIDs */, ptr);
415 		}
416 		if (rqst[1].rq_iov)
417 			SMB2_query_info_free(&rqst[1]);
418 		if (rqst[2].rq_iov)
419 			SMB2_close_free(&rqst[2]);
420 		if (rc)
421 			trace_smb3_posix_query_info_compound_err(xid,  ses->Suid, tcon->tid, rc);
422 		else
423 			trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid);
424 		break;
425 	case SMB2_OP_DELETE:
426 		if (rc)
427 			trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
428 		else
429 			trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
430 		if (rqst[1].rq_iov)
431 			SMB2_close_free(&rqst[1]);
432 		break;
433 	case SMB2_OP_MKDIR:
434 		if (rc)
435 			trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
436 		else
437 			trace_smb3_mkdir_done(xid, ses->Suid, tcon->tid);
438 		if (rqst[1].rq_iov)
439 			SMB2_close_free(&rqst[1]);
440 		break;
441 	case SMB2_OP_HARDLINK:
442 		if (rc)
443 			trace_smb3_hardlink_err(xid,  ses->Suid, tcon->tid, rc);
444 		else
445 			trace_smb3_hardlink_done(xid, ses->Suid, tcon->tid);
446 		free_set_inf_compound(rqst);
447 		break;
448 	case SMB2_OP_RENAME:
449 		if (rc)
450 			trace_smb3_rename_err(xid,  ses->Suid, tcon->tid, rc);
451 		else
452 			trace_smb3_rename_done(xid, ses->Suid, tcon->tid);
453 		free_set_inf_compound(rqst);
454 		break;
455 	case SMB2_OP_RMDIR:
456 		if (rc)
457 			trace_smb3_rmdir_err(xid,  ses->Suid, tcon->tid, rc);
458 		else
459 			trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
460 		free_set_inf_compound(rqst);
461 		break;
462 	case SMB2_OP_SET_EOF:
463 		if (rc)
464 			trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
465 		else
466 			trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
467 		free_set_inf_compound(rqst);
468 		break;
469 	case SMB2_OP_SET_INFO:
470 		if (rc)
471 			trace_smb3_set_info_compound_err(xid,  ses->Suid,
472 						tcon->tid, rc);
473 		else
474 			trace_smb3_set_info_compound_done(xid, ses->Suid,
475 						tcon->tid);
476 		free_set_inf_compound(rqst);
477 		break;
478 	}
479 	free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
480 	free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
481 	free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
482 	kfree(vars);
483 	return rc;
484 }
485 
486 void
move_smb2_info_to_cifs(FILE_ALL_INFO * dst,struct smb2_file_all_info * src)487 move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
488 {
489 	memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
490 	dst->CurrentByteOffset = src->CurrentByteOffset;
491 	dst->Mode = src->Mode;
492 	dst->AlignmentRequirement = src->AlignmentRequirement;
493 	dst->IndexNumber1 = 0; /* we don't use it */
494 }
495 
496 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)497 smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
498 		     struct cifs_sb_info *cifs_sb, const char *full_path,
499 		     FILE_ALL_INFO *data, bool *adjust_tz, bool *reparse)
500 {
501 	int rc;
502 	struct smb2_file_all_info *smb2_data;
503 	__u32 create_options = 0;
504 	struct cifsFileInfo *cfile;
505 	struct cached_fid *cfid = NULL;
506 
507 	*adjust_tz = false;
508 	*reparse = false;
509 
510 	smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
511 			    GFP_KERNEL);
512 	if (smb2_data == NULL)
513 		return -ENOMEM;
514 
515 	if (strcmp(full_path, ""))
516 		rc = -ENOENT;
517 	else
518 		rc = open_cached_dir(xid, tcon, full_path, cifs_sb, &cfid);
519 	/* If it is a root and its handle is cached then use it */
520 	if (!rc) {
521 		if (tcon->crfid.file_all_info_is_valid) {
522 			move_smb2_info_to_cifs(data,
523 					       &tcon->crfid.file_all_info);
524 		} else {
525 			rc = SMB2_query_info(xid, tcon,
526 					     cfid->fid->persistent_fid,
527 					     cfid->fid->volatile_fid, smb2_data);
528 			if (!rc)
529 				move_smb2_info_to_cifs(data, smb2_data);
530 		}
531 		close_cached_dir(cfid);
532 		goto out;
533 	}
534 
535 	cifs_get_readable_path(tcon, full_path, &cfile);
536 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
537 			      FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
538 			      ACL_NO_MODE, smb2_data, SMB2_OP_QUERY_INFO, cfile);
539 	if (rc == -EOPNOTSUPP) {
540 		*reparse = true;
541 		create_options |= OPEN_REPARSE_POINT;
542 
543 		/* Failed on a symbolic link - query a reparse point info */
544 		cifs_get_readable_path(tcon, full_path, &cfile);
545 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
546 				      FILE_READ_ATTRIBUTES, FILE_OPEN,
547 				      create_options, ACL_NO_MODE,
548 				      smb2_data, SMB2_OP_QUERY_INFO, cfile);
549 	}
550 	if (rc)
551 		goto out;
552 
553 	move_smb2_info_to_cifs(data, smb2_data);
554 out:
555 	kfree(smb2_data);
556 	return rc;
557 }
558 
559 
560 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)561 smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
562 		     struct cifs_sb_info *cifs_sb, const char *full_path,
563 		     struct smb311_posix_qinfo *data, bool *adjust_tz, bool *reparse)
564 {
565 	int rc;
566 	__u32 create_options = 0;
567 	struct cifsFileInfo *cfile;
568 	struct smb311_posix_qinfo *smb2_data;
569 
570 	*adjust_tz = false;
571 	*reparse = false;
572 
573 	/* BB TODO: Make struct larger when add support for parsing owner SIDs */
574 	smb2_data = kzalloc(sizeof(struct smb311_posix_qinfo),
575 			    GFP_KERNEL);
576 	if (smb2_data == NULL)
577 		return -ENOMEM;
578 
579 	/*
580 	 * BB TODO: Add support for using the cached root handle.
581 	 * Create SMB2_query_posix_info worker function to do non-compounded query
582 	 * when we already have an open file handle for this. For now this is fast enough
583 	 * (always using the compounded version).
584 	 */
585 
586 	cifs_get_readable_path(tcon, full_path, &cfile);
587 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
588 			      FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
589 			      ACL_NO_MODE, smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
590 	if (rc == -EOPNOTSUPP) {
591 		/* BB TODO: When support for special files added to Samba re-verify this path */
592 		*reparse = true;
593 		create_options |= OPEN_REPARSE_POINT;
594 
595 		/* Failed on a symbolic link - query a reparse point info */
596 		cifs_get_readable_path(tcon, full_path, &cfile);
597 		rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
598 				      FILE_READ_ATTRIBUTES, FILE_OPEN,
599 				      create_options, ACL_NO_MODE,
600 				      smb2_data, SMB2_OP_POSIX_QUERY_INFO, cfile);
601 	}
602 	if (rc)
603 		goto out;
604 
605 	 /* TODO: will need to allow for the 2 SIDs when add support for getting owner UID/GID */
606 	memcpy(data, smb2_data, sizeof(struct smb311_posix_qinfo));
607 
608 out:
609 	kfree(smb2_data);
610 	return rc;
611 }
612 
613 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)614 smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
615 	   struct cifs_tcon *tcon, const char *name,
616 	   struct cifs_sb_info *cifs_sb)
617 {
618 	return smb2_compound_op(xid, tcon, cifs_sb, name,
619 				FILE_WRITE_ATTRIBUTES, FILE_CREATE,
620 				CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR,
621 				NULL);
622 }
623 
624 void
smb2_mkdir_setinfo(struct inode * inode,const char * name,struct cifs_sb_info * cifs_sb,struct cifs_tcon * tcon,const unsigned int xid)625 smb2_mkdir_setinfo(struct inode *inode, const char *name,
626 		   struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
627 		   const unsigned int xid)
628 {
629 	FILE_BASIC_INFO data;
630 	struct cifsInodeInfo *cifs_i;
631 	struct cifsFileInfo *cfile;
632 	u32 dosattrs;
633 	int tmprc;
634 
635 	memset(&data, 0, sizeof(data));
636 	cifs_i = CIFS_I(inode);
637 	dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
638 	data.Attributes = cpu_to_le32(dosattrs);
639 	cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
640 	tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
641 				 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
642 				 CREATE_NOT_FILE, ACL_NO_MODE,
643 				 &data, SMB2_OP_SET_INFO, cfile);
644 	if (tmprc == 0)
645 		cifs_i->cifsAttrs = dosattrs;
646 }
647 
648 int
smb2_rmdir(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)649 smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
650 	   struct cifs_sb_info *cifs_sb)
651 {
652 	return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
653 				CREATE_NOT_FILE, ACL_NO_MODE,
654 				NULL, SMB2_OP_RMDIR, NULL);
655 }
656 
657 int
smb2_unlink(const unsigned int xid,struct cifs_tcon * tcon,const char * name,struct cifs_sb_info * cifs_sb)658 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
659 	    struct cifs_sb_info *cifs_sb)
660 {
661 	return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
662 				CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
663 				ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL);
664 }
665 
666 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)667 smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
668 		   const char *from_name, const char *to_name,
669 		   struct cifs_sb_info *cifs_sb, __u32 access, int command,
670 		   struct cifsFileInfo *cfile)
671 {
672 	__le16 *smb2_to_name = NULL;
673 	int rc;
674 
675 	smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
676 	if (smb2_to_name == NULL) {
677 		rc = -ENOMEM;
678 		goto smb2_rename_path;
679 	}
680 	rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
681 			      FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name,
682 			      command, cfile);
683 smb2_rename_path:
684 	kfree(smb2_to_name);
685 	return rc;
686 }
687 
688 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)689 smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
690 		 const char *from_name, const char *to_name,
691 		 struct cifs_sb_info *cifs_sb)
692 {
693 	struct cifsFileInfo *cfile;
694 
695 	cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
696 
697 	return smb2_set_path_attr(xid, tcon, from_name, to_name,
698 				  cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
699 }
700 
701 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)702 smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
703 		     const char *from_name, const char *to_name,
704 		     struct cifs_sb_info *cifs_sb)
705 {
706 	return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
707 				  FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK,
708 				  NULL);
709 }
710 
711 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)712 smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
713 		   const char *full_path, __u64 size,
714 		   struct cifs_sb_info *cifs_sb, bool set_alloc)
715 {
716 	__le64 eof = cpu_to_le64(size);
717 	struct cifsFileInfo *cfile;
718 
719 	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
720 	return smb2_compound_op(xid, tcon, cifs_sb, full_path,
721 				FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE,
722 				&eof, SMB2_OP_SET_EOF, cfile);
723 }
724 
725 int
smb2_set_file_info(struct inode * inode,const char * full_path,FILE_BASIC_INFO * buf,const unsigned int xid)726 smb2_set_file_info(struct inode *inode, const char *full_path,
727 		   FILE_BASIC_INFO *buf, const unsigned int xid)
728 {
729 	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
730 	struct tcon_link *tlink;
731 	struct cifs_tcon *tcon;
732 	struct cifsFileInfo *cfile;
733 	int rc;
734 
735 	if ((buf->CreationTime == 0) && (buf->LastAccessTime == 0) &&
736 	    (buf->LastWriteTime == 0) && (buf->ChangeTime == 0) &&
737 	    (buf->Attributes == 0))
738 		return 0; /* would be a no op, no sense sending this */
739 
740 	tlink = cifs_sb_tlink(cifs_sb);
741 	if (IS_ERR(tlink))
742 		return PTR_ERR(tlink);
743 	tcon = tlink_tcon(tlink);
744 
745 	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
746 	rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
747 			      FILE_WRITE_ATTRIBUTES, FILE_OPEN,
748 			      0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile);
749 	cifs_put_tlink(tlink);
750 	return rc;
751 }
752