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 /* 228934SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <sys/sdt.h> 27*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h> 285331Samw #include <smbsrv/smb_fsops.h> 295331Samw #include <smbsrv/netbios.h> 305331Samw 315331Samw 325331Samw #define SMB_WRMODE_WRITE_THRU 0x0001 335331Samw #define SMB_WRMODE_IS_STABLE(M) ((M) & SMB_WRMODE_WRITE_THRU) 345331Samw 358934SJose.Borrego@Sun.COM /* 368934SJose.Borrego@Sun.COM * The limit in bytes that the marshalling will grow the buffer 378934SJose.Borrego@Sun.COM * chain to accomodate incoming data on SmbWriteX requests. 388934SJose.Borrego@Sun.COM * This sets the upper limit for the data-count per SmbWriteX 398934SJose.Borrego@Sun.COM * request. 408934SJose.Borrego@Sun.COM */ 418934SJose.Borrego@Sun.COM #define SMB_WRITEX_MAX 102400 425331Samw 436139Sjb150015 static int smb_write_common(smb_request_t *, smb_rw_param_t *); 446139Sjb150015 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *); 455331Samw 465331Samw 475331Samw /* 485331Samw * Write count bytes at the specified offset in a file. The offset is 495331Samw * limited to 32-bits. If the count is zero, the file is truncated to 505331Samw * the length specified by the offset. 515331Samw * 525331Samw * The response count indicates the actual number of bytes written, which 535331Samw * will equal the requested count on success. If request and response 545331Samw * counts differ but there is no error, the client will assume that the 555331Samw * server encountered a resource issue. 565331Samw */ 576030Sjb150015 smb_sdrc_t 586139Sjb150015 smb_pre_write(smb_request_t *sr) 595331Samw { 606139Sjb150015 smb_rw_param_t *param; 615331Samw uint32_t off; 628934SJose.Borrego@Sun.COM uint16_t count; 635331Samw int rc; 645331Samw 656139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 666139Sjb150015 sr->arg.rw = param; 676139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 686139Sjb150015 698934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off); 706139Sjb150015 718934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 726139Sjb150015 param->rw_offset = (uint64_t)off; 738934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 746139Sjb150015 756139Sjb150015 DTRACE_SMB_2(op__Write__start, smb_request_t *, sr, 766139Sjb150015 smb_rw_param_t *, param); 776139Sjb150015 786139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 796139Sjb150015 } 805331Samw 816139Sjb150015 void 826139Sjb150015 smb_post_write(smb_request_t *sr) 836139Sjb150015 { 846139Sjb150015 DTRACE_SMB_2(op__Write__done, smb_request_t *, sr, 856139Sjb150015 smb_rw_param_t *, sr->arg.rw); 866139Sjb150015 876139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 886139Sjb150015 } 896139Sjb150015 906139Sjb150015 smb_sdrc_t 916139Sjb150015 smb_com_write(smb_request_t *sr) 926139Sjb150015 { 936139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 946139Sjb150015 int rc; 955331Samw 968934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 975331Samw if (sr->fid_ofile == NULL) { 985772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 996139Sjb150015 return (SDRC_ERROR); 1005331Samw } 1015331Samw 1027961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 1037961SNatalie.Li@Sun.COM 1046139Sjb150015 if (param->rw_count == 0) { 1055331Samw rc = smb_write_truncate(sr, param); 1065331Samw } else { 1076139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 1085331Samw 1098934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 1106139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 1116139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 1126139Sjb150015 return (SDRC_ERROR); 1135331Samw } 1145331Samw 1158934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 1165331Samw 1175331Samw rc = smb_write_common(sr, param); 1185331Samw } 1195331Samw 1205331Samw if (rc != 0) { 1216139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 1226139Sjb150015 smbsr_errno(sr, rc); 1236139Sjb150015 return (SDRC_ERROR); 1245331Samw } 1255331Samw 1268934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 1278934SJose.Borrego@Sun.COM (uint16_t)param->rw_count, 0); 1286139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1295331Samw } 1305331Samw 1315331Samw /* 1325331Samw * Write count bytes to a file and then close the file. This function 1335331Samw * can only be used to write to 32-bit offsets and the client must set 1345331Samw * WordCount (6 or 12) correctly in order to locate the data to be 1355331Samw * written. If an error occurs on the write, the file should still be 1365331Samw * closed. If Count is 0, the file is truncated (or extended) to offset. 1375331Samw * 1385331Samw * If the last_write time is non-zero, last_write should be used to set 1395331Samw * the mtime. Otherwise the file system stamps the mtime. Failure to 1405331Samw * set mtime should not result in an error response. 1415331Samw */ 1426030Sjb150015 smb_sdrc_t 1436139Sjb150015 smb_pre_write_and_close(smb_request_t *sr) 1445331Samw { 1456139Sjb150015 smb_rw_param_t *param; 1465331Samw uint32_t off; 1478934SJose.Borrego@Sun.COM uint16_t count; 1486139Sjb150015 int rc; 1495331Samw 1506139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 1516139Sjb150015 sr->arg.rw = param; 1526139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 1535331Samw 1545331Samw if (sr->smb_wct == 12) { 1555331Samw rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, 1568934SJose.Borrego@Sun.COM &count, &off, ¶m->rw_last_write); 1575331Samw } else { 1585331Samw rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 1598934SJose.Borrego@Sun.COM &count, &off, ¶m->rw_last_write); 1605331Samw } 1615331Samw 1628934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 1636139Sjb150015 param->rw_offset = (uint64_t)off; 1646139Sjb150015 1656139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr, 1666139Sjb150015 smb_rw_param_t *, param); 1676139Sjb150015 1686139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1696139Sjb150015 } 1706139Sjb150015 1716139Sjb150015 void 1726139Sjb150015 smb_post_write_and_close(smb_request_t *sr) 1736139Sjb150015 { 1746139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr, 1756139Sjb150015 smb_rw_param_t *, sr->arg.rw); 1766139Sjb150015 1776139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 1786139Sjb150015 } 1796139Sjb150015 1806139Sjb150015 smb_sdrc_t 1816139Sjb150015 smb_com_write_and_close(smb_request_t *sr) 1826139Sjb150015 { 1836139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 1848934SJose.Borrego@Sun.COM uint16_t count; 1856139Sjb150015 int rc = 0; 1865331Samw 1878934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 1885331Samw if (sr->fid_ofile == NULL) { 1895772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 1906139Sjb150015 return (SDRC_ERROR); 1915331Samw } 1925331Samw 1937961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 1947961SNatalie.Li@Sun.COM 1956139Sjb150015 if (param->rw_count == 0) { 1965331Samw rc = smb_write_truncate(sr, param); 1975331Samw } else { 1985331Samw /* 1995331Samw * There may be a bug here: should this be "3.#B"? 2005331Samw */ 2016139Sjb150015 rc = smbsr_decode_data(sr, ".#B", param->rw_count, 2026139Sjb150015 ¶m->rw_vdb); 2035331Samw 2048934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 2056139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 2066139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 2076139Sjb150015 return (SDRC_ERROR); 2085331Samw } 2095331Samw 2108934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 2115331Samw 2125331Samw rc = smb_write_common(sr, param); 2135331Samw } 2145331Samw 2155331Samw if (rc != 0) { 2166139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 2176139Sjb150015 smbsr_errno(sr, rc); 2186139Sjb150015 return (SDRC_ERROR); 2195331Samw } 2205331Samw 2217348SJose.Borrego@Sun.COM smb_ofile_close(sr->fid_ofile, param->rw_last_write); 2225331Samw 2238934SJose.Borrego@Sun.COM count = (uint16_t)param->rw_count; 2248934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0); 2256139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2265331Samw } 2275331Samw 2285331Samw /* 2295331Samw * Write count bytes to a file at the specified offset and then unlock 2305331Samw * them. Write behind is safe because the client should have the range 2315331Samw * locked and this request is allowed to extend the file - note that 2326139Sjb150015 * offset is limited to 32-bits. 2336139Sjb150015 * 2346139Sjb150015 * Spec advice: it is an error for count to be zero. For compatibility, 2356139Sjb150015 * we take no action and return success. 2365331Samw * 2375331Samw * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 2385331Samw * files. Reject any attempt to use it on other shares. 2395331Samw * 2405331Samw * The response count indicates the actual number of bytes written, which 2415331Samw * will equal the requested count on success. If request and response 2425331Samw * counts differ but there is no error, the client will assume that the 2435331Samw * server encountered a resource issue. 2445331Samw */ 2456030Sjb150015 smb_sdrc_t 2466139Sjb150015 smb_pre_write_and_unlock(smb_request_t *sr) 2475331Samw { 2486139Sjb150015 smb_rw_param_t *param; 2495331Samw uint32_t off; 2508934SJose.Borrego@Sun.COM uint16_t count; 2515331Samw uint16_t remcnt; 2526139Sjb150015 int rc; 2536139Sjb150015 2546139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 2556139Sjb150015 sr->arg.rw = param; 2566139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 2576139Sjb150015 2588934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt); 2596139Sjb150015 2608934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 2616139Sjb150015 param->rw_offset = (uint64_t)off; 2626139Sjb150015 2636139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr, 2646139Sjb150015 smb_rw_param_t *, param); 2656139Sjb150015 2666139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2676139Sjb150015 } 2686139Sjb150015 2696139Sjb150015 void 2706139Sjb150015 smb_post_write_and_unlock(smb_request_t *sr) 2716139Sjb150015 { 2726139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr, 2736139Sjb150015 smb_rw_param_t *, sr->arg.rw); 2746139Sjb150015 2756139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 2766139Sjb150015 } 2776139Sjb150015 2786139Sjb150015 smb_sdrc_t 2796139Sjb150015 smb_com_write_and_unlock(smb_request_t *sr) 2806139Sjb150015 { 2816139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 2826139Sjb150015 uint32_t status; 2835331Samw int rc = 0; 2845331Samw 2855331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 2865772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 2876139Sjb150015 return (SDRC_ERROR); 2885331Samw } 2895331Samw 2908934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 2915331Samw if (sr->fid_ofile == NULL) { 2925772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 2936139Sjb150015 return (SDRC_ERROR); 2945331Samw } 2955331Samw 2967961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 2977961SNatalie.Li@Sun.COM 2986139Sjb150015 if (param->rw_count == 0) { 2996139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0); 3006139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3015331Samw } 3025331Samw 3038934SJose.Borrego@Sun.COM 3046139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 3055331Samw 3068934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) { 3076139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 3086139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 3096139Sjb150015 return (SDRC_ERROR); 3105331Samw } 3115331Samw 3128934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 3135331Samw 3145331Samw if ((rc = smb_write_common(sr, param)) != 0) { 3156139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 3166139Sjb150015 smbsr_errno(sr, rc); 3176139Sjb150015 return (SDRC_ERROR); 3185331Samw } 3195331Samw 3206139Sjb150015 status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset, 3216139Sjb150015 (uint64_t)param->rw_count); 3226139Sjb150015 if (status != NT_STATUS_SUCCESS) { 3235772Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 3245772Sas200622 ERRDOS, ERRnotlocked); 3256139Sjb150015 return (SDRC_ERROR); 3265331Samw } 3275331Samw 3288934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 3298934SJose.Borrego@Sun.COM (uint16_t)param->rw_count, 0); 3306139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3315331Samw } 3325331Samw 3335331Samw /* 3345331Samw * Write bytes to a file (SMB Core). This request was extended in 3355331Samw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 3365331Samw * 14, instead of 12, and including additional offset information. 3375331Samw * 3385331Samw * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 3395331Samw * to truncate a file. A zero length merely transfers zero bytes. 3405331Samw * 3415331Samw * If bit 0 of WriteMode is set, Fid must refer to a disk file and 3425331Samw * the data must be on stable storage before responding. 3438934SJose.Borrego@Sun.COM * 3448934SJose.Borrego@Sun.COM * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5: 3458934SJose.Borrego@Sun.COM * If CAP_LARGE_WRITEX is set, the byte count may be larger than the 3468934SJose.Borrego@Sun.COM * negotiated buffer size and the server is expected to write the 3478934SJose.Borrego@Sun.COM * number of bytes specified. 3485331Samw */ 3496030Sjb150015 smb_sdrc_t 3506139Sjb150015 smb_pre_write_andx(smb_request_t *sr) 3515331Samw { 3526139Sjb150015 smb_rw_param_t *param; 3535331Samw uint32_t off_low; 3545331Samw uint32_t off_high; 3558934SJose.Borrego@Sun.COM uint16_t datalen_low; 3568934SJose.Borrego@Sun.COM uint16_t datalen_high; 3575331Samw uint16_t remcnt; 3586139Sjb150015 int rc; 3595331Samw 3606139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 3616139Sjb150015 sr->arg.rw = param; 3626139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 3635331Samw 3645331Samw if (sr->smb_wct == 14) { 3658934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid, 3668934SJose.Borrego@Sun.COM &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 3678934SJose.Borrego@Sun.COM &datalen_low, ¶m->rw_dsoff, &off_high); 3685331Samw 3696139Sjb150015 param->rw_dsoff -= 63; 3706139Sjb150015 param->rw_offset = ((uint64_t)off_high << 32) | off_low; 3715331Samw } else { 3728934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid, 3738934SJose.Borrego@Sun.COM &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 3748934SJose.Borrego@Sun.COM &datalen_low, ¶m->rw_dsoff); 3755331Samw 3766139Sjb150015 param->rw_offset = (uint64_t)off_low; 3776139Sjb150015 param->rw_dsoff -= 59; 3785331Samw } 3795331Samw 3808938Samw@Sun.COM param->rw_count = (uint32_t)datalen_low; 3818938Samw@Sun.COM 3828938Samw@Sun.COM if (sr->session->capabilities & CAP_LARGE_WRITEX) 3838938Samw@Sun.COM param->rw_count |= ((uint32_t)datalen_high << 16); 3848934SJose.Borrego@Sun.COM 3856139Sjb150015 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, 3866139Sjb150015 smb_rw_param_t *, param); 3876139Sjb150015 3886139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3896139Sjb150015 } 3906139Sjb150015 3916139Sjb150015 void 3926139Sjb150015 smb_post_write_andx(smb_request_t *sr) 3936139Sjb150015 { 3946139Sjb150015 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr, 3956139Sjb150015 smb_rw_param_t *, sr->arg.rw); 3966139Sjb150015 3976139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 3986139Sjb150015 } 3996139Sjb150015 4006139Sjb150015 smb_sdrc_t 4016139Sjb150015 smb_com_write_andx(smb_request_t *sr) 4026139Sjb150015 { 4036139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 4048934SJose.Borrego@Sun.COM uint16_t count_high; 4058934SJose.Borrego@Sun.COM uint16_t count_low; 4066139Sjb150015 int rc; 4076139Sjb150015 4086139Sjb150015 ASSERT(param); 4096139Sjb150015 ASSERT(param->rw_magic == SMB_RW_MAGIC); 4105331Samw 4118934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 4125331Samw if (sr->fid_ofile == NULL) { 4135772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 4146139Sjb150015 return (SDRC_ERROR); 4155331Samw } 4165331Samw 4177961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 4187961SNatalie.Li@Sun.COM 4196139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) && 4205331Samw STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 4215772Sas200622 smbsr_error(sr, 0, ERRSRV, ERRaccess); 4226139Sjb150015 return (SDRC_ERROR); 4235331Samw } 4245331Samw 4258934SJose.Borrego@Sun.COM sr->smb_data.max_bytes = SMB_WRITEX_MAX; 4266139Sjb150015 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, 4276139Sjb150015 ¶m->rw_vdb); 4288934SJose.Borrego@Sun.COM 4298934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 4306139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 4316139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 4326139Sjb150015 return (SDRC_ERROR); 4335331Samw } 4345331Samw 4358934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 4365331Samw 4376139Sjb150015 if (param->rw_count != 0) { 4385331Samw if ((rc = smb_write_common(sr, param)) != 0) { 4396139Sjb150015 if (sr->smb_error.status != 4406139Sjb150015 NT_STATUS_FILE_LOCK_CONFLICT) 4416139Sjb150015 smbsr_errno(sr, rc); 4426139Sjb150015 return (SDRC_ERROR); 4435331Samw } 4445331Samw } 4455331Samw 4468934SJose.Borrego@Sun.COM count_low = param->rw_count & 0xFFFF; 4478934SJose.Borrego@Sun.COM count_high = (param->rw_count >> 16) & 0xFF; 4488934SJose.Borrego@Sun.COM 4498934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww", 4508934SJose.Borrego@Sun.COM 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0); 4515331Samw 4526139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 4535331Samw } 4545331Samw 4555331Samw /* 4565331Samw * Common function for writing files or IPC/MSRPC named pipes. 4575331Samw * 4585331Samw * Returns errno values. 4595331Samw */ 4606030Sjb150015 static int 4616139Sjb150015 smb_write_common(smb_request_t *sr, smb_rw_param_t *param) 4625331Samw { 46310001SJoyce.McIntosh@Sun.COM smb_ofile_t *ofile = sr->fid_ofile; 4645331Samw smb_node_t *node; 4657052Samw int stability = 0; 4665331Samw uint32_t lcount; 4675331Samw int rc = 0; 4685331Samw 4695331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 4705331Samw case STYPE_DISKTREE: 4715331Samw node = ofile->f_node; 4725331Samw 47310001SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node)) { 4746139Sjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset, 4756139Sjb150015 param->rw_count, B_TRUE); 4766139Sjb150015 if (rc != NT_STATUS_SUCCESS) { 4776139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 4786139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 4796139Sjb150015 return (EACCES); 4806139Sjb150015 } 4815331Samw } 4825331Samw 4836139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) || 4845331Samw (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 4857052Samw stability = FSYNC; 4865331Samw } 4875331Samw 4885331Samw rc = smb_fsop_write(sr, sr->user_cr, node, 48910001SJoyce.McIntosh@Sun.COM ¶m->rw_vdb.vdb_uio, &lcount, stability); 4905331Samw 4915331Samw if (rc) 4925331Samw return (rc); 4935331Samw 49410001SJoyce.McIntosh@Sun.COM smb_ofile_set_write_time_pending(ofile); 4955331Samw 4968934SJose.Borrego@Sun.COM param->rw_count = lcount; 4975331Samw break; 4985331Samw 4995331Samw case STYPE_IPC: 5008934SJose.Borrego@Sun.COM param->rw_count = param->rw_vdb.vdb_uio.uio_resid; 5015331Samw 5028934SJose.Borrego@Sun.COM if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0) 5036139Sjb150015 param->rw_count = 0; 5045331Samw break; 5055331Samw 5065331Samw default: 5075331Samw rc = EACCES; 5085331Samw break; 5095331Samw } 5105331Samw 5115331Samw if (rc != 0) 5125331Samw return (rc); 5135331Samw 5145331Samw mutex_enter(&ofile->f_mutex); 5156139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5165331Samw mutex_exit(&ofile->f_mutex); 5175331Samw return (rc); 5185331Samw } 5195331Samw 5205331Samw /* 5215331Samw * Truncate a disk file to the specified offset. 5225331Samw * Typically, w_count will be zero here. 5235331Samw * 52410001SJoyce.McIntosh@Sun.COM * Note that smb_write_andx cannot be used to reduce the file size so, 52510001SJoyce.McIntosh@Sun.COM * if this is required, smb_write is called with a count of zero and 52610001SJoyce.McIntosh@Sun.COM * the appropriate file length in offset. The file should be resized 52710001SJoyce.McIntosh@Sun.COM * to the length specified by the offset. 52810001SJoyce.McIntosh@Sun.COM * 5295331Samw * Returns errno values. 5305331Samw */ 5316030Sjb150015 static int 5326139Sjb150015 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) 5335331Samw { 53410001SJoyce.McIntosh@Sun.COM smb_ofile_t *ofile = sr->fid_ofile; 5355331Samw smb_node_t *node = ofile->f_node; 53610001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 5376030Sjb150015 uint32_t status; 5385331Samw int rc; 5395331Samw 5405331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) 5415331Samw return (0); 5425331Samw 5438934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 54410001SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node)) { 5456139Sjb150015 status = smb_lock_range_access(sr, node, param->rw_offset, 5466139Sjb150015 param->rw_count, B_TRUE); 5476030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5488934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5496139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 5506139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 5516030Sjb150015 return (EACCES); 5525331Samw } 5535331Samw } 5548934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5555772Sas200622 55610001SJoyce.McIntosh@Sun.COM bzero(&attr, sizeof (smb_attr_t)); 55710001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_SIZE; 55810001SJoyce.McIntosh@Sun.COM attr.sa_vattr.va_size = param->rw_offset; 55910001SJoyce.McIntosh@Sun.COM rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr); 56010001SJoyce.McIntosh@Sun.COM if (rc != 0) 5615331Samw return (rc); 5625331Samw 5635331Samw mutex_enter(&ofile->f_mutex); 5646139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5655331Samw mutex_exit(&ofile->f_mutex); 5665331Samw return (0); 5675331Samw } 568