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