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 */ 21*12508Samw@Sun.COM 225331Samw /* 23*12508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 245331Samw */ 255331Samw 265331Samw #include <sys/sdt.h> 2710966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h> 285331Samw #include <smbsrv/smb_fsops.h> 295331Samw #include <smbsrv/netbios.h> 305331Samw 315331Samw 328934SJose.Borrego@Sun.COM /* 338934SJose.Borrego@Sun.COM * The limit in bytes that the marshalling will grow the buffer 348934SJose.Borrego@Sun.COM * chain to accomodate incoming data on SmbWriteX requests. 358934SJose.Borrego@Sun.COM * This sets the upper limit for the data-count per SmbWriteX 368934SJose.Borrego@Sun.COM * request. 378934SJose.Borrego@Sun.COM */ 388934SJose.Borrego@Sun.COM #define SMB_WRITEX_MAX 102400 395331Samw 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; 588934SJose.Borrego@Sun.COM uint16_t count; 595331Samw int rc; 605331Samw 616139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 626139Sjb150015 sr->arg.rw = param; 636139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 646139Sjb150015 658934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off); 666139Sjb150015 678934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 686139Sjb150015 param->rw_offset = (uint64_t)off; 698934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 706139Sjb150015 716139Sjb150015 DTRACE_SMB_2(op__Write__start, smb_request_t *, sr, 726139Sjb150015 smb_rw_param_t *, param); 736139Sjb150015 746139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 756139Sjb150015 } 765331Samw 776139Sjb150015 void 786139Sjb150015 smb_post_write(smb_request_t *sr) 796139Sjb150015 { 806139Sjb150015 DTRACE_SMB_2(op__Write__done, smb_request_t *, sr, 816139Sjb150015 smb_rw_param_t *, sr->arg.rw); 826139Sjb150015 836139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 846139Sjb150015 } 856139Sjb150015 866139Sjb150015 smb_sdrc_t 876139Sjb150015 smb_com_write(smb_request_t *sr) 886139Sjb150015 { 896139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 906139Sjb150015 int rc; 915331Samw 928934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 935331Samw if (sr->fid_ofile == NULL) { 945772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 956139Sjb150015 return (SDRC_ERROR); 965331Samw } 975331Samw 987961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 997961SNatalie.Li@Sun.COM 1006139Sjb150015 if (param->rw_count == 0) { 1015331Samw rc = smb_write_truncate(sr, param); 1025331Samw } else { 1036139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 1045331Samw 1058934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 1066139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 1076139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 1086139Sjb150015 return (SDRC_ERROR); 1095331Samw } 1105331Samw 1118934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 1125331Samw 11311447Samw@Sun.COM rc = smb_common_write(sr, param); 1145331Samw } 1155331Samw 1165331Samw if (rc != 0) { 1176139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 1186139Sjb150015 smbsr_errno(sr, rc); 1196139Sjb150015 return (SDRC_ERROR); 1205331Samw } 1215331Samw 1228934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 1238934SJose.Borrego@Sun.COM (uint16_t)param->rw_count, 0); 1246139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1255331Samw } 1265331Samw 1275331Samw /* 1285331Samw * Write count bytes to a file and then close the file. This function 1295331Samw * can only be used to write to 32-bit offsets and the client must set 1305331Samw * WordCount (6 or 12) correctly in order to locate the data to be 1315331Samw * written. If an error occurs on the write, the file should still be 1325331Samw * closed. If Count is 0, the file is truncated (or extended) to offset. 1335331Samw * 1345331Samw * If the last_write time is non-zero, last_write should be used to set 1355331Samw * the mtime. Otherwise the file system stamps the mtime. Failure to 1365331Samw * set mtime should not result in an error response. 1375331Samw */ 1386030Sjb150015 smb_sdrc_t 1396139Sjb150015 smb_pre_write_and_close(smb_request_t *sr) 1405331Samw { 1416139Sjb150015 smb_rw_param_t *param; 1425331Samw uint32_t off; 1438934SJose.Borrego@Sun.COM uint16_t count; 1446139Sjb150015 int rc; 1455331Samw 1466139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 1476139Sjb150015 sr->arg.rw = param; 1486139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 1495331Samw 1505331Samw if (sr->smb_wct == 12) { 1515331Samw rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, 1528934SJose.Borrego@Sun.COM &count, &off, ¶m->rw_last_write); 1535331Samw } else { 1545331Samw rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 1558934SJose.Borrego@Sun.COM &count, &off, ¶m->rw_last_write); 1565331Samw } 1575331Samw 1588934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 1596139Sjb150015 param->rw_offset = (uint64_t)off; 1606139Sjb150015 1616139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr, 1626139Sjb150015 smb_rw_param_t *, param); 1636139Sjb150015 1646139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1656139Sjb150015 } 1666139Sjb150015 1676139Sjb150015 void 1686139Sjb150015 smb_post_write_and_close(smb_request_t *sr) 1696139Sjb150015 { 1706139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr, 1716139Sjb150015 smb_rw_param_t *, sr->arg.rw); 1726139Sjb150015 1736139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 1746139Sjb150015 } 1756139Sjb150015 1766139Sjb150015 smb_sdrc_t 1776139Sjb150015 smb_com_write_and_close(smb_request_t *sr) 1786139Sjb150015 { 1796139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 1808934SJose.Borrego@Sun.COM uint16_t count; 1816139Sjb150015 int rc = 0; 1825331Samw 1838934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 1845331Samw if (sr->fid_ofile == NULL) { 1855772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 1866139Sjb150015 return (SDRC_ERROR); 1875331Samw } 1885331Samw 1897961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 1907961SNatalie.Li@Sun.COM 1916139Sjb150015 if (param->rw_count == 0) { 1925331Samw rc = smb_write_truncate(sr, param); 1935331Samw } else { 1945331Samw /* 1955331Samw * There may be a bug here: should this be "3.#B"? 1965331Samw */ 1976139Sjb150015 rc = smbsr_decode_data(sr, ".#B", param->rw_count, 1986139Sjb150015 ¶m->rw_vdb); 1995331Samw 2008934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 2016139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 2026139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 2036139Sjb150015 return (SDRC_ERROR); 2045331Samw } 2055331Samw 2068934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 2075331Samw 20811447Samw@Sun.COM rc = smb_common_write(sr, param); 2095331Samw } 2105331Samw 2115331Samw if (rc != 0) { 2126139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 2136139Sjb150015 smbsr_errno(sr, rc); 2146139Sjb150015 return (SDRC_ERROR); 2155331Samw } 2165331Samw 2177348SJose.Borrego@Sun.COM smb_ofile_close(sr->fid_ofile, param->rw_last_write); 2185331Samw 2198934SJose.Borrego@Sun.COM count = (uint16_t)param->rw_count; 2208934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0); 2216139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2225331Samw } 2235331Samw 2245331Samw /* 2255331Samw * Write count bytes to a file at the specified offset and then unlock 2265331Samw * them. Write behind is safe because the client should have the range 2275331Samw * locked and this request is allowed to extend the file - note that 2286139Sjb150015 * offset is limited to 32-bits. 2296139Sjb150015 * 2306139Sjb150015 * Spec advice: it is an error for count to be zero. For compatibility, 2316139Sjb150015 * we take no action and return success. 2325331Samw * 2335331Samw * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 2345331Samw * files. Reject any attempt to use it on other shares. 2355331Samw * 2365331Samw * The response count indicates the actual number of bytes written, which 2375331Samw * will equal the requested count on success. If request and response 2385331Samw * counts differ but there is no error, the client will assume that the 2395331Samw * server encountered a resource issue. 2405331Samw */ 2416030Sjb150015 smb_sdrc_t 2426139Sjb150015 smb_pre_write_and_unlock(smb_request_t *sr) 2435331Samw { 2446139Sjb150015 smb_rw_param_t *param; 2455331Samw uint32_t off; 2468934SJose.Borrego@Sun.COM uint16_t count; 2475331Samw uint16_t remcnt; 2486139Sjb150015 int rc; 2496139Sjb150015 2506139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 2516139Sjb150015 sr->arg.rw = param; 2526139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 2536139Sjb150015 2548934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt); 2556139Sjb150015 2568934SJose.Borrego@Sun.COM param->rw_count = (uint32_t)count; 2576139Sjb150015 param->rw_offset = (uint64_t)off; 2586139Sjb150015 2596139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr, 2606139Sjb150015 smb_rw_param_t *, param); 2616139Sjb150015 2626139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2636139Sjb150015 } 2646139Sjb150015 2656139Sjb150015 void 2666139Sjb150015 smb_post_write_and_unlock(smb_request_t *sr) 2676139Sjb150015 { 2686139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr, 2696139Sjb150015 smb_rw_param_t *, sr->arg.rw); 2706139Sjb150015 2716139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 2726139Sjb150015 } 2736139Sjb150015 2746139Sjb150015 smb_sdrc_t 2756139Sjb150015 smb_com_write_and_unlock(smb_request_t *sr) 2766139Sjb150015 { 2776139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 2786139Sjb150015 uint32_t status; 2795331Samw int rc = 0; 2805331Samw 2815331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 2825772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 2836139Sjb150015 return (SDRC_ERROR); 2845331Samw } 2855331Samw 2868934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 2875331Samw if (sr->fid_ofile == NULL) { 2885772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 2896139Sjb150015 return (SDRC_ERROR); 2905331Samw } 2915331Samw 2927961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 2937961SNatalie.Li@Sun.COM 2946139Sjb150015 if (param->rw_count == 0) { 2956139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0); 2966139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2975331Samw } 2985331Samw 2998934SJose.Borrego@Sun.COM 3006139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 3015331Samw 3028934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) { 3036139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 3046139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 3056139Sjb150015 return (SDRC_ERROR); 3065331Samw } 3075331Samw 3088934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 3095331Samw 31011447Samw@Sun.COM if ((rc = smb_common_write(sr, param)) != 0) { 3116139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 3126139Sjb150015 smbsr_errno(sr, rc); 3136139Sjb150015 return (SDRC_ERROR); 3145331Samw } 3155331Samw 3166139Sjb150015 status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset, 3176139Sjb150015 (uint64_t)param->rw_count); 3186139Sjb150015 if (status != NT_STATUS_SUCCESS) { 3195772Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 320*12508Samw@Sun.COM ERRDOS, ERROR_NOT_LOCKED); 3216139Sjb150015 return (SDRC_ERROR); 3225331Samw } 3235331Samw 3248934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 3258934SJose.Borrego@Sun.COM (uint16_t)param->rw_count, 0); 3266139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3275331Samw } 3285331Samw 3295331Samw /* 3305331Samw * Write bytes to a file (SMB Core). This request was extended in 3315331Samw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 3325331Samw * 14, instead of 12, and including additional offset information. 3335331Samw * 3345331Samw * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 3355331Samw * to truncate a file. A zero length merely transfers zero bytes. 3365331Samw * 3375331Samw * If bit 0 of WriteMode is set, Fid must refer to a disk file and 3385331Samw * the data must be on stable storage before responding. 3398934SJose.Borrego@Sun.COM * 3408934SJose.Borrego@Sun.COM * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5: 3418934SJose.Borrego@Sun.COM * If CAP_LARGE_WRITEX is set, the byte count may be larger than the 3428934SJose.Borrego@Sun.COM * negotiated buffer size and the server is expected to write the 3438934SJose.Borrego@Sun.COM * number of bytes specified. 3445331Samw */ 3456030Sjb150015 smb_sdrc_t 3466139Sjb150015 smb_pre_write_andx(smb_request_t *sr) 3475331Samw { 3486139Sjb150015 smb_rw_param_t *param; 3495331Samw uint32_t off_low; 3505331Samw uint32_t off_high; 3518934SJose.Borrego@Sun.COM uint16_t datalen_low; 3528934SJose.Borrego@Sun.COM uint16_t datalen_high; 3535331Samw uint16_t remcnt; 3546139Sjb150015 int rc; 3555331Samw 3566139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 3576139Sjb150015 sr->arg.rw = param; 3586139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 3595331Samw 3605331Samw if (sr->smb_wct == 14) { 3618934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid, 3628934SJose.Borrego@Sun.COM &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 3638934SJose.Borrego@Sun.COM &datalen_low, ¶m->rw_dsoff, &off_high); 3645331Samw 3656139Sjb150015 param->rw_dsoff -= 63; 3666139Sjb150015 param->rw_offset = ((uint64_t)off_high << 32) | off_low; 3675331Samw } else { 3688934SJose.Borrego@Sun.COM rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid, 3698934SJose.Borrego@Sun.COM &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 3708934SJose.Borrego@Sun.COM &datalen_low, ¶m->rw_dsoff); 3715331Samw 3726139Sjb150015 param->rw_offset = (uint64_t)off_low; 3736139Sjb150015 param->rw_dsoff -= 59; 3745331Samw } 3755331Samw 3768938Samw@Sun.COM param->rw_count = (uint32_t)datalen_low; 3778938Samw@Sun.COM 3788938Samw@Sun.COM if (sr->session->capabilities & CAP_LARGE_WRITEX) 3798938Samw@Sun.COM param->rw_count |= ((uint32_t)datalen_high << 16); 3808934SJose.Borrego@Sun.COM 3816139Sjb150015 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, 3826139Sjb150015 smb_rw_param_t *, param); 3836139Sjb150015 3846139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3856139Sjb150015 } 3866139Sjb150015 3876139Sjb150015 void 3886139Sjb150015 smb_post_write_andx(smb_request_t *sr) 3896139Sjb150015 { 3906139Sjb150015 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr, 3916139Sjb150015 smb_rw_param_t *, sr->arg.rw); 3926139Sjb150015 3936139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 3946139Sjb150015 } 3956139Sjb150015 3966139Sjb150015 smb_sdrc_t 3976139Sjb150015 smb_com_write_andx(smb_request_t *sr) 3986139Sjb150015 { 3996139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 4008934SJose.Borrego@Sun.COM uint16_t count_high; 4018934SJose.Borrego@Sun.COM uint16_t count_low; 4026139Sjb150015 int rc; 4036139Sjb150015 4046139Sjb150015 ASSERT(param); 4056139Sjb150015 ASSERT(param->rw_magic == SMB_RW_MAGIC); 4065331Samw 4078934SJose.Borrego@Sun.COM smbsr_lookup_file(sr); 4085331Samw if (sr->fid_ofile == NULL) { 4095772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 4106139Sjb150015 return (SDRC_ERROR); 4115331Samw } 4125331Samw 4137961SNatalie.Li@Sun.COM sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 4147961SNatalie.Li@Sun.COM 4156139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) && 41611447Samw@Sun.COM STYPE_ISIPC(sr->tid_tree->t_res_type)) { 4175772Sas200622 smbsr_error(sr, 0, ERRSRV, ERRaccess); 4186139Sjb150015 return (SDRC_ERROR); 4195331Samw } 4205331Samw 4218934SJose.Borrego@Sun.COM sr->smb_data.max_bytes = SMB_WRITEX_MAX; 4226139Sjb150015 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, 4236139Sjb150015 ¶m->rw_vdb); 4248934SJose.Borrego@Sun.COM 4258934SJose.Borrego@Sun.COM if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 4266139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 4276139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 4286139Sjb150015 return (SDRC_ERROR); 4295331Samw } 4305331Samw 4318934SJose.Borrego@Sun.COM param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 4325331Samw 4336139Sjb150015 if (param->rw_count != 0) { 43411447Samw@Sun.COM if ((rc = smb_common_write(sr, param)) != 0) { 4356139Sjb150015 if (sr->smb_error.status != 4366139Sjb150015 NT_STATUS_FILE_LOCK_CONFLICT) 4376139Sjb150015 smbsr_errno(sr, rc); 4386139Sjb150015 return (SDRC_ERROR); 4395331Samw } 4405331Samw } 4415331Samw 4428934SJose.Borrego@Sun.COM count_low = param->rw_count & 0xFFFF; 4438934SJose.Borrego@Sun.COM count_high = (param->rw_count >> 16) & 0xFF; 4448934SJose.Borrego@Sun.COM 4458934SJose.Borrego@Sun.COM rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww", 4468934SJose.Borrego@Sun.COM 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0); 4475331Samw 4486139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 4495331Samw } 4505331Samw 4515331Samw /* 4525331Samw * Common function for writing files or IPC/MSRPC named pipes. 4535331Samw * 4545331Samw * Returns errno values. 4555331Samw */ 45611447Samw@Sun.COM int 45711447Samw@Sun.COM smb_common_write(smb_request_t *sr, smb_rw_param_t *param) 4585331Samw { 45910001SJoyce.McIntosh@Sun.COM smb_ofile_t *ofile = sr->fid_ofile; 4605331Samw smb_node_t *node; 4617052Samw int stability = 0; 4625331Samw uint32_t lcount; 4635331Samw int rc = 0; 4645331Samw 4655331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 4665331Samw case STYPE_DISKTREE: 46711447Samw@Sun.COM case STYPE_PRINTQ: 4685331Samw node = ofile->f_node; 4695331Samw 47010001SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node)) { 4716139Sjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset, 4726139Sjb150015 param->rw_count, B_TRUE); 4736139Sjb150015 if (rc != NT_STATUS_SUCCESS) { 4746139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 4756139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 4766139Sjb150015 return (EACCES); 4776139Sjb150015 } 4785331Samw } 4795331Samw 4806139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) || 4815331Samw (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 4827052Samw stability = FSYNC; 4835331Samw } 4845331Samw 4855331Samw rc = smb_fsop_write(sr, sr->user_cr, node, 48610001SJoyce.McIntosh@Sun.COM ¶m->rw_vdb.vdb_uio, &lcount, stability); 4875331Samw 4885331Samw if (rc) 4895331Samw return (rc); 4905331Samw 49110001SJoyce.McIntosh@Sun.COM smb_ofile_set_write_time_pending(ofile); 4925331Samw 4938934SJose.Borrego@Sun.COM param->rw_count = lcount; 4945331Samw break; 4955331Samw 4965331Samw case STYPE_IPC: 4978934SJose.Borrego@Sun.COM param->rw_count = param->rw_vdb.vdb_uio.uio_resid; 4985331Samw 4998934SJose.Borrego@Sun.COM if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0) 5006139Sjb150015 param->rw_count = 0; 5015331Samw break; 5025331Samw 5035331Samw default: 5045331Samw rc = EACCES; 5055331Samw break; 5065331Samw } 5075331Samw 5085331Samw if (rc != 0) 5095331Samw return (rc); 5105331Samw 5115331Samw mutex_enter(&ofile->f_mutex); 5126139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5135331Samw mutex_exit(&ofile->f_mutex); 5145331Samw return (rc); 5155331Samw } 5165331Samw 5175331Samw /* 5185331Samw * Truncate a disk file to the specified offset. 5195331Samw * Typically, w_count will be zero here. 5205331Samw * 52110001SJoyce.McIntosh@Sun.COM * Note that smb_write_andx cannot be used to reduce the file size so, 52210001SJoyce.McIntosh@Sun.COM * if this is required, smb_write is called with a count of zero and 52310001SJoyce.McIntosh@Sun.COM * the appropriate file length in offset. The file should be resized 52410001SJoyce.McIntosh@Sun.COM * to the length specified by the offset. 52510001SJoyce.McIntosh@Sun.COM * 5265331Samw * Returns errno values. 5275331Samw */ 5286030Sjb150015 static int 5296139Sjb150015 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) 5305331Samw { 53110001SJoyce.McIntosh@Sun.COM smb_ofile_t *ofile = sr->fid_ofile; 5325331Samw smb_node_t *node = ofile->f_node; 53310001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 5346030Sjb150015 uint32_t status; 5355331Samw int rc; 5365331Samw 53711447Samw@Sun.COM if (STYPE_ISIPC(sr->tid_tree->t_res_type)) 5385331Samw return (0); 5395331Samw 5408934SJose.Borrego@Sun.COM mutex_enter(&node->n_mutex); 54110001SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node)) { 5426139Sjb150015 status = smb_lock_range_access(sr, node, param->rw_offset, 5436139Sjb150015 param->rw_count, B_TRUE); 5446030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5458934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5466139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 5476139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 5486030Sjb150015 return (EACCES); 5495331Samw } 5505331Samw } 5518934SJose.Borrego@Sun.COM mutex_exit(&node->n_mutex); 5525772Sas200622 55310001SJoyce.McIntosh@Sun.COM bzero(&attr, sizeof (smb_attr_t)); 55410001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_SIZE; 55510001SJoyce.McIntosh@Sun.COM attr.sa_vattr.va_size = param->rw_offset; 55610001SJoyce.McIntosh@Sun.COM rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr); 55710001SJoyce.McIntosh@Sun.COM if (rc != 0) 5585331Samw return (rc); 5595331Samw 5605331Samw mutex_enter(&ofile->f_mutex); 5616139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5625331Samw mutex_exit(&ofile->f_mutex); 5635331Samw return (0); 5645331Samw } 565