xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c (revision 67a4bb8f9ad4c49e9aa9e21e2114a7c093c3a73a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
24  */
25 
26 /*
27  * Trans2 Set File/Path Information Levels:
28  *
29  * SMB_INFO_STANDARD
30  * SMB_INFO_SET_EAS
31  * SMB_SET_FILE_BASIC_INFO
32  * SMB_SET_FILE_DISPOSITION_INFO
33  * SMB_SET_FILE_END_OF_FILE_INFO
34  * SMB_SET_FILE_ALLOCATION_INFO
35  *
36  * Handled Passthrough levels:
37  * SMB_FILE_BASIC_INFORMATION
38  * SMB_FILE_RENAME_INFORMATION
39  * SMB_FILE_LINK_INFORMATION
40  * SMB_FILE_DISPOSITION_INFORMATION
41  * SMB_FILE_END_OF_FILE_INFORMATION
42  * SMB_FILE_ALLOCATION_INFORMATION
43  *
44  * Internal levels representing non trans2 requests
45  * SMB_SET_INFORMATION
46  * SMB_SET_INFORMATION2
47  */
48 
49 /*
50  * Setting timestamps:
51  * The behaviour when the time field is set to -1 is not documented
52  * but is generally treated like 0, meaning that that server file
53  * system assigned value need not be changed.
54  *
55  * Setting attributes - FILE_ATTRIBUTE_NORMAL:
56  * SMB_SET_INFORMATION -
57  * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
58  *   do NOT change the file's attributes.
59  * SMB_SET_BASIC_INFO -
60  * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
61  *   clear (0) the file's attributes.
62  * - if the specified attributes are 0 do NOT change the file's
63  *   attributes.
64  */
65 
66 #include <smbsrv/smb_kproto.h>
67 #include <smbsrv/smb_fsops.h>
68 
69 typedef struct smb_setinfo {
70 	uint16_t si_infolev;
71 	smb_xa_t *si_xa;
72 	smb_node_t *si_node;
73 } smb_setinfo_t;
74 
75 /*
76  * These functions all return 0 (success)  or -1 (error).
77  * They set error details in the sr when appropriate.
78  */
79 static int smb_set_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
80 static int smb_set_by_path(smb_request_t *, smb_xa_t *, uint16_t);
81 static int smb_set_fileinfo(smb_request_t *, smb_setinfo_t *);
82 static int smb_set_information(smb_request_t *, smb_setinfo_t *);
83 static int smb_set_information2(smb_request_t *, smb_setinfo_t *);
84 static int smb_set_standard_info(smb_request_t *, smb_setinfo_t *);
85 static int smb_set_basic_info(smb_request_t *, smb_setinfo_t *);
86 static int smb_set_disposition_info(smb_request_t *, smb_setinfo_t *);
87 static int smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *);
88 static int smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *);
89 static int smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *);
90 
91 /*
92  * smb_com_trans2_set_file_information
93  */
94 smb_sdrc_t
95 smb_com_trans2_set_file_information(smb_request_t *sr, smb_xa_t *xa)
96 {
97 	uint16_t infolev;
98 
99 	if (smb_mbc_decodef(&xa->req_param_mb, "ww",
100 	    &sr->smb_fid, &infolev) != 0)
101 		return (SDRC_ERROR);
102 
103 	if (smb_set_by_fid(sr, xa, infolev) != 0)
104 		return (SDRC_ERROR);
105 
106 	return (SDRC_SUCCESS);
107 }
108 
109 /*
110  * smb_com_trans2_set_path_information
111  */
112 smb_sdrc_t
113 smb_com_trans2_set_path_information(smb_request_t *sr, smb_xa_t *xa)
114 {
115 	uint16_t	infolev;
116 	smb_fqi_t	*fqi = &sr->arg.dirop.fqi;
117 
118 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
119 		smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
120 		    ERRDOS, ERROR_INVALID_FUNCTION);
121 		return (SDRC_ERROR);
122 	}
123 
124 	if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
125 	    sr, &infolev, &fqi->fq_path.pn_path) != 0)
126 		return (SDRC_ERROR);
127 
128 	if (smb_set_by_path(sr, xa, infolev) != 0)
129 		return (SDRC_ERROR);
130 
131 	return (SDRC_SUCCESS);
132 }
133 
134 /*
135  * smb_com_set_information (aka setattr)
136  */
137 smb_sdrc_t
138 smb_pre_set_information(smb_request_t *sr)
139 {
140 	DTRACE_SMB_1(op__SetInformation__start, smb_request_t *, sr);
141 	return (SDRC_SUCCESS);
142 }
143 
144 void
145 smb_post_set_information(smb_request_t *sr)
146 {
147 	DTRACE_SMB_1(op__SetInformation__done, smb_request_t *, sr);
148 }
149 
150 smb_sdrc_t
151 smb_com_set_information(smb_request_t *sr)
152 {
153 	uint16_t	infolev = SMB_SET_INFORMATION;
154 	smb_fqi_t	*fqi = &sr->arg.dirop.fqi;
155 
156 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
157 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
158 		    ERRDOS, ERROR_ACCESS_DENIED);
159 		return (SDRC_ERROR);
160 	}
161 
162 	if (smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path) != 0)
163 		return (SDRC_ERROR);
164 
165 	if (smb_set_by_path(sr, NULL, infolev) != 0)
166 		return (SDRC_ERROR);
167 
168 	if (smbsr_encode_empty_result(sr) != 0)
169 		return (SDRC_ERROR);
170 
171 	return (SDRC_SUCCESS);
172 }
173 
174 /*
175  * smb_com_set_information2 (aka setattre)
176  */
177 smb_sdrc_t
178 smb_pre_set_information2(smb_request_t *sr)
179 {
180 	DTRACE_SMB_1(op__SetInformation2__start, smb_request_t *, sr);
181 	return (SDRC_SUCCESS);
182 }
183 
184 void
185 smb_post_set_information2(smb_request_t *sr)
186 {
187 	DTRACE_SMB_1(op__SetInformation2__done, smb_request_t *, sr);
188 }
189 
190 smb_sdrc_t
191 smb_com_set_information2(smb_request_t *sr)
192 {
193 	uint16_t infolev = SMB_SET_INFORMATION2;
194 
195 	if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0)
196 		return (SDRC_ERROR);
197 
198 	if (smb_set_by_fid(sr, NULL, infolev) != 0)
199 		return (SDRC_ERROR);
200 
201 	if (smbsr_encode_empty_result(sr) != 0)
202 		return (SDRC_ERROR);
203 
204 	return (SDRC_SUCCESS);
205 }
206 
207 /*
208  * smb_set_by_fid
209  *
210  * Common code for setting file information by open file id.
211  * Use the id to identify the node object and invoke smb_set_fileinfo
212  * for that node.
213  *
214  * Setting attributes on a named pipe by id is handled by simply
215  * returning success.
216  */
217 static int
218 smb_set_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
219 {
220 	int rc;
221 	smb_setinfo_t sinfo;
222 
223 	if (SMB_TREE_IS_READONLY(sr)) {
224 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
225 		    ERRDOS, ERROR_ACCESS_DENIED);
226 		return (-1);
227 	}
228 
229 	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
230 		return (0);
231 
232 	smbsr_lookup_file(sr);
233 	if (sr->fid_ofile == NULL) {
234 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
235 		return (-1);
236 	}
237 
238 	if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
239 		smbsr_release_file(sr);
240 		return (0);
241 	}
242 
243 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
244 
245 	sinfo.si_xa = xa;
246 	sinfo.si_infolev = infolev;
247 	sinfo.si_node = sr->fid_ofile->f_node;
248 	rc = smb_set_fileinfo(sr, &sinfo);
249 
250 	smbsr_release_file(sr);
251 	return (rc);
252 }
253 
254 /*
255  * smb_set_by_path
256  *
257  * Common code for setting file information by file name.
258  * Use the file name to identify the node object and invoke
259  * smb_set_fileinfo for that node.
260  *
261  * Path should be set in sr->arg.dirop.fqi.fq_path prior to
262  * calling smb_set_by_path.
263  *
264  * Setting attributes on a named pipe by name is an error and
265  * is handled in the calling functions so that they can return
266  * the appropriate error status code (which differs by caller).
267  */
268 static int
269 smb_set_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
270 {
271 	int rc;
272 	smb_setinfo_t sinfo;
273 	smb_node_t *node, *dnode;
274 	char *name;
275 	smb_pathname_t	*pn;
276 
277 	if (SMB_TREE_IS_READONLY(sr)) {
278 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
279 		    ERRDOS, ERROR_ACCESS_DENIED);
280 		return (-1);
281 	}
282 
283 	pn = &sr->arg.dirop.fqi.fq_path;
284 	smb_pathname_init(sr, pn, pn->pn_path);
285 	if (!smb_pathname_validate(sr, pn))
286 		return (-1);
287 
288 	name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
289 	rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
290 	    sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, name);
291 	if (rc == 0) {
292 		rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
293 		    sr->tid_tree->t_snode, dnode, name, &node);
294 		smb_node_release(dnode);
295 	}
296 	kmem_free(name, MAXNAMELEN);
297 
298 	if (rc != 0) {
299 		if (rc == ENOENT) {
300 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
301 			    ERRDOS, ERROR_FILE_NOT_FOUND);
302 		} else {
303 			smbsr_errno(sr, rc);
304 		}
305 		return (-1);
306 	}
307 
308 	sinfo.si_xa = xa;
309 	sinfo.si_infolev = infolev;
310 	sinfo.si_node = node;
311 	rc = smb_set_fileinfo(sr, &sinfo);
312 
313 	smb_node_release(node);
314 	return (rc);
315 }
316 
317 /*
318  * smb_set_fileinfo
319  *
320  * For compatibility with windows servers, SMB_FILE_LINK_INFORMATION
321  * is handled by returning NT_STATUS_NOT_SUPPORTED.
322  */
323 static int
324 smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo)
325 {
326 	switch (sinfo->si_infolev) {
327 	case SMB_SET_INFORMATION:
328 		return (smb_set_information(sr, sinfo));
329 
330 	case SMB_SET_INFORMATION2:
331 		return (smb_set_information2(sr, sinfo));
332 
333 	case SMB_INFO_STANDARD:
334 		return (smb_set_standard_info(sr, sinfo));
335 
336 	case SMB_INFO_SET_EAS:
337 		/* EAs not supported */
338 		return (0);
339 
340 	case SMB_SET_FILE_BASIC_INFO:
341 	case SMB_FILE_BASIC_INFORMATION:
342 		return (smb_set_basic_info(sr, sinfo));
343 
344 	case SMB_SET_FILE_DISPOSITION_INFO:
345 	case SMB_FILE_DISPOSITION_INFORMATION:
346 		return (smb_set_disposition_info(sr, sinfo));
347 
348 	case SMB_SET_FILE_END_OF_FILE_INFO:
349 	case SMB_FILE_END_OF_FILE_INFORMATION:
350 		return (smb_set_eof_info(sr, sinfo));
351 
352 	case SMB_SET_FILE_ALLOCATION_INFO:
353 	case SMB_FILE_ALLOCATION_INFORMATION:
354 		return (smb_set_alloc_info(sr, sinfo));
355 
356 	case SMB_FILE_RENAME_INFORMATION:
357 		return (smb_set_rename_info(sr, sinfo));
358 
359 	case SMB_FILE_LINK_INFORMATION:
360 		smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
361 		    ERRDOS, ERROR_NOT_SUPPORTED);
362 		return (-1);
363 	default:
364 		break;
365 	}
366 
367 	smbsr_error(sr, NT_STATUS_INVALID_INFO_CLASS,
368 	    ERRDOS, ERROR_INVALID_PARAMETER);
369 	return (-1);
370 }
371 
372 /*
373  * smb_set_information
374  *
375  * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
376  * target is not a directory.
377  *
378  * For compatibility with Windows Servers, if the specified
379  * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change
380  * the file's attributes.
381  */
382 static int
383 smb_set_information(smb_request_t *sr, smb_setinfo_t *sinfo)
384 {
385 	int rc;
386 	uint16_t attributes;
387 	smb_node_t *node = sinfo->si_node;
388 	smb_attr_t attr;
389 	uint32_t mtime;
390 
391 	if (smbsr_decode_vwv(sr, "wl10.", &attributes, &mtime) != 0)
392 		return (-1);
393 
394 	if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
395 	    (!smb_node_is_dir(node))) {
396 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
397 		    ERRDOS, ERROR_INVALID_PARAMETER);
398 		return (-1);
399 	}
400 
401 	bzero(&attr, sizeof (smb_attr_t));
402 	if (attributes != FILE_ATTRIBUTE_NORMAL) {
403 		attr.sa_dosattr = attributes;
404 		attr.sa_mask |= SMB_AT_DOSATTR;
405 	}
406 
407 	if (mtime != 0 && mtime != UINT_MAX) {
408 		attr.sa_vattr.va_mtime.tv_sec =
409 		    smb_time_local_to_gmt(sr, mtime);
410 		attr.sa_mask |= SMB_AT_MTIME;
411 	}
412 
413 	rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
414 	if (rc != 0) {
415 		smbsr_errno(sr, rc);
416 		return (-1);
417 	}
418 
419 	return (0);
420 }
421 
422 /*
423  * smb_set_information2
424  */
425 static int
426 smb_set_information2(smb_request_t *sr, smb_setinfo_t *sinfo)
427 {
428 	int rc;
429 	uint32_t crtime, atime, mtime;
430 	smb_attr_t attr;
431 
432 	if (smbsr_decode_vwv(sr, "yyy", &crtime, &atime, &mtime) != 0)
433 		return (-1);
434 
435 	bzero(&attr, sizeof (smb_attr_t));
436 	if (mtime != 0 && mtime != UINT_MAX) {
437 		attr.sa_vattr.va_mtime.tv_sec =
438 		    smb_time_local_to_gmt(sr, mtime);
439 		attr.sa_mask |= SMB_AT_MTIME;
440 	}
441 
442 	if (crtime != 0 && crtime != UINT_MAX) {
443 		attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
444 		attr.sa_mask |= SMB_AT_CRTIME;
445 	}
446 
447 	if (atime != 0 && atime != UINT_MAX) {
448 		attr.sa_vattr.va_atime.tv_sec =
449 		    smb_time_local_to_gmt(sr, atime);
450 		attr.sa_mask |= SMB_AT_ATIME;
451 	}
452 
453 	rc = smb_node_setattr(sr, sinfo->si_node, sr->user_cr,
454 	    sr->fid_ofile, &attr);
455 	if (rc != 0) {
456 		smbsr_errno(sr, rc);
457 		return (-1);
458 	}
459 
460 	return (0);
461 }
462 
463 /*
464  * smb_set_standard_info
465  *
466  * Sets standard file/path information.
467  */
468 static int
469 smb_set_standard_info(smb_request_t *sr, smb_setinfo_t *sinfo)
470 {
471 	smb_attr_t attr;
472 	uint32_t crtime, atime, mtime;
473 	smb_node_t *node = sinfo->si_node;
474 	int rc;
475 
476 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "yyy",
477 	    &crtime, &atime, &mtime) != 0) {
478 		return (-1);
479 	}
480 
481 	bzero(&attr, sizeof (smb_attr_t));
482 	if (mtime != 0 && mtime != (uint32_t)-1) {
483 		attr.sa_vattr.va_mtime.tv_sec =
484 		    smb_time_local_to_gmt(sr, mtime);
485 		attr.sa_mask |= SMB_AT_MTIME;
486 	}
487 
488 	if (crtime != 0 && crtime != (uint32_t)-1) {
489 		attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
490 		attr.sa_mask |= SMB_AT_CRTIME;
491 	}
492 
493 	if (atime != 0 && atime != (uint32_t)-1) {
494 		attr.sa_vattr.va_atime.tv_sec =
495 		    smb_time_local_to_gmt(sr, atime);
496 		attr.sa_mask |= SMB_AT_ATIME;
497 	}
498 
499 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
500 	if (rc != 0) {
501 		smbsr_errno(sr, rc);
502 		return (-1);
503 	}
504 
505 	return (0);
506 }
507 
508 /*
509  * smb_set_basic_info
510  *
511  * Sets basic file/path information.
512  *
513  * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
514  * target is not a directory.
515  *
516  * For compatibility with windows servers:
517  * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
518  *   clear (0) the file's attributes.
519  * - if the specified attributes are 0 do NOT change the file's attributes.
520  */
521 static int
522 smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *sinfo)
523 {
524 	int rc;
525 	uint64_t crtime, atime, mtime, ctime;
526 	uint16_t attributes;
527 	smb_attr_t attr;
528 	smb_node_t *node = sinfo->si_node;
529 
530 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "qqqqw",
531 	    &crtime, &atime, &mtime, &ctime, &attributes) != 0) {
532 		return (-1);
533 	}
534 
535 	if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
536 	    (!smb_node_is_dir(node))) {
537 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
538 		    ERRDOS, ERROR_INVALID_PARAMETER);
539 		return (-1);
540 	}
541 
542 	bzero(&attr, sizeof (smb_attr_t));
543 	if (ctime != 0 && ctime != (uint64_t)-1) {
544 		smb_time_nt_to_unix(ctime, &attr.sa_vattr.va_ctime);
545 		attr.sa_mask |= SMB_AT_CTIME;
546 	}
547 
548 	if (crtime != 0 && crtime != (uint64_t)-1) {
549 		smb_time_nt_to_unix(crtime, &attr.sa_crtime);
550 		attr.sa_mask |= SMB_AT_CRTIME;
551 	}
552 
553 	if (mtime != 0 && mtime != (uint64_t)-1) {
554 		smb_time_nt_to_unix(mtime, &attr.sa_vattr.va_mtime);
555 		attr.sa_mask |= SMB_AT_MTIME;
556 	}
557 
558 	if (atime != 0 && atime != (uint64_t)-1) {
559 		smb_time_nt_to_unix(atime, &attr.sa_vattr.va_atime);
560 		attr.sa_mask |= SMB_AT_ATIME;
561 	}
562 
563 	if (attributes != 0) {
564 		attr.sa_dosattr = attributes;
565 		attr.sa_mask |= SMB_AT_DOSATTR;
566 	}
567 
568 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
569 	if (rc != 0) {
570 		smbsr_errno(sr, rc);
571 		return (-1);
572 	}
573 
574 	return (0);
575 }
576 
577 /*
578  * smb_set_eof_info
579  */
580 static int
581 smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *sinfo)
582 {
583 	int rc;
584 	smb_attr_t attr;
585 	uint64_t eof;
586 	smb_node_t *node = sinfo->si_node;
587 
588 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &eof) != 0)
589 		return (-1);
590 
591 	if (smb_node_is_dir(node)) {
592 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
593 		    ERRDOS, ERROR_INVALID_PARAMETER);
594 		return (-1);
595 	}
596 
597 	/* If opened by path, break exclusive oplock */
598 	if (sr->fid_ofile == NULL)
599 		(void) smb_oplock_break(sr, node,
600 		    SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE);
601 
602 	bzero(&attr, sizeof (smb_attr_t));
603 	attr.sa_mask = SMB_AT_SIZE;
604 	attr.sa_vattr.va_size = (u_offset_t)eof;
605 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
606 	if (rc != 0) {
607 		smbsr_errno(sr, rc);
608 		return (-1);
609 	}
610 
611 	smb_oplock_break_levelII(node);
612 	return (0);
613 }
614 
615 /*
616  * smb_set_alloc_info
617  */
618 static int
619 smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *sinfo)
620 {
621 	int rc;
622 	smb_attr_t attr;
623 	uint64_t allocsz;
624 	smb_node_t *node = sinfo->si_node;
625 
626 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &allocsz) != 0)
627 		return (-1);
628 
629 	if (smb_node_is_dir(node)) {
630 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
631 		    ERRDOS, ERROR_INVALID_PARAMETER);
632 		return (-1);
633 	}
634 
635 	/* If opened by path, break exclusive oplock */
636 	if (sr->fid_ofile == NULL)
637 		(void) smb_oplock_break(sr, node,
638 		    SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE);
639 
640 	bzero(&attr, sizeof (smb_attr_t));
641 	attr.sa_mask = SMB_AT_ALLOCSZ;
642 	attr.sa_allocsz = (u_offset_t)allocsz;
643 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
644 	if (rc != 0) {
645 		smbsr_errno(sr, rc);
646 		return (-1);
647 	}
648 
649 	smb_oplock_break_levelII(node);
650 	return (0);
651 }
652 
653 /*
654  * smb_set_disposition_info
655  *
656  * Set/Clear DELETE_ON_CLOSE flag for an open file.
657  * File should have been opened with DELETE access otherwise
658  * the operation is not permitted.
659  *
660  * NOTE: The node should be marked delete-on-close upon the receipt
661  * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
662  * It is different than both SmbNtCreateAndX and SmbNtTransact, which
663  * set delete-on-close on the ofile and defer setting the flag on the
664  * node until the file is closed.
665  *
666  * Observation of Windows 2000 indicates the following:
667  *
668  * 1) If a file is not opened with delete-on-close create options and
669  * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
670  * using that open file handle, any subsequent open requests will fail
671  * with DELETE_PENDING.
672  *
673  * 2) If a file is opened with delete-on-close create options and the
674  * client attempts to unset delete-on-close via Trans2SetFileInfo
675  * (SetDispositionInfo) prior to the file close, any subsequent open
676  * requests will still fail with DELETE_PENDING after the file is closed.
677  *
678  * 3) If a file is opened with delete-on-close create options and that
679  * file handle (not the last open handle and the only file handle
680  * with delete-on-close set) is closed. Any subsequent open requests
681  * will fail with DELETE_PENDING. Unsetting delete-on-close via
682  * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
683  * node delete-on-close flag, which will result in the file not being
684  * removed even after the last file handle is closed.
685  */
686 static int
687 smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *sinfo)
688 {
689 	unsigned char	mark_delete;
690 	uint32_t	flags = 0;
691 	int		doserr;
692 	uint32_t	status;
693 
694 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "b", &mark_delete) != 0)
695 		return (-1);
696 
697 	if ((sr->fid_ofile == NULL) ||
698 	    !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
699 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
700 		    ERRDOS, ERROR_ACCESS_DENIED);
701 		return (-1);
702 	}
703 
704 	if (mark_delete) {
705 		if (SMB_TREE_SUPPORTS_CATIA(sr))
706 			flags |= SMB_CATIA;
707 
708 		status = smb_node_set_delete_on_close(sinfo->si_node,
709 		    sr->user_cr, flags);
710 		if (status != NT_STATUS_SUCCESS) {
711 			switch (status) {
712 			case NT_STATUS_CANNOT_DELETE:
713 				doserr = ERROR_ACCESS_DENIED;
714 				break;
715 			case NT_STATUS_DIRECTORY_NOT_EMPTY:
716 				doserr = ERROR_DIR_NOT_EMPTY;
717 				break;
718 			default:
719 				doserr = ERROR_GEN_FAILURE;
720 				break;
721 			}
722 			smbsr_error(sr, status, ERRDOS, doserr);
723 			return (-1);
724 		}
725 	} else {
726 		smb_node_reset_delete_on_close(sinfo->si_node);
727 	}
728 	return (0);
729 }
730 
731 /*
732  * smb_set_rename_info
733  *
734  * Explicitly specified parameter validation rules:
735  * - If rootdir is not NULL respond with NT_STATUS_INVALID_PARAMETER.
736  * - If the filename contains a separator character respond with
737  *   NT_STATUS_INVALID_PARAMETER.
738  *
739  * Oplock break:
740  * Some Windows servers break BATCH oplocks prior to the rename.
741  * W2K3 does not. We behave as W2K3; we do not send an oplock break.
742  */
743 static int
744 smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *sinfo)
745 {
746 	int rc;
747 	uint32_t flags, rootdir, namelen;
748 	char *fname;
749 
750 	rc = smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "lll",
751 	    &flags, &rootdir, &namelen);
752 	if (rc == 0) {
753 		rc = smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "%#U",
754 		    sr, namelen, &fname);
755 	}
756 	if (rc != 0)
757 		return (-1);
758 
759 	if ((rootdir != 0) || (namelen == 0) || (namelen >= MAXNAMELEN)) {
760 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
761 		    ERRDOS, ERROR_INVALID_PARAMETER);
762 		return (-1);
763 	}
764 
765 	if (strchr(fname, '\\') != NULL) {
766 		smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
767 		    ERRDOS, ERROR_NOT_SUPPORTED);
768 		return (-1);
769 	}
770 
771 	rc = smb_trans2_rename(sr, sinfo->si_node, fname, flags);
772 
773 	return ((rc == 0) ? 0 : -1);
774 }
775