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 /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 26*7348SJose.Borrego@Sun.COM #pragma ident "@(#)smb_write.c 1.10 08/08/08 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 396139Sjb150015 static int smb_write_common(smb_request_t *, smb_rw_param_t *); 406139Sjb150015 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *); 415331Samw 425331Samw 435331Samw /* 445331Samw * Write count bytes at the specified offset in a file. The offset is 455331Samw * limited to 32-bits. If the count is zero, the file is truncated to 465331Samw * the length specified by the offset. 475331Samw * 485331Samw * The response count indicates the actual number of bytes written, which 495331Samw * will equal the requested count on success. If request and response 505331Samw * counts differ but there is no error, the client will assume that the 515331Samw * server encountered a resource issue. 525331Samw */ 536030Sjb150015 smb_sdrc_t 546139Sjb150015 smb_pre_write(smb_request_t *sr) 555331Samw { 566139Sjb150015 smb_rw_param_t *param; 575331Samw uint32_t off; 585331Samw int rc; 595331Samw 606139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 616139Sjb150015 sr->arg.rw = param; 626139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 636139Sjb150015 646139Sjb150015 rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, ¶m->rw_count, &off); 656139Sjb150015 666139Sjb150015 param->rw_offset = (uint64_t)off; 676139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 686139Sjb150015 696139Sjb150015 DTRACE_SMB_2(op__Write__start, smb_request_t *, sr, 706139Sjb150015 smb_rw_param_t *, param); 716139Sjb150015 726139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 736139Sjb150015 } 745331Samw 756139Sjb150015 void 766139Sjb150015 smb_post_write(smb_request_t *sr) 776139Sjb150015 { 786139Sjb150015 DTRACE_SMB_2(op__Write__done, smb_request_t *, sr, 796139Sjb150015 smb_rw_param_t *, sr->arg.rw); 806139Sjb150015 816139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 826139Sjb150015 } 836139Sjb150015 846139Sjb150015 smb_sdrc_t 856139Sjb150015 smb_com_write(smb_request_t *sr) 866139Sjb150015 { 876139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 886139Sjb150015 int rc; 895331Samw 905331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 915331Samw if (sr->fid_ofile == NULL) { 925772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 936139Sjb150015 return (SDRC_ERROR); 945331Samw } 955331Samw 966139Sjb150015 if (param->rw_count == 0) { 975331Samw rc = smb_write_truncate(sr, param); 985331Samw } else { 996139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 1005331Samw 1016139Sjb150015 if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { 1026139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 1036139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 1046139Sjb150015 return (SDRC_ERROR); 1055331Samw } 1065331Samw 1076139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 1085331Samw 1095331Samw rc = smb_write_common(sr, param); 1105331Samw } 1115331Samw 1125331Samw if (rc != 0) { 1136139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 1146139Sjb150015 smbsr_errno(sr, rc); 1156139Sjb150015 return (SDRC_ERROR); 1165331Samw } 1175331Samw 1186139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); 1196139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1205331Samw } 1215331Samw 1225331Samw /* 1235331Samw * Write count bytes to a file and then close the file. This function 1245331Samw * can only be used to write to 32-bit offsets and the client must set 1255331Samw * WordCount (6 or 12) correctly in order to locate the data to be 1265331Samw * written. If an error occurs on the write, the file should still be 1275331Samw * closed. If Count is 0, the file is truncated (or extended) to offset. 1285331Samw * 1295331Samw * If the last_write time is non-zero, last_write should be used to set 1305331Samw * the mtime. Otherwise the file system stamps the mtime. Failure to 1315331Samw * set mtime should not result in an error response. 1325331Samw */ 1336030Sjb150015 smb_sdrc_t 1346139Sjb150015 smb_pre_write_and_close(smb_request_t *sr) 1355331Samw { 1366139Sjb150015 smb_rw_param_t *param; 1375331Samw uint32_t off; 1386139Sjb150015 int rc; 1395331Samw 1406139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 1416139Sjb150015 sr->arg.rw = param; 1426139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 1435331Samw 1445331Samw if (sr->smb_wct == 12) { 1455331Samw rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, 1466139Sjb150015 ¶m->rw_count, &off, ¶m->rw_last_write); 1475331Samw } else { 1485331Samw rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 1496139Sjb150015 ¶m->rw_count, &off, ¶m->rw_last_write); 1505331Samw } 1515331Samw 1526139Sjb150015 param->rw_offset = (uint64_t)off; 1536139Sjb150015 1546139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr, 1556139Sjb150015 smb_rw_param_t *, param); 1566139Sjb150015 1576139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1586139Sjb150015 } 1596139Sjb150015 1606139Sjb150015 void 1616139Sjb150015 smb_post_write_and_close(smb_request_t *sr) 1626139Sjb150015 { 1636139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr, 1646139Sjb150015 smb_rw_param_t *, sr->arg.rw); 1656139Sjb150015 1666139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 1676139Sjb150015 } 1686139Sjb150015 1696139Sjb150015 smb_sdrc_t 1706139Sjb150015 smb_com_write_and_close(smb_request_t *sr) 1716139Sjb150015 { 1726139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 1736139Sjb150015 int rc = 0; 1745331Samw 1755331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 1765331Samw if (sr->fid_ofile == NULL) { 1775772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 1786139Sjb150015 return (SDRC_ERROR); 1795331Samw } 1805331Samw 1816139Sjb150015 if (param->rw_count == 0) { 1825331Samw rc = smb_write_truncate(sr, param); 1835331Samw } else { 1845331Samw /* 1855331Samw * There may be a bug here: should this be "3.#B"? 1865331Samw */ 1876139Sjb150015 rc = smbsr_decode_data(sr, ".#B", param->rw_count, 1886139Sjb150015 ¶m->rw_vdb); 1895331Samw 1906139Sjb150015 if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { 1916139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 1926139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 1936139Sjb150015 return (SDRC_ERROR); 1945331Samw } 1955331Samw 1966139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 1975331Samw 1985331Samw rc = smb_write_common(sr, param); 1995331Samw } 2005331Samw 2015331Samw if (rc != 0) { 2026139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 2036139Sjb150015 smbsr_errno(sr, rc); 2046139Sjb150015 return (SDRC_ERROR); 2055331Samw } 2065331Samw 207*7348SJose.Borrego@Sun.COM smb_ofile_close(sr->fid_ofile, param->rw_last_write); 2085331Samw 2096139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); 2106139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2115331Samw } 2125331Samw 2135331Samw /* 2145331Samw * Write count bytes to a file at the specified offset and then unlock 2155331Samw * them. Write behind is safe because the client should have the range 2165331Samw * locked and this request is allowed to extend the file - note that 2176139Sjb150015 * offset is limited to 32-bits. 2186139Sjb150015 * 2196139Sjb150015 * Spec advice: it is an error for count to be zero. For compatibility, 2206139Sjb150015 * we take no action and return success. 2215331Samw * 2225331Samw * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 2235331Samw * files. Reject any attempt to use it on other shares. 2245331Samw * 2255331Samw * The response count indicates the actual number of bytes written, which 2265331Samw * will equal the requested count on success. If request and response 2275331Samw * counts differ but there is no error, the client will assume that the 2285331Samw * server encountered a resource issue. 2295331Samw */ 2306030Sjb150015 smb_sdrc_t 2316139Sjb150015 smb_pre_write_and_unlock(smb_request_t *sr) 2325331Samw { 2336139Sjb150015 smb_rw_param_t *param; 2345331Samw uint32_t off; 2355331Samw uint16_t remcnt; 2366139Sjb150015 int rc; 2376139Sjb150015 2386139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 2396139Sjb150015 sr->arg.rw = param; 2406139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 2416139Sjb150015 2426139Sjb150015 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, ¶m->rw_count, &off, 2436139Sjb150015 &remcnt); 2446139Sjb150015 2456139Sjb150015 param->rw_offset = (uint64_t)off; 2466139Sjb150015 2476139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr, 2486139Sjb150015 smb_rw_param_t *, param); 2496139Sjb150015 2506139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2516139Sjb150015 } 2526139Sjb150015 2536139Sjb150015 void 2546139Sjb150015 smb_post_write_and_unlock(smb_request_t *sr) 2556139Sjb150015 { 2566139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr, 2576139Sjb150015 smb_rw_param_t *, sr->arg.rw); 2586139Sjb150015 2596139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 2606139Sjb150015 } 2616139Sjb150015 2626139Sjb150015 smb_sdrc_t 2636139Sjb150015 smb_com_write_and_unlock(smb_request_t *sr) 2646139Sjb150015 { 2656139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 2666139Sjb150015 uint32_t status; 2675331Samw int rc = 0; 2685331Samw 2695331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 2705772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 2716139Sjb150015 return (SDRC_ERROR); 2725331Samw } 2735331Samw 2745331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 2755331Samw if (sr->fid_ofile == NULL) { 2765772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 2776139Sjb150015 return (SDRC_ERROR); 2785331Samw } 2795331Samw 2806139Sjb150015 if (param->rw_count == 0) { 2816139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0); 2826139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2835331Samw } 2845331Samw 2856139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 2865331Samw 2876139Sjb150015 if ((rc != 0) || (param->rw_count != param->rw_vdb.len)) { 2886139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 2896139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 2906139Sjb150015 return (SDRC_ERROR); 2915331Samw } 2925331Samw 2936139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 2945331Samw 2955331Samw if ((rc = smb_write_common(sr, param)) != 0) { 2966139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 2976139Sjb150015 smbsr_errno(sr, rc); 2986139Sjb150015 return (SDRC_ERROR); 2995331Samw } 3005331Samw 3016139Sjb150015 status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset, 3026139Sjb150015 (uint64_t)param->rw_count); 3036139Sjb150015 if (status != NT_STATUS_SUCCESS) { 3045772Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 3055772Sas200622 ERRDOS, ERRnotlocked); 3066139Sjb150015 return (SDRC_ERROR); 3075331Samw } 3085331Samw 3096139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); 3106139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3115331Samw } 3125331Samw 3135331Samw /* 3145331Samw * Write bytes to a file (SMB Core). This request was extended in 3155331Samw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 3165331Samw * 14, instead of 12, and including additional offset information. 3175331Samw * 3185331Samw * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 3195331Samw * to truncate a file. A zero length merely transfers zero bytes. 3205331Samw * 3215331Samw * If bit 0 of WriteMode is set, Fid must refer to a disk file and 3225331Samw * the data must be on stable storage before responding. 3235331Samw */ 3246030Sjb150015 smb_sdrc_t 3256139Sjb150015 smb_pre_write_andx(smb_request_t *sr) 3265331Samw { 3276139Sjb150015 smb_rw_param_t *param; 3285331Samw uint32_t off_low; 3295331Samw uint32_t off_high; 3305331Samw uint16_t remcnt; 3316139Sjb150015 int rc; 3325331Samw 3336139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 3346139Sjb150015 sr->arg.rw = param; 3356139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 3365331Samw 3375331Samw if (sr->smb_wct == 14) { 3385331Samw rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid, 3396139Sjb150015 &off_low, ¶m->rw_mode, &remcnt, ¶m->rw_count, 3406139Sjb150015 ¶m->rw_dsoff, &off_high); 3415331Samw 3426139Sjb150015 param->rw_dsoff -= 63; 3436139Sjb150015 param->rw_offset = ((uint64_t)off_high << 32) | off_low; 3445331Samw } else { 3455331Samw rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid, 3466139Sjb150015 &off_low, ¶m->rw_mode, &remcnt, ¶m->rw_count, 3476139Sjb150015 ¶m->rw_dsoff); 3485331Samw 3496139Sjb150015 param->rw_offset = (uint64_t)off_low; 3506139Sjb150015 param->rw_dsoff -= 59; 3515331Samw } 3525331Samw 3536139Sjb150015 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, 3546139Sjb150015 smb_rw_param_t *, param); 3556139Sjb150015 3566139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3576139Sjb150015 } 3586139Sjb150015 3596139Sjb150015 void 3606139Sjb150015 smb_post_write_andx(smb_request_t *sr) 3616139Sjb150015 { 3626139Sjb150015 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr, 3636139Sjb150015 smb_rw_param_t *, sr->arg.rw); 3646139Sjb150015 3656139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 3666139Sjb150015 } 3676139Sjb150015 3686139Sjb150015 smb_sdrc_t 3696139Sjb150015 smb_com_write_andx(smb_request_t *sr) 3706139Sjb150015 { 3716139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 3726139Sjb150015 int rc; 3736139Sjb150015 3746139Sjb150015 ASSERT(param); 3756139Sjb150015 ASSERT(param->rw_magic == SMB_RW_MAGIC); 3765331Samw 3775331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 3785331Samw if (sr->fid_ofile == NULL) { 3795772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 3806139Sjb150015 return (SDRC_ERROR); 3815331Samw } 3825331Samw 3836139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) && 3845331Samw STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 3855772Sas200622 smbsr_error(sr, 0, ERRSRV, ERRaccess); 3866139Sjb150015 return (SDRC_ERROR); 3875331Samw } 3885331Samw 3896139Sjb150015 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, 3906139Sjb150015 ¶m->rw_vdb); 3916139Sjb150015 if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { 3926139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 3936139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 3946139Sjb150015 return (SDRC_ERROR); 3955331Samw } 3965331Samw 3976139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 3985331Samw 3996139Sjb150015 if (param->rw_count != 0) { 4005331Samw if ((rc = smb_write_common(sr, param)) != 0) { 4016139Sjb150015 if (sr->smb_error.status != 4026139Sjb150015 NT_STATUS_FILE_LOCK_CONFLICT) 4036139Sjb150015 smbsr_errno(sr, rc); 4046139Sjb150015 return (SDRC_ERROR); 4055331Samw } 4065331Samw } 4075331Samw 4086030Sjb150015 rc = smbsr_encode_result(sr, 6, 0, "bb1.ww6.w", 4096139Sjb150015 6, sr->andx_com, 15, param->rw_count, 0); 4105331Samw 4116139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 4125331Samw } 4135331Samw 4145331Samw /* 4155331Samw * Common function for writing files or IPC/MSRPC named pipes. 4165331Samw * 4175331Samw * Returns errno values. 4185331Samw */ 4196030Sjb150015 static int 4206139Sjb150015 smb_write_common(smb_request_t *sr, smb_rw_param_t *param) 4215331Samw { 4225331Samw struct smb_ofile *ofile = sr->fid_ofile; 4235331Samw smb_node_t *node; 4247052Samw int stability = 0; 4255331Samw uint32_t lcount; 4265331Samw int rc = 0; 4275331Samw 4285331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 4295331Samw case STYPE_DISKTREE: 4305331Samw node = ofile->f_node; 4315331Samw 4325331Samw if (node->attr.sa_vattr.va_type != VDIR) { 4336139Sjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset, 4346139Sjb150015 param->rw_count, B_TRUE); 4356139Sjb150015 if (rc != NT_STATUS_SUCCESS) { 4366139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 4376139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 4386139Sjb150015 return (EACCES); 4396139Sjb150015 } 4405331Samw } 4415331Samw 4426139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) || 4435331Samw (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 4447052Samw stability = FSYNC; 4455331Samw } 4465331Samw 4475331Samw rc = smb_fsop_write(sr, sr->user_cr, node, 4487052Samw ¶m->rw_vdb.uio, &lcount, &node->attr, stability); 4495331Samw 4505331Samw if (rc) 4515331Samw return (rc); 4525331Samw 4535331Samw node->flags |= NODE_FLAGS_SYNCATIME; 4545331Samw 4555331Samw if (node->flags & NODE_FLAGS_SET_SIZE) { 4566139Sjb150015 if ((param->rw_offset + lcount) >= node->n_size) { 4575331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 4586139Sjb150015 node->n_size = param->rw_offset + lcount; 4595331Samw } 4605331Samw } 4615331Samw 4626139Sjb150015 param->rw_count = (uint16_t)lcount; 4635331Samw break; 4645331Samw 4655331Samw case STYPE_IPC: 4666139Sjb150015 param->rw_count = (uint16_t)param->rw_vdb.uio.uio_resid; 4675331Samw 4687052Samw if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.uio)) != 0) 4696139Sjb150015 param->rw_count = 0; 4705331Samw break; 4715331Samw 4725331Samw default: 4735331Samw rc = EACCES; 4745331Samw break; 4755331Samw } 4765331Samw 4775331Samw if (rc != 0) 4785331Samw return (rc); 4795331Samw 4805331Samw mutex_enter(&ofile->f_mutex); 4816139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 4825331Samw mutex_exit(&ofile->f_mutex); 4835331Samw return (rc); 4845331Samw } 4855331Samw 4865331Samw /* 4875331Samw * Truncate a disk file to the specified offset. 4885331Samw * Typically, w_count will be zero here. 4895331Samw * 4905331Samw * Returns errno values. 4915331Samw */ 4926030Sjb150015 static int 4936139Sjb150015 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) 4945331Samw { 4955331Samw struct smb_ofile *ofile = sr->fid_ofile; 4965331Samw smb_node_t *node = ofile->f_node; 4975772Sas200622 boolean_t append_only = B_FALSE; 4986030Sjb150015 uint32_t status; 4995331Samw int rc; 5005331Samw 5015331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) 5025331Samw return (0); 5035331Samw 5046030Sjb150015 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, FILE_WRITE_DATA); 5056030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5066030Sjb150015 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, 5075772Sas200622 FILE_APPEND_DATA); 5086030Sjb150015 if (status != NT_STATUS_SUCCESS) 5096030Sjb150015 return (EACCES); 5106030Sjb150015 else 5115772Sas200622 append_only = B_TRUE; 5125772Sas200622 } 5135772Sas200622 5145772Sas200622 smb_rwx_xenter(&node->n_lock); 5155772Sas200622 5166139Sjb150015 if (append_only && (param->rw_offset < node->n_size)) { 5175772Sas200622 smb_rwx_xexit(&node->n_lock); 5186030Sjb150015 return (EACCES); 5195772Sas200622 } 5205772Sas200622 5215331Samw if (node->attr.sa_vattr.va_type != VDIR) { 5226139Sjb150015 status = smb_lock_range_access(sr, node, param->rw_offset, 5236139Sjb150015 param->rw_count, B_TRUE); 5246030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5255772Sas200622 smb_rwx_xexit(&node->n_lock); 5266139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 5276139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 5286030Sjb150015 return (EACCES); 5295331Samw } 5305331Samw } 5315331Samw 5325331Samw node->flags |= NODE_FLAGS_SET_SIZE; 5336139Sjb150015 node->n_size = param->rw_offset; 5345331Samw 5355772Sas200622 smb_rwx_xexit(&node->n_lock); 5365772Sas200622 5376600Sas200622 if ((rc = smb_set_file_size(sr, node)) != 0) 5385331Samw return (rc); 5395331Samw 5405331Samw mutex_enter(&ofile->f_mutex); 5416139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5425331Samw mutex_exit(&ofile->f_mutex); 5435331Samw return (0); 5445331Samw } 5455331Samw 5465331Samw /* 5475331Samw * Set the file size using the value in the node. The file will only be 5485331Samw * updated if NODE_FLAGS_SET_SIZE is set. It is safe to pass a null node 5495331Samw * pointer, we just return success. 5505331Samw * 5515331Samw * The node attributes are refreshed here from the file system. So any 5525331Samw * attributes that are affected by file size changes, i.e. the mtime, 5535331Samw * will be current. 5545331Samw * 5555331Samw * Note that smb_write_andx cannot be used to reduce the file size so, 5565331Samw * if this is required, smb_write is called with a count of zero and 5575331Samw * the appropriate file length in offset. The file should be resized 5585331Samw * to the length specified by the offset. 5595331Samw */ 5605331Samw int 5616600Sas200622 smb_set_file_size(smb_request_t *sr, smb_node_t *node) 5625331Samw { 5635331Samw smb_attr_t new_attr; 5645331Samw 5656600Sas200622 if (node == NULL) 5665331Samw return (0); 5675331Samw 5685331Samw if ((node->flags & NODE_FLAGS_SET_SIZE) == 0) 5695331Samw return (0); 5705331Samw 5715331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 5725331Samw 5735331Samw bzero(&new_attr, sizeof (new_attr)); 5745331Samw new_attr.sa_vattr.va_size = node->n_size; 5755331Samw new_attr.sa_mask = SMB_AT_SIZE; 5765331Samw 577*7348SJose.Borrego@Sun.COM return (smb_fsop_setattr(sr, sr->user_cr, node, &new_attr, 578*7348SJose.Borrego@Sun.COM &node->attr)); 5795331Samw } 580