15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 22*8934SJose.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 36*8934SJose.Borrego@Sun.COM /* 37*8934SJose.Borrego@Sun.COM * The limit in bytes that the marshalling will grow the buffer 38*8934SJose.Borrego@Sun.COM * chain to accomodate incoming data on SmbWriteX requests. 39*8934SJose.Borrego@Sun.COM * This sets the upper limit for the data-count per SmbWriteX 40*8934SJose.Borrego@Sun.COM * request. 41*8934SJose.Borrego@Sun.COM */ 42*8934SJose.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; 63*8934SJose.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 70*8934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off); 716139Sjb150015 72*8934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 736139Sjb150015 param->rw_offset = (uint64_t)off; 74*8934SJose.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 97*8934SJose.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 110*8934SJose.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 116*8934SJose.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 127*8934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 128*8934SJose.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; 148*8934SJose.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, 157*8934SJose.Borrego@Sun.COM &count, &off, ¶m->rw_last_write); 1585331Samw } else { 1595331Samw rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 160*8934SJose.Borrego@Sun.COM &count, &off, ¶m->rw_last_write); 1615331Samw } 1625331Samw 163*8934SJose.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; 185*8934SJose.Borrego@Sun.COM uint16_t count; 1866139Sjb150015 int rc = 0; 1875331Samw 188*8934SJose.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 205*8934SJose.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 211*8934SJose.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 224*8934SJose.Borrego@Sun.COM count = (uint16_t)param->rw_count; 225*8934SJose.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; 251*8934SJose.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 259*8934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt); 2606139Sjb150015 261*8934SJose.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 291*8934SJose.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 304*8934SJose.Borrego@Sun.COM 3056139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 3065331Samw 307*8934SJose.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 313*8934SJose.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 329*8934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 330*8934SJose.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. 344*8934SJose.Borrego@Sun.COM * 345*8934SJose.Borrego@Sun.COM * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5: 346*8934SJose.Borrego@Sun.COM * If CAP_LARGE_WRITEX is set, the byte count may be larger than the 347*8934SJose.Borrego@Sun.COM * negotiated buffer size and the server is expected to write the 348*8934SJose.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; 356*8934SJose.Borrego@Sun.COM uint16_t datalen_low; 357*8934SJose.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) { 366*8934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid, 367*8934SJose.Borrego@Sun.COM &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 368*8934SJose.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 { 373*8934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid, 374*8934SJose.Borrego@Sun.COM &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 375*8934SJose.Borrego@Sun.COM &datalen_low, ¶m->rw_dsoff); 3765331Samw 3776139Sjb150015 param->rw_offset = (uint64_t)off_low; 3786139Sjb150015 param->rw_dsoff -= 59; 3795331Samw } 3805331Samw 381*8934SJose.Borrego@Sun.COM param->rw_count = ((uint32_t)datalen_high << 16) | 382*8934SJose.Borrego@Sun.COM (uint32_t)datalen_low; 383*8934SJose.Borrego@Sun.COM 3846139Sjb150015 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, 3856139Sjb150015 smb_rw_param_t *, param); 3866139Sjb150015 3876139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3886139Sjb150015 } 3896139Sjb150015 3906139Sjb150015 void 3916139Sjb150015 smb_post_write_andx(smb_request_t *sr) 3926139Sjb150015 { 3936139Sjb150015 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr, 3946139Sjb150015 smb_rw_param_t *, sr->arg.rw); 3956139Sjb150015 3966139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 3976139Sjb150015 } 3986139Sjb150015 3996139Sjb150015 smb_sdrc_t 4006139Sjb150015 smb_com_write_andx(smb_request_t *sr) 4016139Sjb150015 { 4026139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 403*8934SJose.Borrego@Sun.COM uint16_t count_high; 404*8934SJose.Borrego@Sun.COM uint16_t count_low; 4056139Sjb150015 int rc; 4066139Sjb150015 4076139Sjb150015 ASSERT(param); 4086139Sjb150015 ASSERT(param->rw_magic == SMB_RW_MAGIC); 4095331Samw 410*8934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 4115331Samw if (sr->fid_ofile == NULL) { 4125772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 4136139Sjb150015 return (SDRC_ERROR); 4145331Samw } 4155331Samw 4167961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 4177961SNatalie.Li@Sun.COM 4186139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) && 4195331Samw STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 4205772Sas200622 smbsr_error(sr, 0, ERRSRV, ERRaccess); 4216139Sjb150015 return (SDRC_ERROR); 4225331Samw } 4235331Samw 424*8934SJose.Borrego@Sun.COM sr->smb_data.max_bytes = SMB_WRITEX_MAX; 4256139Sjb150015 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, 4266139Sjb150015 ¶m->rw_vdb); 427*8934SJose.Borrego@Sun.COM 428*8934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 4296139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 4306139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 4316139Sjb150015 return (SDRC_ERROR); 4325331Samw } 4335331Samw 434*8934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 4355331Samw 4366139Sjb150015 if (param->rw_count != 0) { 4375331Samw if ((rc = smb_write_common(sr, param)) != 0) { 4386139Sjb150015 if (sr->smb_error.status != 4396139Sjb150015 NT_STATUS_FILE_LOCK_CONFLICT) 4406139Sjb150015 smbsr_errno(sr, rc); 4416139Sjb150015 return (SDRC_ERROR); 4425331Samw } 4435331Samw } 4445331Samw 445*8934SJose.Borrego@Sun.COM count_low = param->rw_count & 0xFFFF; 446*8934SJose.Borrego@Sun.COM count_high = (param->rw_count >> 16) & 0xFF; 447*8934SJose.Borrego@Sun.COM 448*8934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww", 449*8934SJose.Borrego@Sun.COM 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0); 4505331Samw 4516139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 4525331Samw } 4535331Samw 4545331Samw /* 4555331Samw * Common function for writing files or IPC/MSRPC named pipes. 4565331Samw * 4575331Samw * Returns errno values. 4585331Samw */ 4596030Sjb150015 static int 4606139Sjb150015 smb_write_common(smb_request_t *sr, smb_rw_param_t *param) 4615331Samw { 4625331Samw struct smb_ofile *ofile = sr->fid_ofile; 4635331Samw smb_node_t *node; 4647052Samw int stability = 0; 4655331Samw uint32_t lcount; 4665331Samw int rc = 0; 4675331Samw 4685331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 4695331Samw case STYPE_DISKTREE: 4705331Samw node = ofile->f_node; 4715331Samw 4725331Samw if (node->attr.sa_vattr.va_type != VDIR) { 4736139Sjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset, 4746139Sjb150015 param->rw_count, B_TRUE); 4756139Sjb150015 if (rc != NT_STATUS_SUCCESS) { 4766139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 4776139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 4786139Sjb150015 return (EACCES); 4796139Sjb150015 } 4805331Samw } 4815331Samw 4826139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) || 4835331Samw (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 4847052Samw stability = FSYNC; 4855331Samw } 4865331Samw 4875331Samw rc = smb_fsop_write(sr, sr->user_cr, node, 488*8934SJose.Borrego@Sun.COM ¶m->rw_vdb.vdb_uio, &lcount, &node->attr, stability); 4895331Samw 4905331Samw if (rc) 4915331Samw return (rc); 4925331Samw 4935331Samw node->flags |= NODE_FLAGS_SYNCATIME; 4945331Samw 4955331Samw if (node->flags & NODE_FLAGS_SET_SIZE) { 4966139Sjb150015 if ((param->rw_offset + lcount) >= node->n_size) { 4975331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 4986139Sjb150015 node->n_size = param->rw_offset + lcount; 4995331Samw } 5005331Samw } 5015331Samw 502*8934SJose.Borrego@Sun.COM param->rw_count = lcount; 5035331Samw break; 5045331Samw 5055331Samw case STYPE_IPC: 506*8934SJose.Borrego@Sun.COM param->rw_count = param->rw_vdb.vdb_uio.uio_resid; 5075331Samw 508*8934SJose.Borrego@Sun.COM if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0) 5096139Sjb150015 param->rw_count = 0; 5105331Samw break; 5115331Samw 5125331Samw default: 5135331Samw rc = EACCES; 5145331Samw break; 5155331Samw } 5165331Samw 5175331Samw if (rc != 0) 5185331Samw return (rc); 5195331Samw 5205331Samw mutex_enter(&ofile->f_mutex); 5216139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5225331Samw mutex_exit(&ofile->f_mutex); 5235331Samw return (rc); 5245331Samw } 5255331Samw 5265331Samw /* 5275331Samw * Truncate a disk file to the specified offset. 5285331Samw * Typically, w_count will be zero here. 5295331Samw * 5305331Samw * Returns errno values. 5315331Samw */ 5326030Sjb150015 static int 5336139Sjb150015 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) 5345331Samw { 5355331Samw struct smb_ofile *ofile = sr->fid_ofile; 5365331Samw smb_node_t *node = ofile->f_node; 5375772Sas200622 boolean_t append_only = B_FALSE; 5386030Sjb150015 uint32_t status; 5395331Samw int rc; 5405331Samw 5415331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) 5425331Samw return (0); 5435331Samw 5446030Sjb150015 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, FILE_WRITE_DATA); 5456030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5466030Sjb150015 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, 5475772Sas200622 FILE_APPEND_DATA); 5486030Sjb150015 if (status != NT_STATUS_SUCCESS) 5496030Sjb150015 return (EACCES); 5506030Sjb150015 else 5515772Sas200622 append_only = B_TRUE; 5525772Sas200622 } 5535772Sas200622 554*8934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 5555772Sas200622 5566139Sjb150015 if (append_only && (param->rw_offset < node->n_size)) { 557*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5586030Sjb150015 return (EACCES); 5595772Sas200622 } 5605772Sas200622 5615331Samw if (node->attr.sa_vattr.va_type != VDIR) { 5626139Sjb150015 status = smb_lock_range_access(sr, node, param->rw_offset, 5636139Sjb150015 param->rw_count, B_TRUE); 5646030Sjb150015 if (status != NT_STATUS_SUCCESS) { 565*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5666139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 5676139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 5686030Sjb150015 return (EACCES); 5695331Samw } 5705331Samw } 5715331Samw 5725331Samw node->flags |= NODE_FLAGS_SET_SIZE; 5736139Sjb150015 node->n_size = param->rw_offset; 5745331Samw 575*8934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5765772Sas200622 5776600Sas200622 if ((rc = smb_set_file_size(sr, node)) != 0) 5785331Samw return (rc); 5795331Samw 5805331Samw mutex_enter(&ofile->f_mutex); 5816139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5825331Samw mutex_exit(&ofile->f_mutex); 5835331Samw return (0); 5845331Samw } 5855331Samw 5865331Samw /* 5875331Samw * Set the file size using the value in the node. The file will only be 5885331Samw * updated if NODE_FLAGS_SET_SIZE is set. It is safe to pass a null node 5895331Samw * pointer, we just return success. 5905331Samw * 5915331Samw * The node attributes are refreshed here from the file system. So any 5925331Samw * attributes that are affected by file size changes, i.e. the mtime, 5935331Samw * will be current. 5945331Samw * 5955331Samw * Note that smb_write_andx cannot be used to reduce the file size so, 5965331Samw * if this is required, smb_write is called with a count of zero and 5975331Samw * the appropriate file length in offset. The file should be resized 5985331Samw * to the length specified by the offset. 5995331Samw */ 6005331Samw int 6016600Sas200622 smb_set_file_size(smb_request_t *sr, smb_node_t *node) 6025331Samw { 6035331Samw smb_attr_t new_attr; 6045331Samw 6056600Sas200622 if (node == NULL) 6065331Samw return (0); 6075331Samw 6085331Samw if ((node->flags & NODE_FLAGS_SET_SIZE) == 0) 6095331Samw return (0); 6105331Samw 6115331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 6125331Samw 6135331Samw bzero(&new_attr, sizeof (new_attr)); 6145331Samw new_attr.sa_vattr.va_size = node->n_size; 6155331Samw new_attr.sa_mask = SMB_AT_SIZE; 6165331Samw 6177348SJose.Borrego@Sun.COM return (smb_fsop_setattr(sr, sr->user_cr, node, &new_attr, 6187348SJose.Borrego@Sun.COM &node->attr)); 6195331Samw } 620