15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 22*5772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw #include <sys/sdt.h> 295331Samw #include <smbsrv/smb_incl.h> 305331Samw #include <smbsrv/smb_fsops.h> 315331Samw #include <smbsrv/mbuf.h> 325331Samw #include <smbsrv/netbios.h> 335331Samw 345331Samw 355331Samw #define SMB_WRMODE_WRITE_THRU 0x0001 365331Samw #define SMB_WRMODE_IS_STABLE(M) ((M) & SMB_WRMODE_WRITE_THRU) 375331Samw 385331Samw 395331Samw typedef struct smb_write_param { 405331Samw struct vardata_block w_vdb; 415331Samw uint64_t w_offset; 425331Samw uint16_t w_mode; 435331Samw uint16_t w_count; 445331Samw } smb_write_param_t; 455331Samw 465331Samw 475331Samw int smb_write_common(struct smb_request *sr, smb_write_param_t *param); 485331Samw int smb_write_truncate(struct smb_request *sr, smb_write_param_t *param); 495331Samw int smb_set_file_size(struct smb_request *sr); 505331Samw 515331Samw 525331Samw /* 535331Samw * Write count bytes at the specified offset in a file. The offset is 545331Samw * limited to 32-bits. If the count is zero, the file is truncated to 555331Samw * the length specified by the offset. 565331Samw * 575331Samw * The response count indicates the actual number of bytes written, which 585331Samw * will equal the requested count on success. If request and response 595331Samw * counts differ but there is no error, the client will assume that the 605331Samw * server encountered a resource issue. 615331Samw */ 625331Samw int 635331Samw smb_com_write(struct smb_request *sr) 645331Samw { 655331Samw smb_write_param_t *param; 665331Samw uint32_t off; 675331Samw int rc; 685331Samw 695331Samw param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP); 705331Samw 715331Samw rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, ¶m->w_count, &off); 725331Samw if (rc != 0) { 735331Samw kmem_free(param, sizeof (smb_write_param_t)); 745331Samw smbsr_decode_error(sr); 755331Samw /* NOTREACHED */ 765331Samw } 775331Samw 785331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 795331Samw if (sr->fid_ofile == NULL) { 805331Samw kmem_free(param, sizeof (smb_write_param_t)); 81*5772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 825331Samw /* NOTREACHED */ 835331Samw } 845331Samw 855331Samw param->w_offset = (uint64_t)off; 865521Sas200622 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 875331Samw 885331Samw if (param->w_count == 0) { 895331Samw rc = smb_write_truncate(sr, param); 905331Samw } else { 915331Samw rc = smbsr_decode_data(sr, "D", ¶m->w_vdb); 925331Samw 935331Samw if ((rc != 0) || (param->w_vdb.len != param->w_count)) { 945331Samw kmem_free(param, sizeof (smb_write_param_t)); 955331Samw smbsr_decode_error(sr); 965331Samw /* NOTREACHED */ 975331Samw } 985331Samw 995521Sas200622 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 1005331Samw 1015331Samw rc = smb_write_common(sr, param); 1025331Samw } 1035331Samw 1045331Samw if (rc != 0) { 1055331Samw kmem_free(param, sizeof (smb_write_param_t)); 106*5772Sas200622 smbsr_errno(sr, rc); 1075331Samw /* NOTREACHED */ 1085331Samw } 1095331Samw 1105331Samw smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0); 1115331Samw kmem_free(param, sizeof (smb_write_param_t)); 1125331Samw return (SDRC_NORMAL_REPLY); 1135331Samw } 1145331Samw 1155331Samw /* 1165331Samw * Write count bytes to a file and then close the file. This function 1175331Samw * can only be used to write to 32-bit offsets and the client must set 1185331Samw * WordCount (6 or 12) correctly in order to locate the data to be 1195331Samw * written. If an error occurs on the write, the file should still be 1205331Samw * closed. If Count is 0, the file is truncated (or extended) to offset. 1215331Samw * 1225331Samw * If the last_write time is non-zero, last_write should be used to set 1235331Samw * the mtime. Otherwise the file system stamps the mtime. Failure to 1245331Samw * set mtime should not result in an error response. 1255331Samw */ 1265331Samw int 1275331Samw smb_com_write_and_close(struct smb_request *sr) 1285331Samw { 1295331Samw smb_write_param_t *param; 1305331Samw uint32_t last_write; 1315331Samw uint32_t off; 1325331Samw int rc = 0; 1335331Samw 1345331Samw param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP); 1355331Samw 1365331Samw if (sr->smb_wct == 12) { 1375331Samw rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, 1385331Samw ¶m->w_count, &off, &last_write); 1395331Samw } else { 1405331Samw rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 1415331Samw ¶m->w_count, &off, &last_write); 1425331Samw } 1435331Samw 1445331Samw if (rc != 0) { 1455331Samw kmem_free(param, sizeof (smb_write_param_t)); 1465331Samw smbsr_decode_error(sr); 1475331Samw /* NOTREACHED */ 1485331Samw } 1495331Samw 1505331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 1515331Samw if (sr->fid_ofile == NULL) { 1525331Samw kmem_free(param, sizeof (smb_write_param_t)); 153*5772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 1545331Samw /* NOTREACHED */ 1555331Samw } 1565331Samw 1575331Samw param->w_offset = (uint64_t)off; 1585331Samw 1595331Samw if (param->w_count == 0) { 1605331Samw rc = smb_write_truncate(sr, param); 1615331Samw } else { 1625331Samw /* 1635331Samw * There may be a bug here: should this be "3.#B"? 1645331Samw */ 1655331Samw rc = smbsr_decode_data(sr, ".#B", param->w_count, 1665331Samw ¶m->w_vdb); 1675331Samw 1685331Samw if ((rc != 0) || (param->w_vdb.len != param->w_count)) { 1695331Samw kmem_free(param, sizeof (smb_write_param_t)); 1705331Samw smbsr_decode_error(sr); 1715331Samw /* NOTREACHED */ 1725331Samw } 1735331Samw 1745521Sas200622 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 1755331Samw 1765331Samw rc = smb_write_common(sr, param); 1775331Samw } 1785331Samw 1795331Samw if (rc != 0) { 1805331Samw kmem_free(param, sizeof (smb_write_param_t)); 181*5772Sas200622 smbsr_errno(sr, rc); 1825331Samw /* NOTREACHED */ 1835331Samw } 1845331Samw 1855331Samw if ((rc = smb_common_close(sr, last_write)) != 0) { 1865331Samw kmem_free(param, sizeof (smb_write_param_t)); 187*5772Sas200622 smbsr_errno(sr, rc); 1885331Samw /* NOTREACHED */ 1895331Samw } 1905331Samw 1915331Samw smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0); 1925331Samw kmem_free(param, sizeof (smb_write_param_t)); 1935331Samw return (SDRC_NORMAL_REPLY); 1945331Samw } 1955331Samw 1965331Samw /* 1975331Samw * Write count bytes to a file at the specified offset and then unlock 1985331Samw * them. Write behind is safe because the client should have the range 1995331Samw * locked and this request is allowed to extend the file - note that 2005331Samw * offest is limited to 32-bits. It is an error for count to be zero. 2015331Samw * 2025331Samw * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 2035331Samw * files. Reject any attempt to use it on other shares. 2045331Samw * 2055331Samw * The response count indicates the actual number of bytes written, which 2065331Samw * will equal the requested count on success. If request and response 2075331Samw * counts differ but there is no error, the client will assume that the 2085331Samw * server encountered a resource issue. 2095331Samw */ 2105331Samw int 2115331Samw smb_com_write_and_unlock(struct smb_request *sr) 2125331Samw { 2135331Samw smb_write_param_t *param; 2145331Samw uint32_t off; 2155331Samw uint32_t result; 2165331Samw uint16_t remcnt; 2175331Samw int rc = 0; 2185331Samw 2195331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 220*5772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 2215331Samw /* NOTREACHED */ 2225331Samw } 2235331Samw 2245331Samw param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP); 2255331Samw 2265331Samw rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, ¶m->w_count, &off, 2275331Samw &remcnt); 2285331Samw if (rc != 0) { 2295331Samw kmem_free(param, sizeof (smb_write_param_t)); 2305331Samw smbsr_decode_error(sr); 2315331Samw /* NOTREACHED */ 2325331Samw } 2335331Samw 2345331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 2355331Samw if (sr->fid_ofile == NULL) { 2365331Samw kmem_free(param, sizeof (smb_write_param_t)); 237*5772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 2385331Samw /* NOTREACHED */ 2395331Samw } 2405331Samw 2415331Samw if (param->w_count == 0) { 2425331Samw smbsr_decode_error(sr); 2435331Samw /* NOTREACHED */ 2445331Samw } 2455331Samw 2465331Samw rc = smbsr_decode_data(sr, "D", ¶m->w_vdb); 2475331Samw 2485331Samw if ((rc != 0) || (param->w_count != param->w_vdb.len)) { 2495331Samw kmem_free(param, sizeof (smb_write_param_t)); 2505331Samw smbsr_decode_error(sr); 2515331Samw /* NOTREACHED */ 2525331Samw } 2535331Samw 2545331Samw param->w_offset = (uint64_t)off; 2555521Sas200622 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 2565331Samw 2575331Samw if ((rc = smb_write_common(sr, param)) != 0) { 2585331Samw kmem_free(param, sizeof (smb_write_param_t)); 259*5772Sas200622 smbsr_errno(sr, rc); 2605331Samw /* NOTREACHED */ 2615331Samw } 2625331Samw 2635331Samw result = smb_unlock_range(sr, sr->fid_ofile->f_node, param->w_offset, 2645331Samw (uint64_t)param->w_count); 2655331Samw if (result != NT_STATUS_SUCCESS) { 2665331Samw kmem_free(param, sizeof (smb_write_param_t)); 267*5772Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 268*5772Sas200622 ERRDOS, ERRnotlocked); 2695331Samw /* NOTREACHED */ 2705331Samw } 2715331Samw 2725331Samw smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0); 2735331Samw kmem_free(param, sizeof (smb_write_param_t)); 2745331Samw return (SDRC_NORMAL_REPLY); 2755331Samw } 2765331Samw 2775331Samw /* 2785331Samw * Write bytes to a file (SMB Core). This request was extended in 2795331Samw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 2805331Samw * 14, instead of 12, and including additional offset information. 2815331Samw * 2825331Samw * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 2835331Samw * to truncate a file. A zero length merely transfers zero bytes. 2845331Samw * 2855331Samw * If bit 0 of WriteMode is set, Fid must refer to a disk file and 2865331Samw * the data must be on stable storage before responding. 2875331Samw */ 2885331Samw int 2895331Samw smb_com_write_andx(struct smb_request *sr) 2905331Samw { 2915331Samw smb_write_param_t *param; 2925331Samw uint32_t off_low; 2935331Samw uint32_t off_high; 2945331Samw uint16_t data_offset; 2955331Samw uint16_t remcnt; 2965331Samw int rc = 0; 2975331Samw 2985331Samw param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP); 2995331Samw 3005331Samw if (sr->smb_wct == 14) { 3015331Samw rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid, 3025331Samw &off_low, ¶m->w_mode, &remcnt, ¶m->w_count, 3035331Samw &data_offset, &off_high); 3045331Samw 3055331Samw data_offset -= 63; 3065331Samw param->w_offset = ((uint64_t)off_high << 32) | off_low; 3075331Samw } else { 3085331Samw rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid, 3095331Samw &off_low, ¶m->w_mode, &remcnt, ¶m->w_count, 3105331Samw &data_offset); 3115331Samw 3125331Samw param->w_offset = (uint64_t)off_low; 3135331Samw data_offset -= 59; 3145331Samw } 3155331Samw 3165331Samw if (rc != 0) { 3175331Samw kmem_free(param, sizeof (smb_write_param_t)); 3185331Samw smbsr_decode_error(sr); 3195331Samw /* NOTREACHED */ 3205331Samw } 3215331Samw 3225331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 3235331Samw if (sr->fid_ofile == NULL) { 3245331Samw kmem_free(param, sizeof (smb_write_param_t)); 325*5772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 3265331Samw /* NOTREACHED */ 3275331Samw } 3285331Samw 3295331Samw if (SMB_WRMODE_IS_STABLE(param->w_mode) && 3305331Samw STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 3315331Samw kmem_free(param, sizeof (smb_write_param_t)); 332*5772Sas200622 smbsr_error(sr, 0, ERRSRV, ERRaccess); 3335331Samw /* NOTREACHED */ 3345331Samw } 3355331Samw 3365331Samw rc = smbsr_decode_data(sr, "#.#B", data_offset, param->w_count, 3375331Samw ¶m->w_vdb); 3385331Samw if ((rc != 0) || (param->w_vdb.len != param->w_count)) { 3395331Samw kmem_free(param, sizeof (smb_write_param_t)); 3405331Samw smbsr_decode_error(sr); 3415331Samw /* NOTREACHED */ 3425331Samw } 3435331Samw 3445521Sas200622 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 3455331Samw 3465331Samw if (param->w_count != 0) { 3475331Samw if ((rc = smb_write_common(sr, param)) != 0) { 3485331Samw kmem_free(param, sizeof (smb_write_param_t)); 349*5772Sas200622 smbsr_errno(sr, rc); 3505331Samw /* NOTREACHED */ 3515331Samw } 3525331Samw } 3535331Samw 3545331Samw smbsr_encode_result(sr, 6, 0, "bb1.ww6.w", 3555331Samw 6, sr->andx_com, 15, param->w_count, 0); 3565331Samw 3575331Samw kmem_free(param, sizeof (smb_write_param_t)); 3585331Samw return (SDRC_NORMAL_REPLY); 3595331Samw } 3605331Samw 3615331Samw /* 3625331Samw * Common function for writing files or IPC/MSRPC named pipes. 3635331Samw * 3645331Samw * Returns errno values. 3655331Samw */ 3665331Samw int 3675331Samw smb_write_common(struct smb_request *sr, smb_write_param_t *param) 3685331Samw { 3695331Samw struct smb_ofile *ofile = sr->fid_ofile; 3705331Samw smb_node_t *node; 3715331Samw uint32_t stability = FSSTAB_UNSTABLE; 3725331Samw uint32_t lcount; 3735331Samw int rc = 0; 3745331Samw 3755331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 3765331Samw case STYPE_DISKTREE: 3775331Samw node = ofile->f_node; 3785331Samw 3795331Samw if (node->attr.sa_vattr.va_type != VDIR) { 3805331Samw rc = smb_lock_range_access(sr, node, param->w_offset, 381*5772Sas200622 param->w_count, B_TRUE); 3825331Samw if (rc != NT_STATUS_SUCCESS) { 383*5772Sas200622 smbsr_error(sr, rc, ERRSRV, ERRaccess); 3845331Samw /* NOTREACHED */ 3855331Samw } 3865331Samw } 3875331Samw 3885331Samw if (SMB_WRMODE_IS_STABLE(param->w_mode) || 3895331Samw (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 3905331Samw stability = FSSTAB_FILE_SYNC; 3915331Samw } 3925331Samw 3935331Samw rc = smb_fsop_write(sr, sr->user_cr, node, 3945331Samw ¶m->w_vdb.uio, &lcount, &node->attr, &stability); 3955331Samw 3965331Samw if (rc) 3975331Samw return (rc); 3985331Samw 3995331Samw node->flags |= NODE_FLAGS_SYNCATIME; 4005331Samw 4015331Samw if (node->flags & NODE_FLAGS_SET_SIZE) { 4025331Samw if ((param->w_offset + lcount) >= node->n_size) { 4035331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 4045331Samw node->n_size = param->w_offset + lcount; 4055331Samw } 4065331Samw } 4075331Samw 4085331Samw param->w_count = (uint16_t)lcount; 4095331Samw break; 4105331Samw 4115331Samw case STYPE_IPC: 4125331Samw param->w_count = (uint16_t)param->w_vdb.uio.uio_resid; 4135331Samw 4145331Samw if ((rc = smb_rpc_write(sr, ¶m->w_vdb.uio)) != 0) 4155331Samw param->w_count = 0; 4165331Samw break; 4175331Samw 4185331Samw default: 4195331Samw rc = EACCES; 4205331Samw break; 4215331Samw } 4225331Samw 4235331Samw if (rc != 0) 4245331Samw return (rc); 4255331Samw 4265331Samw mutex_enter(&ofile->f_mutex); 4275331Samw ofile->f_seek_pos = param->w_offset + param->w_count; 4285331Samw mutex_exit(&ofile->f_mutex); 4295331Samw return (rc); 4305331Samw } 4315331Samw 4325331Samw /* 4335331Samw * Truncate a disk file to the specified offset. 4345331Samw * Typically, w_count will be zero here. 4355331Samw * 4365331Samw * Returns errno values. 4375331Samw */ 4385331Samw int 4395331Samw smb_write_truncate(struct smb_request *sr, smb_write_param_t *param) 4405331Samw { 4415331Samw struct smb_ofile *ofile = sr->fid_ofile; 4425331Samw smb_node_t *node = ofile->f_node; 443*5772Sas200622 boolean_t append_only = B_FALSE; 4445331Samw int rc; 4455331Samw 4465331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) 4475331Samw return (0); 4485331Samw 449*5772Sas200622 rc = smb_ofile_access(sr->fid_ofile, sr->user_cr, FILE_WRITE_DATA); 450*5772Sas200622 if (rc != NT_STATUS_SUCCESS) { 451*5772Sas200622 rc = smb_ofile_access(sr->fid_ofile, sr->user_cr, 452*5772Sas200622 FILE_APPEND_DATA); 453*5772Sas200622 if (rc != NT_STATUS_SUCCESS) { 454*5772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, 455*5772Sas200622 ERROR_ACCESS_DENIED); 456*5772Sas200622 /* NOTREACHED */ 457*5772Sas200622 } else { 458*5772Sas200622 append_only = B_TRUE; 459*5772Sas200622 } 460*5772Sas200622 } 461*5772Sas200622 462*5772Sas200622 smb_rwx_xenter(&node->n_lock); 463*5772Sas200622 464*5772Sas200622 if (append_only && (param->w_offset < node->n_size)) { 465*5772Sas200622 smb_rwx_xexit(&node->n_lock); 466*5772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 467*5772Sas200622 ERRDOS, ERRnoaccess); 468*5772Sas200622 /* NOTREACHED */ 469*5772Sas200622 } 470*5772Sas200622 4715331Samw if (node->attr.sa_vattr.va_type != VDIR) { 4725331Samw rc = smb_lock_range_access(sr, node, param->w_offset, 473*5772Sas200622 param->w_count, B_TRUE); 4745331Samw if (rc != NT_STATUS_SUCCESS) { 475*5772Sas200622 smb_rwx_xexit(&node->n_lock); 476*5772Sas200622 smbsr_error(sr, rc, ERRSRV, ERRaccess); 4775331Samw /* NOTREACHED */ 4785331Samw } 4795331Samw } 4805331Samw 4815331Samw node->flags |= NODE_FLAGS_SET_SIZE; 4825331Samw node->n_size = param->w_offset; 4835331Samw 484*5772Sas200622 smb_rwx_xexit(&node->n_lock); 485*5772Sas200622 4865331Samw if ((rc = smb_set_file_size(sr)) != 0) 4875331Samw return (rc); 4885331Samw 4895331Samw mutex_enter(&ofile->f_mutex); 4905331Samw ofile->f_seek_pos = param->w_offset + param->w_count; 4915331Samw mutex_exit(&ofile->f_mutex); 4925331Samw return (0); 4935331Samw } 4945331Samw 4955331Samw /* 4965331Samw * Set the file size using the value in the node. The file will only be 4975331Samw * updated if NODE_FLAGS_SET_SIZE is set. It is safe to pass a null node 4985331Samw * pointer, we just return success. 4995331Samw * 5005331Samw * The node attributes are refreshed here from the file system. So any 5015331Samw * attributes that are affected by file size changes, i.e. the mtime, 5025331Samw * will be current. 5035331Samw * 5045331Samw * Note that smb_write_andx cannot be used to reduce the file size so, 5055331Samw * if this is required, smb_write is called with a count of zero and 5065331Samw * the appropriate file length in offset. The file should be resized 5075331Samw * to the length specified by the offset. 5085331Samw * 5095331Samw * Returns 0 on success. Otherwise returns EACCES. 5105331Samw */ 5115331Samw int 5125331Samw smb_set_file_size(struct smb_request *sr) 5135331Samw { 5145331Samw struct smb_node *node; 5155331Samw smb_attr_t new_attr; 5165331Samw uint32_t dosattr; 5175331Samw 5185331Samw if ((node = sr->fid_ofile->f_node) == 0) 5195331Samw return (0); 5205331Samw 5215331Samw if ((node->flags & NODE_FLAGS_SET_SIZE) == 0) 5225331Samw return (0); 5235331Samw 5245331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 5255331Samw 5265331Samw dosattr = smb_node_get_dosattr(node); 5275331Samw 5285331Samw if (dosattr & SMB_FA_READONLY) { 5295331Samw if (((node->flags & NODE_FLAGS_CREATED) == 0) || 5305331Samw (sr->session->s_kid != node->n_orig_session_id)) 5315331Samw return (EACCES); 5325331Samw } 5335331Samw 5345331Samw bzero(&new_attr, sizeof (new_attr)); 5355331Samw new_attr.sa_vattr.va_size = node->n_size; 5365331Samw new_attr.sa_mask = SMB_AT_SIZE; 5375331Samw 5385331Samw (void) smb_fsop_setattr(sr, sr->user_cr, node, &new_attr, 5395331Samw &node->attr); 5405331Samw 5415331Samw return (0); 5425331Samw } 5435331Samw 5445331Samw /* 5455331Samw * write_complete is sent acknowledge completion of raw write requests. 5465331Samw * We never send raw write commands to other servers so, if we receive a 5475331Samw * write_complete, we treat it as an error. 5485331Samw */ 5495331Samw int 5505331Samw smb_com_write_complete(struct smb_request *sr) 5515331Samw { 5525331Samw smbsr_decode_error(sr); 5535331Samw /* NOT REACHED */ 5545331Samw return (0); 5555331Samw } 5565331Samw 5575331Samw /* 5585331Samw * The Write Block Multiplexed protocol is used to maximize performance 5595331Samw * when writing a large block of data. 5605331Samw * 5615331Samw * The mpx sub protocol is not supported because we support only 5625331Samw * connection oriented transports and NT supports SMB_COM_READ_MPX 5635331Samw * only over connectionless transports. 5645331Samw */ 5655331Samw int /*ARGSUSED*/ 5665331Samw smb_com_write_mpx(struct smb_request *sr) 5675331Samw { 5685331Samw return (SDRC_UNIMPLEMENTED); 5695331Samw } 5705331Samw 5715331Samw int /*ARGSUSED*/ 5725331Samw smb_com_write_mpx_secondary(struct smb_request *sr) 5735331Samw { 5745331Samw return (SDRC_UNIMPLEMENTED); 5755331Samw } 576