Home | History | Annotate | Download | only in smbsrv
      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  * 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, char *);
     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 	char *path;
    117 
    118 	if (!STYPE_ISDSK(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, &path) != 0)
    126 		return (SDRC_ERROR);
    127 
    128 	if (smb_set_by_path(sr, xa, infolev, path) != 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 	char *path;
    155 
    156 	if (!STYPE_ISDSK(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, &path) != 0)
    163 		return (SDRC_ERROR);
    164 
    165 	if (smb_set_by_path(sr, NULL, infolev, path) != 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_ISDSK(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  * Setting attributes on a named pipe by name is an error and
    262  * is handled in the calling functions so that they can return
    263  * the appropriate error status code (which differs by caller).
    264  */
    265 static int
    266 smb_set_by_path(smb_request_t *sr, smb_xa_t *xa,
    267     uint16_t infolev, char *path)
    268 {
    269 	int rc;
    270 	smb_setinfo_t sinfo;
    271 	smb_node_t *node, *dnode;
    272 	char *name;
    273 
    274 	if (SMB_TREE_IS_READONLY(sr)) {
    275 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
    276 		    ERRDOS, ERROR_ACCESS_DENIED);
    277 		return (-1);
    278 	}
    279 
    280 	name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
    281 	rc = smb_pathname_reduce(sr, sr->user_cr, path,
    282 	    sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, name);
    283 	if (rc == 0) {
    284 		rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
    285 		    sr->tid_tree->t_snode, dnode, name, &node);
    286 		smb_node_release(dnode);
    287 	}
    288 	kmem_free(name, MAXNAMELEN);
    289 
    290 	if (rc != 0) {
    291 		if (rc == ENOENT) {
    292 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
    293 			    ERRDOS, ERROR_FILE_NOT_FOUND);
    294 		} else {
    295 			smbsr_errno(sr, rc);
    296 		}
    297 		return (-1);
    298 	}
    299 
    300 	/* Break any conflicting oplock for subsequent attribute setting */
    301 	if (smb_oplock_conflict(node, sr->session, NULL)) {
    302 		(void) smb_oplock_break(node, sr->session, B_FALSE);
    303 	}
    304 
    305 	sinfo.si_xa = xa;
    306 	sinfo.si_infolev = infolev;
    307 	sinfo.si_node = node;
    308 	rc = smb_set_fileinfo(sr, &sinfo);
    309 
    310 	smb_node_release(node);
    311 	return (rc);
    312 }
    313 
    314 /*
    315  * smb_set_fileinfo
    316  *
    317  * For compatibility with windows servers, SMB_FILE_LINK_INFORMATION
    318  * is handled by returning NT_STATUS_NOT_SUPPORTED.
    319  */
    320 static int
    321 smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo)
    322 {
    323 	switch (sinfo->si_infolev) {
    324 	case SMB_SET_INFORMATION:
    325 		return (smb_set_information(sr, sinfo));
    326 
    327 	case SMB_SET_INFORMATION2:
    328 		return (smb_set_information2(sr, sinfo));
    329 
    330 	case SMB_INFO_STANDARD:
    331 		return (smb_set_standard_info(sr, sinfo));
    332 
    333 	case SMB_INFO_SET_EAS:
    334 		/* EAs not supported */
    335 		return (0);
    336 
    337 	case SMB_SET_FILE_BASIC_INFO:
    338 	case SMB_FILE_BASIC_INFORMATION:
    339 		return (smb_set_basic_info(sr, sinfo));
    340 
    341 	case SMB_SET_FILE_DISPOSITION_INFO:
    342 	case SMB_FILE_DISPOSITION_INFORMATION:
    343 		return (smb_set_disposition_info(sr, sinfo));
    344 
    345 	case SMB_SET_FILE_END_OF_FILE_INFO:
    346 	case SMB_FILE_END_OF_FILE_INFORMATION:
    347 		return (smb_set_eof_info(sr, sinfo));
    348 
    349 	case SMB_SET_FILE_ALLOCATION_INFO:
    350 	case SMB_FILE_ALLOCATION_INFORMATION:
    351 		return (smb_set_alloc_info(sr, sinfo));
    352 
    353 	case SMB_FILE_RENAME_INFORMATION:
    354 		return (smb_set_rename_info(sr, sinfo));
    355 
    356 	case SMB_FILE_LINK_INFORMATION:
    357 		smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
    358 		    ERRDOS, ERROR_NOT_SUPPORTED);
    359 		return (-1);
    360 	default:
    361 		break;
    362 	}
    363 
    364 	smbsr_error(sr, NT_STATUS_INVALID_INFO_CLASS,
    365 	    ERRDOS, ERROR_INVALID_PARAMETER);
    366 	return (-1);
    367 }
    368 
    369 /*
    370  * smb_set_information
    371  *
    372  * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
    373  * target is not a directory.
    374  *
    375  * For compatibility with Windows Servers, if the specified
    376  * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change
    377  * the file's attributes.
    378  */
    379 static int
    380 smb_set_information(smb_request_t *sr, smb_setinfo_t *sinfo)
    381 {
    382 	int rc;
    383 	uint16_t attributes;
    384 	smb_node_t *node = sinfo->si_node;
    385 	smb_attr_t attr;
    386 	uint32_t mtime;
    387 
    388 	if (smbsr_decode_vwv(sr, "wl10.", &attributes, &mtime) != 0)
    389 		return (-1);
    390 
    391 	if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
    392 	    (!smb_node_is_dir(node))) {
    393 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
    394 		    ERRDOS, ERROR_INVALID_PARAMETER);
    395 		return (-1);
    396 	}
    397 
    398 	bzero(&attr, sizeof (smb_attr_t));
    399 	if (attributes != FILE_ATTRIBUTE_NORMAL) {
    400 		attr.sa_dosattr = attributes;
    401 		attr.sa_mask |= SMB_AT_DOSATTR;
    402 	}
    403 
    404 	if (mtime != 0 && mtime != UINT_MAX) {
    405 		attr.sa_vattr.va_mtime.tv_sec =
    406 		    smb_time_local_to_gmt(sr, mtime);
    407 		attr.sa_mask |= SMB_AT_MTIME;
    408 	}
    409 
    410 	rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
    411 	if (rc != 0) {
    412 		smbsr_errno(sr, rc);
    413 		return (-1);
    414 	}
    415 
    416 	return (0);
    417 }
    418 
    419 /*
    420  * smb_set_information2
    421  */
    422 static int
    423 smb_set_information2(smb_request_t *sr, smb_setinfo_t *sinfo)
    424 {
    425 	int rc;
    426 	uint32_t crtime, atime, mtime;
    427 	smb_attr_t attr;
    428 
    429 	if (smbsr_decode_vwv(sr, "yyy", &crtime, &atime, &mtime) != 0)
    430 		return (-1);
    431 
    432 	bzero(&attr, sizeof (smb_attr_t));
    433 	if (mtime != 0 && mtime != UINT_MAX) {
    434 		attr.sa_vattr.va_mtime.tv_sec =
    435 		    smb_time_local_to_gmt(sr, mtime);
    436 		attr.sa_mask |= SMB_AT_MTIME;
    437 	}
    438 
    439 	if (crtime != 0 && crtime != UINT_MAX) {
    440 		attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
    441 		attr.sa_mask |= SMB_AT_CRTIME;
    442 	}
    443 
    444 	if (atime != 0 && atime != UINT_MAX) {
    445 		attr.sa_vattr.va_atime.tv_sec =
    446 		    smb_time_local_to_gmt(sr, atime);
    447 		attr.sa_mask |= SMB_AT_ATIME;
    448 	}
    449 
    450 	rc = smb_node_setattr(sr, sinfo->si_node, sr->user_cr,
    451 	    sr->fid_ofile, &attr);
    452 	if (rc != 0) {
    453 		smbsr_errno(sr, rc);
    454 		return (-1);
    455 	}
    456 
    457 	return (0);
    458 }
    459 
    460 /*
    461  * smb_set_standard_info
    462  *
    463  * Sets standard file/path information.
    464  */
    465 static int
    466 smb_set_standard_info(smb_request_t *sr, smb_setinfo_t *sinfo)
    467 {
    468 	smb_attr_t attr;
    469 	uint32_t crtime, atime, mtime;
    470 	smb_node_t *node = sinfo->si_node;
    471 	int rc;
    472 
    473 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "yyy",
    474 	    &crtime, &atime, &mtime) != 0) {
    475 		return (-1);
    476 	}
    477 
    478 	bzero(&attr, sizeof (smb_attr_t));
    479 	if (mtime != 0 && mtime != (uint32_t)-1) {
    480 		attr.sa_vattr.va_mtime.tv_sec =
    481 		    smb_time_local_to_gmt(sr, mtime);
    482 		attr.sa_mask |= SMB_AT_MTIME;
    483 	}
    484 
    485 	if (crtime != 0 && crtime != (uint32_t)-1) {
    486 		attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
    487 		attr.sa_mask |= SMB_AT_CRTIME;
    488 	}
    489 
    490 	if (atime != 0 && atime != (uint32_t)-1) {
    491 		attr.sa_vattr.va_atime.tv_sec =
    492 		    smb_time_local_to_gmt(sr, atime);
    493 		attr.sa_mask |= SMB_AT_ATIME;
    494 	}
    495 
    496 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
    497 	if (rc != 0) {
    498 		smbsr_errno(sr, rc);
    499 		return (-1);
    500 	}
    501 
    502 	return (0);
    503 }
    504 
    505 /*
    506  * smb_set_basic_info
    507  *
    508  * Sets basic file/path information.
    509  *
    510  * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
    511  * target is not a directory.
    512  *
    513  * For compatibility with windows servers:
    514  * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
    515  *   clear (0) the file's attributes.
    516  * - if the specified attributes are 0 do NOT change the file's attributes.
    517  */
    518 static int
    519 smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *sinfo)
    520 {
    521 	int rc;
    522 	uint64_t crtime, atime, mtime, ctime;
    523 	uint16_t attributes;
    524 	smb_attr_t attr;
    525 	smb_node_t *node = sinfo->si_node;
    526 
    527 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "qqqqw",
    528 	    &crtime, &atime, &mtime, &ctime, &attributes) != 0) {
    529 		return (-1);
    530 	}
    531 
    532 	if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
    533 	    (!smb_node_is_dir(node))) {
    534 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
    535 		    ERRDOS, ERROR_INVALID_PARAMETER);
    536 		return (-1);
    537 	}
    538 
    539 	bzero(&attr, sizeof (smb_attr_t));
    540 	if (ctime != 0 && ctime != (uint64_t)-1) {
    541 		smb_time_nt_to_unix(ctime, &attr.sa_vattr.va_ctime);
    542 		attr.sa_mask |= SMB_AT_CTIME;
    543 	}
    544 
    545 	if (crtime != 0 && crtime != (uint64_t)-1) {
    546 		smb_time_nt_to_unix(crtime, &attr.sa_crtime);
    547 		attr.sa_mask |= SMB_AT_CRTIME;
    548 	}
    549 
    550 	if (mtime != 0 && mtime != (uint64_t)-1) {
    551 		smb_time_nt_to_unix(mtime, &attr.sa_vattr.va_mtime);
    552 		attr.sa_mask |= SMB_AT_MTIME;
    553 	}
    554 
    555 	if (atime != 0 && atime != (uint64_t)-1) {
    556 		smb_time_nt_to_unix(atime, &attr.sa_vattr.va_atime);
    557 		attr.sa_mask |= SMB_AT_ATIME;
    558 	}
    559 
    560 	if (attributes != 0) {
    561 		attr.sa_dosattr = attributes;
    562 		attr.sa_mask |= SMB_AT_DOSATTR;
    563 	}
    564 
    565 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
    566 	if (rc != 0) {
    567 		smbsr_errno(sr, rc);
    568 		return (-1);
    569 	}
    570 
    571 	return (0);
    572 }
    573 
    574 /*
    575  * smb_set_eof_info
    576  */
    577 static int
    578 smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *sinfo)
    579 {
    580 	int rc;
    581 	smb_attr_t attr;
    582 	uint64_t eof;
    583 	smb_node_t *node = sinfo->si_node;
    584 
    585 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &eof) != 0)
    586 		return (-1);
    587 
    588 	if (smb_node_is_dir(node)) {
    589 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
    590 		    ERRDOS, ERROR_INVALID_PARAMETER);
    591 		return (-1);
    592 	}
    593 
    594 	bzero(&attr, sizeof (smb_attr_t));
    595 	attr.sa_mask = SMB_AT_SIZE;
    596 	attr.sa_vattr.va_size = (u_offset_t)eof;
    597 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
    598 	if (rc != 0) {
    599 		smbsr_errno(sr, rc);
    600 		return (-1);
    601 	}
    602 
    603 	return (0);
    604 }
    605 
    606 /*
    607  * smb_set_alloc_info
    608  */
    609 static int
    610 smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *sinfo)
    611 {
    612 	int rc;
    613 	smb_attr_t attr;
    614 	uint64_t allocsz;
    615 	smb_node_t *node = sinfo->si_node;
    616 
    617 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &allocsz) != 0)
    618 		return (-1);
    619 
    620 	if (smb_node_is_dir(node)) {
    621 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
    622 		    ERRDOS, ERROR_INVALID_PARAMETER);
    623 		return (-1);
    624 	}
    625 
    626 	bzero(&attr, sizeof (smb_attr_t));
    627 	attr.sa_mask = SMB_AT_ALLOCSZ;
    628 	attr.sa_allocsz = (u_offset_t)allocsz;
    629 	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
    630 	if (rc != 0) {
    631 		smbsr_errno(sr, rc);
    632 		return (-1);
    633 	}
    634 
    635 	return (0);
    636 }
    637 
    638 /*
    639  * smb_set_disposition_info
    640  *
    641  * Set/Clear DELETE_ON_CLOSE flag for an open file.
    642  * File should have been opened with DELETE access otherwise
    643  * the operation is not permitted.
    644  *
    645  * NOTE: The node should be marked delete-on-close upon the receipt
    646  * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
    647  * It is different than both SmbNtCreateAndX and SmbNtTransact, which
    648  * set delete-on-close on the ofile and defer setting the flag on the
    649  * node until the file is closed.
    650  *
    651  * Observation of Windows 2000 indicates the following:
    652  *
    653  * 1) If a file is not opened with delete-on-close create options and
    654  * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
    655  * using that open file handle, any subsequent open requests will fail
    656  * with DELETE_PENDING.
    657  *
    658  * 2) If a file is opened with delete-on-close create options and the
    659  * client attempts to unset delete-on-close via Trans2SetFileInfo
    660  * (SetDispositionInfo) prior to the file close, any subsequent open
    661  * requests will still fail with DELETE_PENDING after the file is closed.
    662  *
    663  * 3) If a file is opened with delete-on-close create options and that
    664  * file handle (not the last open handle and the only file handle
    665  * with delete-on-close set) is closed. Any subsequent open requests
    666  * will fail with DELETE_PENDING. Unsetting delete-on-close via
    667  * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
    668  * node delete-on-close flag, which will result in the file not being
    669  * removed even after the last file handle is closed.
    670  */
    671 static int
    672 smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *sinfo)
    673 {
    674 	unsigned char	mark_delete;
    675 	uint32_t	flags = 0;
    676 
    677 	if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "b", &mark_delete) != 0)
    678 		return (-1);
    679 
    680 	if ((sr->fid_ofile == NULL) ||
    681 	    !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
    682 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
    683 		    ERRDOS, ERROR_ACCESS_DENIED);
    684 		return (-1);
    685 	}
    686 
    687 	if (mark_delete) {
    688 		if (SMB_TREE_SUPPORTS_CATIA(sr))
    689 			flags |= SMB_CATIA;
    690 
    691 		if (smb_node_set_delete_on_close(sinfo->si_node,
    692 		    sr->user_cr, flags)) {
    693 			smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
    694 			    ERRDOS, ERROR_ACCESS_DENIED);
    695 			return (-1);
    696 		}
    697 	} else {
    698 		smb_node_reset_delete_on_close(sinfo->si_node);
    699 	}
    700 	return (0);
    701 }
    702 
    703 /*
    704  * smb_set_rename_info
    705  *
    706  * Explicity specified parameter validation rules:
    707  * - If rootdir is not NULL respond with NT_STATUS_INVALID_PARAMETER.
    708  * - If the filename contains a separator character respond with
    709  *   NT_STATUS_INVALID_PARAMETER.
    710  */
    711 static int
    712 smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *sinfo)
    713 {
    714 	int rc;
    715 	uint32_t flags, rootdir, namelen;
    716 	char *fname;
    717 
    718 	rc = smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "lll",
    719 	    &flags, &rootdir, &namelen);
    720 	if (rc == 0) {
    721 		rc = smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "%#U",
    722 		    sr, namelen, &fname);
    723 	}
    724 	if (rc != 0)
    725 		return (-1);
    726 
    727 	if ((rootdir != 0) || (namelen == 0) || (namelen >= MAXNAMELEN)) {
    728 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
    729 		    ERRDOS, ERROR_INVALID_PARAMETER);
    730 		return (-1);
    731 	}
    732 
    733 	if (strchr(fname, '\\') != NULL) {
    734 		smbsr_error(sr, NT_STATUS_NOT_SUPPORTED,
    735 		    ERRDOS, ERROR_NOT_SUPPORTED);
    736 		return (-1);
    737 	}
    738 
    739 	rc = smb_trans2_rename(sr, sinfo->si_node, fname, flags);
    740 
    741 	return ((rc == 0) ? 0 : -1);
    742 }
    743