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 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 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 2076139Sjb150015 if ((rc = smb_common_close(sr, param->rw_last_write)) != 0) { 2085772Sas200622 smbsr_errno(sr, rc); 2096139Sjb150015 return (SDRC_ERROR); 2105331Samw } 2115331Samw 2126139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); 2136139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2145331Samw } 2155331Samw 2165331Samw /* 2175331Samw * Write count bytes to a file at the specified offset and then unlock 2185331Samw * them. Write behind is safe because the client should have the range 2195331Samw * locked and this request is allowed to extend the file - note that 2206139Sjb150015 * offset is limited to 32-bits. 2216139Sjb150015 * 2226139Sjb150015 * Spec advice: it is an error for count to be zero. For compatibility, 2236139Sjb150015 * we take no action and return success. 2245331Samw * 2255331Samw * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 2265331Samw * files. Reject any attempt to use it on other shares. 2275331Samw * 2285331Samw * The response count indicates the actual number of bytes written, which 2295331Samw * will equal the requested count on success. If request and response 2305331Samw * counts differ but there is no error, the client will assume that the 2315331Samw * server encountered a resource issue. 2325331Samw */ 2336030Sjb150015 smb_sdrc_t 2346139Sjb150015 smb_pre_write_and_unlock(smb_request_t *sr) 2355331Samw { 2366139Sjb150015 smb_rw_param_t *param; 2375331Samw uint32_t off; 2385331Samw uint16_t remcnt; 2396139Sjb150015 int rc; 2406139Sjb150015 2416139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 2426139Sjb150015 sr->arg.rw = param; 2436139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 2446139Sjb150015 2456139Sjb150015 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, ¶m->rw_count, &off, 2466139Sjb150015 &remcnt); 2476139Sjb150015 2486139Sjb150015 param->rw_offset = (uint64_t)off; 2496139Sjb150015 2506139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr, 2516139Sjb150015 smb_rw_param_t *, param); 2526139Sjb150015 2536139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2546139Sjb150015 } 2556139Sjb150015 2566139Sjb150015 void 2576139Sjb150015 smb_post_write_and_unlock(smb_request_t *sr) 2586139Sjb150015 { 2596139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr, 2606139Sjb150015 smb_rw_param_t *, sr->arg.rw); 2616139Sjb150015 2626139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 2636139Sjb150015 } 2646139Sjb150015 2656139Sjb150015 smb_sdrc_t 2666139Sjb150015 smb_com_write_and_unlock(smb_request_t *sr) 2676139Sjb150015 { 2686139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 2696139Sjb150015 uint32_t status; 2705331Samw int rc = 0; 2715331Samw 2725331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 2735772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 2746139Sjb150015 return (SDRC_ERROR); 2755331Samw } 2765331Samw 2775331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 2785331Samw if (sr->fid_ofile == NULL) { 2795772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 2806139Sjb150015 return (SDRC_ERROR); 2815331Samw } 2825331Samw 2836139Sjb150015 if (param->rw_count == 0) { 2846139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0); 2856139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2865331Samw } 2875331Samw 2886139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 2895331Samw 2906139Sjb150015 if ((rc != 0) || (param->rw_count != param->rw_vdb.len)) { 2916139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 2926139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 2936139Sjb150015 return (SDRC_ERROR); 2945331Samw } 2955331Samw 2966139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 2975331Samw 2985331Samw if ((rc = smb_write_common(sr, param)) != 0) { 2996139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 3006139Sjb150015 smbsr_errno(sr, rc); 3016139Sjb150015 return (SDRC_ERROR); 3025331Samw } 3035331Samw 3046139Sjb150015 status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset, 3056139Sjb150015 (uint64_t)param->rw_count); 3066139Sjb150015 if (status != NT_STATUS_SUCCESS) { 3075772Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 3085772Sas200622 ERRDOS, ERRnotlocked); 3096139Sjb150015 return (SDRC_ERROR); 3105331Samw } 3115331Samw 3126139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); 3136139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3145331Samw } 3155331Samw 3165331Samw /* 3175331Samw * Write bytes to a file (SMB Core). This request was extended in 3185331Samw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 3195331Samw * 14, instead of 12, and including additional offset information. 3205331Samw * 3215331Samw * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 3225331Samw * to truncate a file. A zero length merely transfers zero bytes. 3235331Samw * 3245331Samw * If bit 0 of WriteMode is set, Fid must refer to a disk file and 3255331Samw * the data must be on stable storage before responding. 3265331Samw */ 3276030Sjb150015 smb_sdrc_t 3286139Sjb150015 smb_pre_write_andx(smb_request_t *sr) 3295331Samw { 3306139Sjb150015 smb_rw_param_t *param; 3315331Samw uint32_t off_low; 3325331Samw uint32_t off_high; 3335331Samw uint16_t remcnt; 3346139Sjb150015 int rc; 3355331Samw 3366139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 3376139Sjb150015 sr->arg.rw = param; 3386139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 3395331Samw 3405331Samw if (sr->smb_wct == 14) { 3415331Samw rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid, 3426139Sjb150015 &off_low, ¶m->rw_mode, &remcnt, ¶m->rw_count, 3436139Sjb150015 ¶m->rw_dsoff, &off_high); 3445331Samw 3456139Sjb150015 param->rw_dsoff -= 63; 3466139Sjb150015 param->rw_offset = ((uint64_t)off_high << 32) | off_low; 3475331Samw } else { 3485331Samw rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid, 3496139Sjb150015 &off_low, ¶m->rw_mode, &remcnt, ¶m->rw_count, 3506139Sjb150015 ¶m->rw_dsoff); 3515331Samw 3526139Sjb150015 param->rw_offset = (uint64_t)off_low; 3536139Sjb150015 param->rw_dsoff -= 59; 3545331Samw } 3555331Samw 3566139Sjb150015 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, 3576139Sjb150015 smb_rw_param_t *, param); 3586139Sjb150015 3596139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3606139Sjb150015 } 3616139Sjb150015 3626139Sjb150015 void 3636139Sjb150015 smb_post_write_andx(smb_request_t *sr) 3646139Sjb150015 { 3656139Sjb150015 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr, 3666139Sjb150015 smb_rw_param_t *, sr->arg.rw); 3676139Sjb150015 3686139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 3696139Sjb150015 } 3706139Sjb150015 3716139Sjb150015 smb_sdrc_t 3726139Sjb150015 smb_com_write_andx(smb_request_t *sr) 3736139Sjb150015 { 3746139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 3756139Sjb150015 int rc; 3766139Sjb150015 3776139Sjb150015 ASSERT(param); 3786139Sjb150015 ASSERT(param->rw_magic == SMB_RW_MAGIC); 3795331Samw 3805331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 3815331Samw if (sr->fid_ofile == NULL) { 3825772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 3836139Sjb150015 return (SDRC_ERROR); 3845331Samw } 3855331Samw 3866139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) && 3875331Samw STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 3885772Sas200622 smbsr_error(sr, 0, ERRSRV, ERRaccess); 3896139Sjb150015 return (SDRC_ERROR); 3905331Samw } 3915331Samw 3926139Sjb150015 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, 3936139Sjb150015 ¶m->rw_vdb); 3946139Sjb150015 if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { 3956139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 3966139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 3976139Sjb150015 return (SDRC_ERROR); 3985331Samw } 3995331Samw 4006139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 4015331Samw 4026139Sjb150015 if (param->rw_count != 0) { 4035331Samw if ((rc = smb_write_common(sr, param)) != 0) { 4046139Sjb150015 if (sr->smb_error.status != 4056139Sjb150015 NT_STATUS_FILE_LOCK_CONFLICT) 4066139Sjb150015 smbsr_errno(sr, rc); 4076139Sjb150015 return (SDRC_ERROR); 4085331Samw } 4095331Samw } 4105331Samw 4116030Sjb150015 rc = smbsr_encode_result(sr, 6, 0, "bb1.ww6.w", 4126139Sjb150015 6, sr->andx_com, 15, param->rw_count, 0); 4135331Samw 4146139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 4155331Samw } 4165331Samw 4175331Samw /* 4185331Samw * Common function for writing files or IPC/MSRPC named pipes. 4195331Samw * 4205331Samw * Returns errno values. 4215331Samw */ 4226030Sjb150015 static int 4236139Sjb150015 smb_write_common(smb_request_t *sr, smb_rw_param_t *param) 4245331Samw { 4255331Samw struct smb_ofile *ofile = sr->fid_ofile; 4265331Samw smb_node_t *node; 4275331Samw uint32_t stability = FSSTAB_UNSTABLE; 4285331Samw uint32_t lcount; 4295331Samw int rc = 0; 4305331Samw 4315331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 4325331Samw case STYPE_DISKTREE: 4335331Samw node = ofile->f_node; 4345331Samw 4355331Samw if (node->attr.sa_vattr.va_type != VDIR) { 4366139Sjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset, 4376139Sjb150015 param->rw_count, B_TRUE); 4386139Sjb150015 if (rc != NT_STATUS_SUCCESS) { 4396139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 4406139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 4416139Sjb150015 return (EACCES); 4426139Sjb150015 } 4435331Samw } 4445331Samw 4456139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) || 4465331Samw (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 4475331Samw stability = FSSTAB_FILE_SYNC; 4485331Samw } 4495331Samw 4505331Samw rc = smb_fsop_write(sr, sr->user_cr, node, 4516139Sjb150015 ¶m->rw_vdb.uio, &lcount, &node->attr, &stability); 4525331Samw 4535331Samw if (rc) 4545331Samw return (rc); 4555331Samw 4565331Samw node->flags |= NODE_FLAGS_SYNCATIME; 4575331Samw 4585331Samw if (node->flags & NODE_FLAGS_SET_SIZE) { 4596139Sjb150015 if ((param->rw_offset + lcount) >= node->n_size) { 4605331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 4616139Sjb150015 node->n_size = param->rw_offset + lcount; 4625331Samw } 4635331Samw } 4645331Samw 4656139Sjb150015 param->rw_count = (uint16_t)lcount; 4665331Samw break; 4675331Samw 4685331Samw case STYPE_IPC: 4696139Sjb150015 param->rw_count = (uint16_t)param->rw_vdb.uio.uio_resid; 4705331Samw 4716139Sjb150015 if ((rc = smb_rpc_write(sr, ¶m->rw_vdb.uio)) != 0) 4726139Sjb150015 param->rw_count = 0; 4735331Samw break; 4745331Samw 4755331Samw default: 4765331Samw rc = EACCES; 4775331Samw break; 4785331Samw } 4795331Samw 4805331Samw if (rc != 0) 4815331Samw return (rc); 4825331Samw 4835331Samw mutex_enter(&ofile->f_mutex); 4846139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 4855331Samw mutex_exit(&ofile->f_mutex); 4865331Samw return (rc); 4875331Samw } 4885331Samw 4895331Samw /* 4905331Samw * Truncate a disk file to the specified offset. 4915331Samw * Typically, w_count will be zero here. 4925331Samw * 4935331Samw * Returns errno values. 4945331Samw */ 4956030Sjb150015 static int 4966139Sjb150015 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) 4975331Samw { 4985331Samw struct smb_ofile *ofile = sr->fid_ofile; 4995331Samw smb_node_t *node = ofile->f_node; 5005772Sas200622 boolean_t append_only = B_FALSE; 5016030Sjb150015 uint32_t status; 5025331Samw int rc; 5035331Samw 5045331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) 5055331Samw return (0); 5065331Samw 5076030Sjb150015 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, FILE_WRITE_DATA); 5086030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5096030Sjb150015 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, 5105772Sas200622 FILE_APPEND_DATA); 5116030Sjb150015 if (status != NT_STATUS_SUCCESS) 5126030Sjb150015 return (EACCES); 5136030Sjb150015 else 5145772Sas200622 append_only = B_TRUE; 5155772Sas200622 } 5165772Sas200622 5175772Sas200622 smb_rwx_xenter(&node->n_lock); 5185772Sas200622 5196139Sjb150015 if (append_only && (param->rw_offset < node->n_size)) { 5205772Sas200622 smb_rwx_xexit(&node->n_lock); 5216030Sjb150015 return (EACCES); 5225772Sas200622 } 5235772Sas200622 5245331Samw if (node->attr.sa_vattr.va_type != VDIR) { 5256139Sjb150015 status = smb_lock_range_access(sr, node, param->rw_offset, 5266139Sjb150015 param->rw_count, B_TRUE); 5276030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5285772Sas200622 smb_rwx_xexit(&node->n_lock); 5296139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 5306139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 5316030Sjb150015 return (EACCES); 5325331Samw } 5335331Samw } 5345331Samw 5355331Samw node->flags |= NODE_FLAGS_SET_SIZE; 5366139Sjb150015 node->n_size = param->rw_offset; 5375331Samw 5385772Sas200622 smb_rwx_xexit(&node->n_lock); 5395772Sas200622 540*6600Sas200622 if ((rc = smb_set_file_size(sr, node)) != 0) 5415331Samw return (rc); 5425331Samw 5435331Samw mutex_enter(&ofile->f_mutex); 5446139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5455331Samw mutex_exit(&ofile->f_mutex); 5465331Samw return (0); 5475331Samw } 5485331Samw 5495331Samw /* 5505331Samw * Set the file size using the value in the node. The file will only be 5515331Samw * updated if NODE_FLAGS_SET_SIZE is set. It is safe to pass a null node 5525331Samw * pointer, we just return success. 5535331Samw * 5545331Samw * The node attributes are refreshed here from the file system. So any 5555331Samw * attributes that are affected by file size changes, i.e. the mtime, 5565331Samw * will be current. 5575331Samw * 5585331Samw * Note that smb_write_andx cannot be used to reduce the file size so, 5595331Samw * if this is required, smb_write is called with a count of zero and 5605331Samw * the appropriate file length in offset. The file should be resized 5615331Samw * to the length specified by the offset. 5625331Samw * 5635331Samw * Returns 0 on success. Otherwise returns EACCES. 5645331Samw */ 5655331Samw int 566*6600Sas200622 smb_set_file_size(smb_request_t *sr, smb_node_t *node) 5675331Samw { 5685331Samw smb_attr_t new_attr; 5695331Samw uint32_t dosattr; 5705331Samw 571*6600Sas200622 if (node == NULL) 5725331Samw return (0); 5735331Samw 5745331Samw if ((node->flags & NODE_FLAGS_SET_SIZE) == 0) 5755331Samw return (0); 5765331Samw 5775331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 5785331Samw 5795331Samw dosattr = smb_node_get_dosattr(node); 5805331Samw 5815331Samw if (dosattr & SMB_FA_READONLY) { 5825331Samw if (((node->flags & NODE_FLAGS_CREATED) == 0) || 5835331Samw (sr->session->s_kid != node->n_orig_session_id)) 5845331Samw return (EACCES); 5855331Samw } 5865331Samw 5875331Samw bzero(&new_attr, sizeof (new_attr)); 5885331Samw new_attr.sa_vattr.va_size = node->n_size; 5895331Samw new_attr.sa_mask = SMB_AT_SIZE; 5905331Samw 5915331Samw (void) smb_fsop_setattr(sr, sr->user_cr, node, &new_attr, 5925331Samw &node->attr); 5935331Samw 5945331Samw return (0); 5955331Samw } 596