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> 275331Samw #include <smbsrv/smb_incl.h> 285331Samw #include <smbsrv/smb_fsops.h> 295331Samw #include <smbsrv/mbuf.h> 305331Samw #include <smbsrv/netbios.h> 315331Samw 325331Samw 335331Samw #define SMB_WRMODE_WRITE_THRU 0x0001 345331Samw #define SMB_WRMODE_IS_STABLE(M) ((M) & SMB_WRMODE_WRITE_THRU) 355331Samw 368934SJose.Borrego@Sun.COM /* 378934SJose.Borrego@Sun.COM * The limit in bytes that the marshalling will grow the buffer 388934SJose.Borrego@Sun.COM * chain to accomodate incoming data on SmbWriteX requests. 398934SJose.Borrego@Sun.COM * This sets the upper limit for the data-count per SmbWriteX 408934SJose.Borrego@Sun.COM * request. 418934SJose.Borrego@Sun.COM */ 428934SJose.Borrego@Sun.COM #define SMB_WRITEX_MAX 102400 435331Samw 446139Sjb150015 static int smb_write_common(smb_request_t *, smb_rw_param_t *); 456139Sjb150015 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *); 465331Samw 475331Samw 485331Samw /* 495331Samw * Write count bytes at the specified offset in a file. The offset is 505331Samw * limited to 32-bits. If the count is zero, the file is truncated to 515331Samw * the length specified by the offset. 525331Samw * 535331Samw * The response count indicates the actual number of bytes written, which 545331Samw * will equal the requested count on success. If request and response 555331Samw * counts differ but there is no error, the client will assume that the 565331Samw * server encountered a resource issue. 575331Samw */ 586030Sjb150015 smb_sdrc_t 596139Sjb150015 smb_pre_write(smb_request_t *sr) 605331Samw { 616139Sjb150015 smb_rw_param_t *param; 625331Samw uint32_t off; 638934SJose.Borrego@Sun.COM uint16_t count; 645331Samw int rc; 655331Samw 666139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 676139Sjb150015 sr->arg.rw = param; 686139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 696139Sjb150015 708934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off); 716139Sjb150015 728934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 736139Sjb150015 param->rw_offset = (uint64_t)off; 748934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 756139Sjb150015 766139Sjb150015 DTRACE_SMB_2(op__Write__start, smb_request_t *, sr, 776139Sjb150015 smb_rw_param_t *, param); 786139Sjb150015 796139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 806139Sjb150015 } 815331Samw 826139Sjb150015 void 836139Sjb150015 smb_post_write(smb_request_t *sr) 846139Sjb150015 { 856139Sjb150015 DTRACE_SMB_2(op__Write__done, smb_request_t *, sr, 866139Sjb150015 smb_rw_param_t *, sr->arg.rw); 876139Sjb150015 886139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 896139Sjb150015 } 906139Sjb150015 916139Sjb150015 smb_sdrc_t 926139Sjb150015 smb_com_write(smb_request_t *sr) 936139Sjb150015 { 946139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 956139Sjb150015 int rc; 965331Samw 978934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 985331Samw if (sr->fid_ofile == NULL) { 995772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 1006139Sjb150015 return (SDRC_ERROR); 1015331Samw } 1025331Samw 1037961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 1047961SNatalie.Li@Sun.COM 1056139Sjb150015 if (param->rw_count == 0) { 1065331Samw rc = smb_write_truncate(sr, param); 1075331Samw } else { 1086139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 1095331Samw 1108934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 1116139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 1126139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 1136139Sjb150015 return (SDRC_ERROR); 1145331Samw } 1155331Samw 1168934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 1175331Samw 1185331Samw rc = smb_write_common(sr, param); 1195331Samw } 1205331Samw 1215331Samw if (rc != 0) { 1226139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 1236139Sjb150015 smbsr_errno(sr, rc); 1246139Sjb150015 return (SDRC_ERROR); 1255331Samw } 1265331Samw 1278934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 1288934SJose.Borrego@Sun.COM (uint16_t)param->rw_count, 0); 1296139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1305331Samw } 1315331Samw 1325331Samw /* 1335331Samw * Write count bytes to a file and then close the file. This function 1345331Samw * can only be used to write to 32-bit offsets and the client must set 1355331Samw * WordCount (6 or 12) correctly in order to locate the data to be 1365331Samw * written. If an error occurs on the write, the file should still be 1375331Samw * closed. If Count is 0, the file is truncated (or extended) to offset. 1385331Samw * 1395331Samw * If the last_write time is non-zero, last_write should be used to set 1405331Samw * the mtime. Otherwise the file system stamps the mtime. Failure to 1415331Samw * set mtime should not result in an error response. 1425331Samw */ 1436030Sjb150015 smb_sdrc_t 1446139Sjb150015 smb_pre_write_and_close(smb_request_t *sr) 1455331Samw { 1466139Sjb150015 smb_rw_param_t *param; 1475331Samw uint32_t off; 1488934SJose.Borrego@Sun.COM uint16_t count; 1496139Sjb150015 int rc; 1505331Samw 1516139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 1526139Sjb150015 sr->arg.rw = param; 1536139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 1545331Samw 1555331Samw if (sr->smb_wct == 12) { 1565331Samw rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, 1578934SJose.Borrego@Sun.COM &count, &off, ¶m->rw_last_write); 1585331Samw } else { 1595331Samw rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 1608934SJose.Borrego@Sun.COM &count, &off, ¶m->rw_last_write); 1615331Samw } 1625331Samw 1638934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 1646139Sjb150015 param->rw_offset = (uint64_t)off; 1656139Sjb150015 1666139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr, 1676139Sjb150015 smb_rw_param_t *, param); 1686139Sjb150015 1696139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1706139Sjb150015 } 1716139Sjb150015 1726139Sjb150015 void 1736139Sjb150015 smb_post_write_and_close(smb_request_t *sr) 1746139Sjb150015 { 1756139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr, 1766139Sjb150015 smb_rw_param_t *, sr->arg.rw); 1776139Sjb150015 1786139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 1796139Sjb150015 } 1806139Sjb150015 1816139Sjb150015 smb_sdrc_t 1826139Sjb150015 smb_com_write_and_close(smb_request_t *sr) 1836139Sjb150015 { 1846139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 1858934SJose.Borrego@Sun.COM uint16_t count; 1866139Sjb150015 int rc = 0; 1875331Samw 1888934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 1895331Samw if (sr->fid_ofile == NULL) { 1905772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 1916139Sjb150015 return (SDRC_ERROR); 1925331Samw } 1935331Samw 1947961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 1957961SNatalie.Li@Sun.COM 1966139Sjb150015 if (param->rw_count == 0) { 1975331Samw rc = smb_write_truncate(sr, param); 1985331Samw } else { 1995331Samw /* 2005331Samw * There may be a bug here: should this be "3.#B"? 2015331Samw */ 2026139Sjb150015 rc = smbsr_decode_data(sr, ".#B", param->rw_count, 2036139Sjb150015 ¶m->rw_vdb); 2045331Samw 2058934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 2066139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 2076139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 2086139Sjb150015 return (SDRC_ERROR); 2095331Samw } 2105331Samw 2118934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 2125331Samw 2135331Samw rc = smb_write_common(sr, param); 2145331Samw } 2155331Samw 2165331Samw if (rc != 0) { 2176139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 2186139Sjb150015 smbsr_errno(sr, rc); 2196139Sjb150015 return (SDRC_ERROR); 2205331Samw } 2215331Samw 2227348SJose.Borrego@Sun.COM smb_ofile_close(sr->fid_ofile, param->rw_last_write); 2235331Samw 2248934SJose.Borrego@Sun.COM count = (uint16_t)param->rw_count; 2258934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0); 2266139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2275331Samw } 2285331Samw 2295331Samw /* 2305331Samw * Write count bytes to a file at the specified offset and then unlock 2315331Samw * them. Write behind is safe because the client should have the range 2325331Samw * locked and this request is allowed to extend the file - note that 2336139Sjb150015 * offset is limited to 32-bits. 2346139Sjb150015 * 2356139Sjb150015 * Spec advice: it is an error for count to be zero. For compatibility, 2366139Sjb150015 * we take no action and return success. 2375331Samw * 2385331Samw * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 2395331Samw * files. Reject any attempt to use it on other shares. 2405331Samw * 2415331Samw * The response count indicates the actual number of bytes written, which 2425331Samw * will equal the requested count on success. If request and response 2435331Samw * counts differ but there is no error, the client will assume that the 2445331Samw * server encountered a resource issue. 2455331Samw */ 2466030Sjb150015 smb_sdrc_t 2476139Sjb150015 smb_pre_write_and_unlock(smb_request_t *sr) 2485331Samw { 2496139Sjb150015 smb_rw_param_t *param; 2505331Samw uint32_t off; 2518934SJose.Borrego@Sun.COM uint16_t count; 2525331Samw uint16_t remcnt; 2536139Sjb150015 int rc; 2546139Sjb150015 2556139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 2566139Sjb150015 sr->arg.rw = param; 2576139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 2586139Sjb150015 2598934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt); 2606139Sjb150015 2618934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 2626139Sjb150015 param->rw_offset = (uint64_t)off; 2636139Sjb150015 2646139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr, 2656139Sjb150015 smb_rw_param_t *, param); 2666139Sjb150015 2676139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2686139Sjb150015 } 2696139Sjb150015 2706139Sjb150015 void 2716139Sjb150015 smb_post_write_and_unlock(smb_request_t *sr) 2726139Sjb150015 { 2736139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr, 2746139Sjb150015 smb_rw_param_t *, sr->arg.rw); 2756139Sjb150015 2766139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 2776139Sjb150015 } 2786139Sjb150015 2796139Sjb150015 smb_sdrc_t 2806139Sjb150015 smb_com_write_and_unlock(smb_request_t *sr) 2816139Sjb150015 { 2826139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 2836139Sjb150015 uint32_t status; 2845331Samw int rc = 0; 2855331Samw 2865331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 2875772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 2886139Sjb150015 return (SDRC_ERROR); 2895331Samw } 2905331Samw 2918934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 2925331Samw if (sr->fid_ofile == NULL) { 2935772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 2946139Sjb150015 return (SDRC_ERROR); 2955331Samw } 2965331Samw 2977961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 2987961SNatalie.Li@Sun.COM 2996139Sjb150015 if (param->rw_count == 0) { 3006139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0); 3016139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3025331Samw } 3035331Samw 3048934SJose.Borrego@Sun.COM 3056139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 3065331Samw 3078934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) { 3086139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 3096139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 3106139Sjb150015 return (SDRC_ERROR); 3115331Samw } 3125331Samw 3138934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 3145331Samw 3155331Samw if ((rc = smb_write_common(sr, param)) != 0) { 3166139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 3176139Sjb150015 smbsr_errno(sr, rc); 3186139Sjb150015 return (SDRC_ERROR); 3195331Samw } 3205331Samw 3216139Sjb150015 status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset, 3226139Sjb150015 (uint64_t)param->rw_count); 3236139Sjb150015 if (status != NT_STATUS_SUCCESS) { 3245772Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 3255772Sas200622 ERRDOS, ERRnotlocked); 3266139Sjb150015 return (SDRC_ERROR); 3275331Samw } 3285331Samw 3298934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 3308934SJose.Borrego@Sun.COM (uint16_t)param->rw_count, 0); 3316139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3325331Samw } 3335331Samw 3345331Samw /* 3355331Samw * Write bytes to a file (SMB Core). This request was extended in 3365331Samw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 3375331Samw * 14, instead of 12, and including additional offset information. 3385331Samw * 3395331Samw * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 3405331Samw * to truncate a file. A zero length merely transfers zero bytes. 3415331Samw * 3425331Samw * If bit 0 of WriteMode is set, Fid must refer to a disk file and 3435331Samw * the data must be on stable storage before responding. 3448934SJose.Borrego@Sun.COM * 3458934SJose.Borrego@Sun.COM * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5: 3468934SJose.Borrego@Sun.COM * If CAP_LARGE_WRITEX is set, the byte count may be larger than the 3478934SJose.Borrego@Sun.COM * negotiated buffer size and the server is expected to write the 3488934SJose.Borrego@Sun.COM * number of bytes specified. 3495331Samw */ 3506030Sjb150015 smb_sdrc_t 3516139Sjb150015 smb_pre_write_andx(smb_request_t *sr) 3525331Samw { 3536139Sjb150015 smb_rw_param_t *param; 3545331Samw uint32_t off_low; 3555331Samw uint32_t off_high; 3568934SJose.Borrego@Sun.COM uint16_t datalen_low; 3578934SJose.Borrego@Sun.COM uint16_t datalen_high; 3585331Samw uint16_t remcnt; 3596139Sjb150015 int rc; 3605331Samw 3616139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 3626139Sjb150015 sr->arg.rw = param; 3636139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 3645331Samw 3655331Samw if (sr->smb_wct == 14) { 3668934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid, 3678934SJose.Borrego@Sun.COM &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 3688934SJose.Borrego@Sun.COM &datalen_low, ¶m->rw_dsoff, &off_high); 3695331Samw 3706139Sjb150015 param->rw_dsoff -= 63; 3716139Sjb150015 param->rw_offset = ((uint64_t)off_high << 32) | off_low; 3725331Samw } else { 3738934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid, 3748934SJose.Borrego@Sun.COM &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 3758934SJose.Borrego@Sun.COM &datalen_low, ¶m->rw_dsoff); 3765331Samw 3776139Sjb150015 param->rw_offset = (uint64_t)off_low; 3786139Sjb150015 param->rw_dsoff -= 59; 3795331Samw } 3805331Samw 3818938Samw@Sun.COM param->rw_count = (uint32_t)datalen_low; 3828938Samw@Sun.COM 3838938Samw@Sun.COM if (sr->session->capabilities & CAP_LARGE_WRITEX) 3848938Samw@Sun.COM param->rw_count |= ((uint32_t)datalen_high << 16); 3858934SJose.Borrego@Sun.COM 3866139Sjb150015 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, 3876139Sjb150015 smb_rw_param_t *, param); 3886139Sjb150015 3896139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3906139Sjb150015 } 3916139Sjb150015 3926139Sjb150015 void 3936139Sjb150015 smb_post_write_andx(smb_request_t *sr) 3946139Sjb150015 { 3956139Sjb150015 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr, 3966139Sjb150015 smb_rw_param_t *, sr->arg.rw); 3976139Sjb150015 3986139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 3996139Sjb150015 } 4006139Sjb150015 4016139Sjb150015 smb_sdrc_t 4026139Sjb150015 smb_com_write_andx(smb_request_t *sr) 4036139Sjb150015 { 4046139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 4058934SJose.Borrego@Sun.COM uint16_t count_high; 4068934SJose.Borrego@Sun.COM uint16_t count_low; 4076139Sjb150015 int rc; 4086139Sjb150015 4096139Sjb150015 ASSERT(param); 4106139Sjb150015 ASSERT(param->rw_magic == SMB_RW_MAGIC); 4115331Samw 4128934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 4135331Samw if (sr->fid_ofile == NULL) { 4145772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 4156139Sjb150015 return (SDRC_ERROR); 4165331Samw } 4175331Samw 4187961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 4197961SNatalie.Li@Sun.COM 4206139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) && 4215331Samw STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 4225772Sas200622 smbsr_error(sr, 0, ERRSRV, ERRaccess); 4236139Sjb150015 return (SDRC_ERROR); 4245331Samw } 4255331Samw 4268934SJose.Borrego@Sun.COM sr->smb_data.max_bytes = SMB_WRITEX_MAX; 4276139Sjb150015 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, 4286139Sjb150015 ¶m->rw_vdb); 4298934SJose.Borrego@Sun.COM 4308934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 4316139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 4326139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 4336139Sjb150015 return (SDRC_ERROR); 4345331Samw } 4355331Samw 4368934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 4375331Samw 4386139Sjb150015 if (param->rw_count != 0) { 4395331Samw if ((rc = smb_write_common(sr, param)) != 0) { 4406139Sjb150015 if (sr->smb_error.status != 4416139Sjb150015 NT_STATUS_FILE_LOCK_CONFLICT) 4426139Sjb150015 smbsr_errno(sr, rc); 4436139Sjb150015 return (SDRC_ERROR); 4445331Samw } 4455331Samw } 4465331Samw 4478934SJose.Borrego@Sun.COM count_low = param->rw_count & 0xFFFF; 4488934SJose.Borrego@Sun.COM count_high = (param->rw_count >> 16) & 0xFF; 4498934SJose.Borrego@Sun.COM 4508934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww", 4518934SJose.Borrego@Sun.COM 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0); 4525331Samw 4536139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 4545331Samw } 4555331Samw 4565331Samw /* 4575331Samw * Common function for writing files or IPC/MSRPC named pipes. 4585331Samw * 4595331Samw * Returns errno values. 4605331Samw */ 4616030Sjb150015 static int 4626139Sjb150015 smb_write_common(smb_request_t *sr, smb_rw_param_t *param) 4635331Samw { 464*10001SJoyce.McIntosh@Sun.COM smb_ofile_t *ofile = sr->fid_ofile; 4655331Samw smb_node_t *node; 4667052Samw int stability = 0; 4675331Samw uint32_t lcount; 4685331Samw int rc = 0; 4695331Samw 4705331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 4715331Samw case STYPE_DISKTREE: 4725331Samw node = ofile->f_node; 4735331Samw 474*10001SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node)) { 4756139Sjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset, 4766139Sjb150015 param->rw_count, B_TRUE); 4776139Sjb150015 if (rc != NT_STATUS_SUCCESS) { 4786139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 4796139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 4806139Sjb150015 return (EACCES); 4816139Sjb150015 } 4825331Samw } 4835331Samw 4846139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) || 4855331Samw (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 4867052Samw stability = FSYNC; 4875331Samw } 4885331Samw 4895331Samw rc = smb_fsop_write(sr, sr->user_cr, node, 490*10001SJoyce.McIntosh@Sun.COM ¶m->rw_vdb.vdb_uio, &lcount, stability); 4915331Samw 4925331Samw if (rc) 4935331Samw return (rc); 4945331Samw 495*10001SJoyce.McIntosh@Sun.COM smb_ofile_set_write_time_pending(ofile); 4965331Samw 4978934SJose.Borrego@Sun.COM param->rw_count = lcount; 4985331Samw break; 4995331Samw 5005331Samw case STYPE_IPC: 5018934SJose.Borrego@Sun.COM param->rw_count = param->rw_vdb.vdb_uio.uio_resid; 5025331Samw 5038934SJose.Borrego@Sun.COM if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0) 5046139Sjb150015 param->rw_count = 0; 5055331Samw break; 5065331Samw 5075331Samw default: 5085331Samw rc = EACCES; 5095331Samw break; 5105331Samw } 5115331Samw 5125331Samw if (rc != 0) 5135331Samw return (rc); 5145331Samw 5155331Samw mutex_enter(&ofile->f_mutex); 5166139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5175331Samw mutex_exit(&ofile->f_mutex); 5185331Samw return (rc); 5195331Samw } 5205331Samw 5215331Samw /* 5225331Samw * Truncate a disk file to the specified offset. 5235331Samw * Typically, w_count will be zero here. 5245331Samw * 525*10001SJoyce.McIntosh@Sun.COM * Note that smb_write_andx cannot be used to reduce the file size so, 526*10001SJoyce.McIntosh@Sun.COM * if this is required, smb_write is called with a count of zero and 527*10001SJoyce.McIntosh@Sun.COM * the appropriate file length in offset. The file should be resized 528*10001SJoyce.McIntosh@Sun.COM * to the length specified by the offset. 529*10001SJoyce.McIntosh@Sun.COM * 5305331Samw * Returns errno values. 5315331Samw */ 5326030Sjb150015 static int 5336139Sjb150015 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) 5345331Samw { 535*10001SJoyce.McIntosh@Sun.COM smb_ofile_t *ofile = sr->fid_ofile; 5365331Samw smb_node_t *node = ofile->f_node; 537*10001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 5386030Sjb150015 uint32_t status; 5395331Samw int rc; 5405331Samw 5415331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) 5425331Samw return (0); 5435331Samw 5448934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 545*10001SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node)) { 5466139Sjb150015 status = smb_lock_range_access(sr, node, param->rw_offset, 5476139Sjb150015 param->rw_count, B_TRUE); 5486030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5498934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5506139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 5516139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 5526030Sjb150015 return (EACCES); 5535331Samw } 5545331Samw } 5558934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5565772Sas200622 557*10001SJoyce.McIntosh@Sun.COM bzero(&attr, sizeof (smb_attr_t)); 558*10001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_SIZE; 559*10001SJoyce.McIntosh@Sun.COM attr.sa_vattr.va_size = param->rw_offset; 560*10001SJoyce.McIntosh@Sun.COM rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr); 561*10001SJoyce.McIntosh@Sun.COM if (rc != 0) 5625331Samw return (rc); 5635331Samw 5645331Samw mutex_enter(&ofile->f_mutex); 5656139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5665331Samw mutex_exit(&ofile->f_mutex); 5675331Samw return (0); 5685331Samw } 569