xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c (revision dbed73cbda2229fd1aa6dc5743993cae7f0a7ee9)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
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  * Supported Passthrough levels:
37  * SMB_FILE_BASIC_INFORMATION
38  * SMB_FILE_DISPOSITION_INFORMATION
39  * SMB_FILE_END_OF_FILE_INFORMATION
40  * SMB_FILE_ALLOCATION_INFORMATION
41  *
42  * Internal levels representing non trans2 requests
43  * SMB_SET_INFORMATION
44  * SMB_SET_INFORMATION2
45  */
46 
47 /*
48  * Setting timestamps:
49  * The behaviour when the time field is set to -1 is not documented
50  * but is generally treated like 0, meaning that that server file
51  * system assigned value need not be changed.
52  *
53  * Setting attributes - FILE_ATTRIBUTE_NORMAL:
54  * SMB_SET_INFORMATION -
55  * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
56  *   do NOT change the file's attributes.
57  * SMB_SET_BASIC_INFO -
58  * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
59  *   clear (0) the file's attributes.
60  * - if the specified attributes are 0 do NOT change the file's
61  *   attributes.
62  */
63 
64 #include <smbsrv/smb_incl.h>
65 #include <smbsrv/smb_fsops.h>
66 
67 typedef struct smb_setinfo {
68 	uint16_t si_infolev;
69 	smb_xa_t *si_xa;
70 	smb_node_t *si_node;
71 } smb_setinfo_t;
72 
73 /*
74  * These functions all return 0 (success)  or -1 (error).
75  * They set error details in the sr when appropriate.
76  */
77 static int smb_set_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
78 static int smb_set_by_path(smb_request_t *, smb_xa_t *, uint16_t, char *);
79 static int smb_set_fileinfo(smb_request_t *, smb_setinfo_t *);
80 static int smb_set_information(smb_request_t *, smb_setinfo_t *);
81 static int smb_set_information2(smb_request_t *, smb_setinfo_t *);
82 static int smb_set_standard_info(smb_request_t *, smb_setinfo_t *);
83 static int smb_set_basic_info(smb_request_t *, smb_setinfo_t *);
84 static int smb_set_disposition_info(smb_request_t *, smb_setinfo_t *);
85 static int smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *);
86 static int smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *);
87 
88 /*
89  * smb_com_trans2_set_file_information
90  */
91 smb_sdrc_t
92 smb_com_trans2_set_file_information(smb_request_t *sr, smb_xa_t *xa)
93 {
94 	uint16_t infolev;
95 
96 	if (smb_mbc_decodef(&xa->req_param_mb, "ww",
97 	    &sr->smb_fid, &infolev) != 0)
98 		return (SDRC_ERROR);
99 
100 	if (smb_set_by_fid(sr, xa, infolev) != 0)
101 		return (SDRC_ERROR);
102 
103 	return (SDRC_SUCCESS);
104 }
105 
106 /*
107  * smb_com_trans2_set_path_information
108  */
109 smb_sdrc_t
110 smb_com_trans2_set_path_information(smb_request_t *sr, smb_xa_t *xa)
111 {
112 	uint16_t infolev;
113 	char *path;
114 
115 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
116 		smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
117 		    ERRDOS, ERROR_INVALID_FUNCTION);
118 		return (SDRC_ERROR);
119 	}
120 
121 	if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
122 	    sr, &infolev, &path) != 0)
123 		return (SDRC_ERROR);
124 
125 	if (smb_set_by_path(sr, xa, infolev, path) != 0)
126 		return (SDRC_ERROR);
127 
128 	return (SDRC_SUCCESS);
129 }
130 
131 /*
132  * smb_com_set_information (aka setattr)
133  */
134 smb_sdrc_t
135 smb_pre_set_information(smb_request_t *sr)
136 {
137 	DTRACE_SMB_1(op__SetInformation__start, smb_request_t *, sr);
138 	return (SDRC_SUCCESS);
139 }
140 
141 void
142 smb_post_set_information(smb_request_t *sr)
143 {
144 	DTRACE_SMB_1(op__SetInformation__done, smb_request_t *, sr);
145 }
146 
147 smb_sdrc_t
148 smb_com_set_information(smb_request_t *sr)
149 {
150 	uint16_t infolev = SMB_SET_INFORMATION;
151 	char *path;
152 
153 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
154 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
155 		    ERRDOS, ERROR_ACCESS_DENIED);
156 		return (SDRC_ERROR);
157 	}
158 
159 	if (smbsr_decode_data(sr, "%S", sr, &path) != 0)
160 		return (SDRC_ERROR);
161 
162 	if (smb_set_by_path(sr, NULL, infolev, path) != 0)
163 		return (SDRC_ERROR);
164 
165 	if (smbsr_encode_empty_result(sr) != 0)
166 		return (SDRC_ERROR);
167 
168 	return (SDRC_SUCCESS);
169 }
170 
171 /*
172  * smb_com_set_information2 (aka setattre)
173  */
174 smb_sdrc_t
175 smb_pre_set_information2(smb_request_t *sr)
176 {
177 	DTRACE_SMB_1(op__SetInformation2__start, smb_request_t *, sr);
178 	return (SDRC_SUCCESS);
179 }
180 
181 void
182 smb_post_set_information2(smb_request_t *sr)
183 {
184 	DTRACE_SMB_1(op__SetInformation2__done, smb_request_t *, sr);
185 }
186 
187 smb_sdrc_t
188 smb_com_set_information2(smb_request_t *sr)
189 {
190 	uint16_t infolev = SMB_SET_INFORMATION2;
191 
192 	if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0)
193 		return (SDRC_ERROR);
194 
195 	if (smb_set_by_fid(sr, NULL, infolev) != 0)
196 		return (SDRC_ERROR);
197 
198 	if (smbsr_encode_empty_result(sr) != 0)
199 		return (SDRC_ERROR);
200 
201 	return (SDRC_SUCCESS);
202 }
203 
204 /*
205  * smb_set_by_fid
206  *
207  * Common code for setting file information by open file id.
208  * Use the id to identify the node object and invoke smb_set_fileinfo
209  * for that node.
210  *
211  * Setting attributes on a named pipe by id is handled by simply
212  * returning success.
213  */
214 static int
215 smb_set_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
216 {
217 	int rc;
218 	smb_setinfo_t sinfo;
219 
220 	if (SMB_TREE_IS_READONLY(sr)) {
221 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
222 		    ERRDOS, ERROR_ACCESS_DENIED);
223 		return (-1);
224 	}
225 
226 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type))
227 		return (0);
228 
229 	smbsr_lookup_file(sr);
230 	if (sr->fid_ofile == NULL) {
231 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
232 		return (-1);
233 	}
234 
235 	if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
236 		smbsr_release_file(sr);
237 		return (0);
238 	}
239 
240 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
241 
242 	sinfo.si_xa = xa;
243 	sinfo.si_infolev = infolev;
244 	sinfo.si_node = sr->fid_ofile->f_node;
245 	rc = smb_set_fileinfo(sr, &sinfo);
246 
247 	smbsr_release_file(sr);
248 	return (rc);
249 }
250 
251 /*
252  * smb_set_by_path
253  *
254  * Common code for setting file information by file name.
255  * Use the file name to identify the node object and invoke
256  * smb_set_fileinfo for that node.
257  *
258  * Setting attributes on a named pipe by name is an error and
259  * is handled in the calling functions so that they can return
260  * the appropriate error status code (which differs by caller).
261  */
262 static int
263 smb_set_by_path(smb_request_t *sr, smb_xa_t *xa,
264     uint16_t infolev, char *path)
265 {
266 	int rc;
267 	smb_setinfo_t sinfo;
268 	smb_node_t *node, *dnode;
269 	char *name;
270 
271 	if (SMB_TREE_IS_READONLY(sr)) {
272 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
273 		    ERRDOS, ERROR_ACCESS_DENIED);
274 		return (-1);
275 	}
276 
277 	name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
278 	rc = smb_pathname_reduce(sr, sr->user_cr, path,
279 	    sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, name);
280 	if (rc == 0) {
281 		rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
282 		    sr->tid_tree->t_snode, dnode, name, &node);
283 		smb_node_release(dnode);
284 	}
285 	kmem_free(name, MAXNAMELEN);
286 
287 	if (rc != 0) {
288 		smbsr_errno(sr, rc);
289 		return (-1);
290 	}
291 
292 	/* Break any conflicting oplock for subsequent attribute setting */
293 	if (smb_oplock_conflict(node, sr->session, NULL)) {
294 		(void) smb_oplock_break(node, sr->session, B_FALSE);
295 	}
296 
297 	sinfo.si_xa = xa;
298 	sinfo.si_infolev = infolev;
299 	sinfo.si_node = node;
300 	rc = smb_set_fileinfo(sr, &sinfo);
301 
302 	smb_node_release(node);
303 	return (rc);
304 }
305 
306 /*
307  * smb_set_fileinfo
308  */
309 static int
310 smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo)
311 {
312 	switch (sinfo->si_infolev) {
313 	case SMB_SET_INFORMATION:
314 		return (smb_set_information(sr, sinfo));
315 
316 	case SMB_SET_INFORMATION2:
317 		return (smb_set_information2(sr, sinfo));
318 
319 	case SMB_INFO_STANDARD:
320 		return (smb_set_standard_info(sr, sinfo));
321 
322 	case SMB_INFO_SET_EAS:
323 		/* EAs not supported */
324 		return (0);
325 
326 	case SMB_SET_FILE_BASIC_INFO:
327 	case SMB_FILE_BASIC_INFORMATION:
328 		return (smb_set_basic_info(sr, sinfo));
329 
330 	case SMB_SET_FILE_DISPOSITION_INFO:
331 	case SMB_FILE_DISPOSITION_INFORMATION:
332 		return (smb_set_disposition_info(sr, sinfo));
333 
334 	case SMB_SET_FILE_END_OF_FILE_INFO:
335 	case SMB_FILE_END_OF_FILE_INFORMATION:
336 		return (smb_set_eof_info(sr, sinfo));
337 
338 	case SMB_SET_FILE_ALLOCATION_INFO:
339 	case SMB_FILE_ALLOCATION_INFORMATION:
340 		return (smb_set_alloc_info(sr, sinfo));
341 
342 	default:
343 		break;
344 	}
345 
346 	smbsr_error(sr, NT_STATUS_INVALID_INFO_CLASS,
347 	    ERRDOS, ERROR_INVALID_PARAMETER);
348 	return (-1);
349 }
350 
351 /*
352  * smb_set_information
353  *
354  * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
355  * target is not a directory.
356  *
357  * For compatibility with Windows Servers, if the specified
358  * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change
359  * the file's attributes.
360  */
361 static int
362 smb_set_information(smb_request_t *sr, smb_setinfo_t *sinfo)
363 {
364 	int rc;
365 	uint16_t attributes;
366 	smb_node_t *node = sinfo->si_node;
367 	smb_attr_t attr;
368 	uint32_t mtime;
369 
370 	if (smbsr_decode_vwv(sr, "wl10.", &attributes, &mtime) != 0)
371 		return (-1);
372 
373 	if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
374 	    (!smb_node_is_dir(node))) {
375 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
376 		    ERRDOS, ERROR_INVALID_PARAMETER);
377 		return (-1);
378 	}
379 
380 	bzero(&attr, sizeof (smb_attr_t));
381 	if (attributes != FILE_ATTRIBUTE_NORMAL) {
382 		attr.sa_dosattr = attributes;
383 		attr.sa_mask |= SMB_AT_DOSATTR;
384 	}
385 
386 	if (mtime != 0 && mtime != UINT_MAX) {
387 		attr.sa_vattr.va_mtime.tv_sec =
388 		    smb_time_local_to_gmt(sr, mtime);
389 		attr.sa_mask |= SMB_AT_MTIME;
390 	}
391 
392 	rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
393 	if (rc != 0) {
394 		smbsr_errno(sr, rc);
395 		return (-1);
396 	}
397 
398 	return (0);
399 }
400 
401 /*
402  * smb_set_information2
403  */
404 static int
405 smb_set_information2(smb_request_t *sr, smb_setinfo_t *sinfo)
406 {
407 	int rc;
408 	uint32_t crtime, atime, mtime;
409 	smb_attr_t attr;
410 
411 	if (smbsr_decode_vwv(sr, "yyy", &crtime, &atime, &mtime) != 0)
412 		return (-1);
413 
414 	bzero(&attr, sizeof (smb_attr_t));
415 	if (mtime != 0 && mtime != UINT_MAX) {
416 		attr.sa_vattr.va_mtime.tv_sec =
417 		    smb_time_local_to_gmt(sr, mtime);
418 		attr.sa_mask |= SMB_AT_MTIME;
419 	}
420 
421 	if (crtime != 0 && crtime != UINT_MAX) {
422 		attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
423 		attr.sa_mask |= SMB_AT_CRTIME;
424 	}
425 
426 	if (atime != 0 && atime != UINT_MAX) {
427 		attr.sa_vattr.va_atime.tv_sec =
428 		    smb_time_local_to_gmt(sr, atime);
429 		attr.sa_mask |= SMB_AT_ATIME;
430 	}
431 
432 	rc = smb_node_setattr(sr, sinfo->si_node, sr->user_cr,
433 	    sr->fid_ofile, &attr);
434 	if (rc != 0) {
435 		smbsr_errno(sr, rc);
436 		return (-1);
437 	}
438 
439 	return (0);
440 }
441 
442 /*
443  * smb_set_standard_info
444  *
445  * Sets standard file/path information.
446  */
447 static int
448 smb_set_standard_info(smb_request_t *sr, smb_setinfo_t *sinfo)
449 {
450 	smb_attr_t attr;
451 	uint32_t crtime, atime, mtime;
452 	smb_node_t *node = sinfo->si_node;
453 	int rc;
454 
455 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "yyy",
456 	    &crtime, &atime, &mtime) != 0) {
457 		return (-1);
458 	}
459 
460 	bzero(&attr, sizeof (smb_attr_t));
461 	if (mtime != 0 && mtime != (uint32_t)-1) {
462 		attr.sa_vattr.va_mtime.tv_sec =
463 		    smb_time_local_to_gmt(sr, mtime);
464 		attr.sa_mask |= SMB_AT_MTIME;
465 	}
466 
467 	if (crtime != 0 && crtime != (uint32_t)-1) {
468 		attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
469 		attr.sa_mask |= SMB_AT_CRTIME;
470 	}
471 
472 	if (atime != 0 && atime != (uint32_t)-1) {
473 		attr.sa_vattr.va_atime.tv_sec =
474 		    smb_time_local_to_gmt(sr, atime);
475 		attr.sa_mask |= SMB_AT_ATIME;
476 	}
477 
478 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
479 	if (rc != 0) {
480 		smbsr_errno(sr, rc);
481 		return (-1);
482 	}
483 
484 	return (0);
485 }
486 
487 /*
488  * smb_set_basic_info
489  *
490  * Sets basic file/path information.
491  *
492  * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
493  * target is not a directory.
494  *
495  * For compatibility with windows servers:
496  * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
497  *   clear (0) the file's attributes.
498  * - if the specified attributes are 0 do NOT change the file's attributes.
499  */
500 static int
501 smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *sinfo)
502 {
503 	int rc;
504 	uint64_t crtime, atime, mtime, ctime;
505 	uint16_t attributes;
506 	smb_attr_t attr;
507 	smb_node_t *node = sinfo->si_node;
508 
509 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "qqqqw",
510 	    &crtime, &atime, &mtime, &ctime, &attributes) != 0) {
511 		return (-1);
512 	}
513 
514 	if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
515 	    (!smb_node_is_dir(node))) {
516 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
517 		    ERRDOS, ERROR_INVALID_PARAMETER);
518 		return (-1);
519 	}
520 
521 	bzero(&attr, sizeof (smb_attr_t));
522 	if (ctime != 0 && ctime != (uint64_t)-1) {
523 		smb_time_nt_to_unix(ctime, &attr.sa_vattr.va_ctime);
524 		attr.sa_mask |= SMB_AT_CTIME;
525 	}
526 
527 	if (crtime != 0 && crtime != (uint64_t)-1) {
528 		smb_time_nt_to_unix(crtime, &attr.sa_crtime);
529 		attr.sa_mask |= SMB_AT_CRTIME;
530 	}
531 
532 	if (mtime != 0 && mtime != (uint64_t)-1) {
533 		smb_time_nt_to_unix(mtime, &attr.sa_vattr.va_mtime);
534 		attr.sa_mask |= SMB_AT_MTIME;
535 	}
536 
537 	if (atime != 0 && atime != (uint64_t)-1) {
538 		smb_time_nt_to_unix(atime, &attr.sa_vattr.va_atime);
539 		attr.sa_mask |= SMB_AT_ATIME;
540 	}
541 
542 	if (attributes != 0) {
543 		attr.sa_dosattr = attributes;
544 		attr.sa_mask |= SMB_AT_DOSATTR;
545 	}
546 
547 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
548 	if (rc != 0) {
549 		smbsr_errno(sr, rc);
550 		return (-1);
551 	}
552 
553 	return (0);
554 }
555 
556 /*
557  * smb_set_eof_info
558  */
559 static int
560 smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *sinfo)
561 {
562 	int rc;
563 	smb_attr_t attr;
564 	uint64_t eof;
565 	smb_node_t *node = sinfo->si_node;
566 
567 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &eof) != 0)
568 		return (-1);
569 
570 	if (smb_node_is_dir(node)) {
571 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
572 		    ERRDOS, ERROR_INVALID_PARAMETER);
573 		return (-1);
574 	}
575 
576 	bzero(&attr, sizeof (smb_attr_t));
577 	attr.sa_mask = SMB_AT_SIZE;
578 	attr.sa_vattr.va_size = (u_offset_t)eof;
579 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
580 	if (rc != 0) {
581 		smbsr_errno(sr, rc);
582 		return (-1);
583 	}
584 
585 	return (0);
586 }
587 
588 /*
589  * smb_set_alloc_info
590  */
591 static int
592 smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *sinfo)
593 {
594 	int rc;
595 	smb_attr_t attr;
596 	uint64_t allocsz;
597 	smb_node_t *node = sinfo->si_node;
598 
599 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &allocsz) != 0)
600 		return (-1);
601 
602 	if (smb_node_is_dir(node)) {
603 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
604 		    ERRDOS, ERROR_INVALID_PARAMETER);
605 		return (-1);
606 	}
607 
608 	bzero(&attr, sizeof (smb_attr_t));
609 	attr.sa_mask = SMB_AT_ALLOCSZ;
610 	attr.sa_allocsz = (u_offset_t)allocsz;
611 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
612 	if (rc != 0) {
613 		smbsr_errno(sr, rc);
614 		return (-1);
615 	}
616 
617 	return (0);
618 }
619 
620 /*
621  * smb_set_disposition_info
622  *
623  * Set/Clear DELETE_ON_CLOSE flag for an open file.
624  * File should have been opened with DELETE access otherwise
625  * the operation is not permitted.
626  *
627  * NOTE: The node should be marked delete-on-close upon the receipt
628  * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
629  * It is different than both SmbNtCreateAndX and SmbNtTransact, which
630  * set delete-on-close on the ofile and defer setting the flag on the
631  * node until the file is closed.
632  *
633  * Observation of Windows 2000 indicates the following:
634  *
635  * 1) If a file is not opened with delete-on-close create options and
636  * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
637  * using that open file handle, any subsequent open requests will fail
638  * with DELETE_PENDING.
639  *
640  * 2) If a file is opened with delete-on-close create options and the
641  * client attempts to unset delete-on-close via Trans2SetFileInfo
642  * (SetDispositionInfo) prior to the file close, any subsequent open
643  * requests will still fail with DELETE_PENDING after the file is closed.
644  *
645  * 3) If a file is opened with delete-on-close create options and that
646  * file handle (not the last open handle and the only file handle
647  * with delete-on-close set) is closed. Any subsequent open requests
648  * will fail with DELETE_PENDING. Unsetting delete-on-close via
649  * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
650  * node delete-on-close flag, which will result in the file not being
651  * removed even after the last file handle is closed.
652  */
653 static int
654 smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *sinfo)
655 {
656 	unsigned char	mark_delete;
657 	uint32_t	flags = 0;
658 
659 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "b", &mark_delete) != 0)
660 		return (-1);
661 
662 	if ((sr->fid_ofile == NULL) ||
663 	    !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
664 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
665 		    ERRDOS, ERROR_ACCESS_DENIED);
666 		return (-1);
667 	}
668 
669 	if (mark_delete) {
670 		if (SMB_TREE_SUPPORTS_CATIA(sr))
671 			flags |= SMB_CATIA;
672 
673 		if (smb_node_set_delete_on_close(sinfo->si_node,
674 		    sr->user_cr, flags)) {
675 			smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
676 			    ERRDOS, ERROR_ACCESS_DENIED);
677 			return (-1);
678 		}
679 	} else {
680 		smb_node_reset_delete_on_close(sinfo->si_node);
681 	}
682 	return (0);
683 }
684