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 */
2112508Samw@Sun.COM
225331Samw /*
2312508Samw@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
smb_pre_write(smb_request_t * sr)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
smb_post_write(smb_request_t * sr)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
smb_com_write(smb_request_t * sr)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
smb_pre_write_and_close(smb_request_t * sr)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
smb_post_write_and_close(smb_request_t * sr)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
smb_com_write_and_close(smb_request_t * sr)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
smb_pre_write_and_unlock(smb_request_t * sr)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
smb_post_write_and_unlock(smb_request_t * sr)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
smb_com_write_and_unlock(smb_request_t * sr)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,
32012508Samw@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
smb_pre_write_andx(smb_request_t * sr)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
smb_post_write_andx(smb_request_t * sr)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
smb_com_write_andx(smb_request_t * sr)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
smb_common_write(smb_request_t * sr,smb_rw_param_t * param)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
493*12890SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node))
494*12890SJoyce.McIntosh@Sun.COM smb_oplock_break_levelII(node);
495*12890SJoyce.McIntosh@Sun.COM
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
smb_write_truncate(smb_request_t * sr,smb_rw_param_t * param)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
54011447Samw@Sun.COM if (STYPE_ISIPC(sr->tid_tree->t_res_type))
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