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 /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw #include <sys/sdt.h> 295331Samw #include <smbsrv/smb_incl.h> 305331Samw #include <smbsrv/smb_fsops.h> 315331Samw #include <smbsrv/mbuf.h> 325331Samw #include <smbsrv/netbios.h> 335331Samw 345331Samw 355331Samw #define SMB_WRMODE_WRITE_THRU 0x0001 365331Samw #define SMB_WRMODE_IS_STABLE(M) ((M) & SMB_WRMODE_WRITE_THRU) 375331Samw 385331Samw 39*6139Sjb150015 static int smb_write_common(smb_request_t *, smb_rw_param_t *); 40*6139Sjb150015 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *); 41*6139Sjb150015 int smb_set_file_size(smb_request_t *); 425331Samw 435331Samw 445331Samw /* 455331Samw * Write count bytes at the specified offset in a file. The offset is 465331Samw * limited to 32-bits. If the count is zero, the file is truncated to 475331Samw * the length specified by the offset. 485331Samw * 495331Samw * The response count indicates the actual number of bytes written, which 505331Samw * will equal the requested count on success. If request and response 515331Samw * counts differ but there is no error, the client will assume that the 525331Samw * server encountered a resource issue. 535331Samw */ 546030Sjb150015 smb_sdrc_t 55*6139Sjb150015 smb_pre_write(smb_request_t *sr) 565331Samw { 57*6139Sjb150015 smb_rw_param_t *param; 585331Samw uint32_t off; 595331Samw int rc; 605331Samw 61*6139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 62*6139Sjb150015 sr->arg.rw = param; 63*6139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 64*6139Sjb150015 65*6139Sjb150015 rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, ¶m->rw_count, &off); 66*6139Sjb150015 67*6139Sjb150015 param->rw_offset = (uint64_t)off; 68*6139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 69*6139Sjb150015 70*6139Sjb150015 DTRACE_SMB_2(op__Write__start, smb_request_t *, sr, 71*6139Sjb150015 smb_rw_param_t *, param); 72*6139Sjb150015 73*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 74*6139Sjb150015 } 755331Samw 76*6139Sjb150015 void 77*6139Sjb150015 smb_post_write(smb_request_t *sr) 78*6139Sjb150015 { 79*6139Sjb150015 DTRACE_SMB_2(op__Write__done, smb_request_t *, sr, 80*6139Sjb150015 smb_rw_param_t *, sr->arg.rw); 81*6139Sjb150015 82*6139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 83*6139Sjb150015 } 84*6139Sjb150015 85*6139Sjb150015 smb_sdrc_t 86*6139Sjb150015 smb_com_write(smb_request_t *sr) 87*6139Sjb150015 { 88*6139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 89*6139Sjb150015 int rc; 905331Samw 915331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 925331Samw if (sr->fid_ofile == NULL) { 935772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 94*6139Sjb150015 return (SDRC_ERROR); 955331Samw } 965331Samw 97*6139Sjb150015 if (param->rw_count == 0) { 985331Samw rc = smb_write_truncate(sr, param); 995331Samw } else { 100*6139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 1015331Samw 102*6139Sjb150015 if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { 103*6139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 104*6139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 105*6139Sjb150015 return (SDRC_ERROR); 1065331Samw } 1075331Samw 108*6139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 1095331Samw 1105331Samw rc = smb_write_common(sr, param); 1115331Samw } 1125331Samw 1135331Samw if (rc != 0) { 114*6139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 115*6139Sjb150015 smbsr_errno(sr, rc); 116*6139Sjb150015 return (SDRC_ERROR); 1175331Samw } 1185331Samw 119*6139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); 120*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1215331Samw } 1225331Samw 1235331Samw /* 1245331Samw * Write count bytes to a file and then close the file. This function 1255331Samw * can only be used to write to 32-bit offsets and the client must set 1265331Samw * WordCount (6 or 12) correctly in order to locate the data to be 1275331Samw * written. If an error occurs on the write, the file should still be 1285331Samw * closed. If Count is 0, the file is truncated (or extended) to offset. 1295331Samw * 1305331Samw * If the last_write time is non-zero, last_write should be used to set 1315331Samw * the mtime. Otherwise the file system stamps the mtime. Failure to 1325331Samw * set mtime should not result in an error response. 1335331Samw */ 1346030Sjb150015 smb_sdrc_t 135*6139Sjb150015 smb_pre_write_and_close(smb_request_t *sr) 1365331Samw { 137*6139Sjb150015 smb_rw_param_t *param; 1385331Samw uint32_t off; 139*6139Sjb150015 int rc; 1405331Samw 141*6139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 142*6139Sjb150015 sr->arg.rw = param; 143*6139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 1445331Samw 1455331Samw if (sr->smb_wct == 12) { 1465331Samw rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, 147*6139Sjb150015 ¶m->rw_count, &off, ¶m->rw_last_write); 1485331Samw } else { 1495331Samw rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 150*6139Sjb150015 ¶m->rw_count, &off, ¶m->rw_last_write); 1515331Samw } 1525331Samw 153*6139Sjb150015 param->rw_offset = (uint64_t)off; 154*6139Sjb150015 155*6139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr, 156*6139Sjb150015 smb_rw_param_t *, param); 157*6139Sjb150015 158*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 159*6139Sjb150015 } 160*6139Sjb150015 161*6139Sjb150015 void 162*6139Sjb150015 smb_post_write_and_close(smb_request_t *sr) 163*6139Sjb150015 { 164*6139Sjb150015 DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr, 165*6139Sjb150015 smb_rw_param_t *, sr->arg.rw); 166*6139Sjb150015 167*6139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 168*6139Sjb150015 } 169*6139Sjb150015 170*6139Sjb150015 smb_sdrc_t 171*6139Sjb150015 smb_com_write_and_close(smb_request_t *sr) 172*6139Sjb150015 { 173*6139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 174*6139Sjb150015 int rc = 0; 1755331Samw 1765331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 1775331Samw if (sr->fid_ofile == NULL) { 1785772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 179*6139Sjb150015 return (SDRC_ERROR); 1805331Samw } 1815331Samw 182*6139Sjb150015 if (param->rw_count == 0) { 1835331Samw rc = smb_write_truncate(sr, param); 1845331Samw } else { 1855331Samw /* 1865331Samw * There may be a bug here: should this be "3.#B"? 1875331Samw */ 188*6139Sjb150015 rc = smbsr_decode_data(sr, ".#B", param->rw_count, 189*6139Sjb150015 ¶m->rw_vdb); 1905331Samw 191*6139Sjb150015 if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { 192*6139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 193*6139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 194*6139Sjb150015 return (SDRC_ERROR); 1955331Samw } 1965331Samw 197*6139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 1985331Samw 1995331Samw rc = smb_write_common(sr, param); 2005331Samw } 2015331Samw 2025331Samw if (rc != 0) { 203*6139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 204*6139Sjb150015 smbsr_errno(sr, rc); 205*6139Sjb150015 return (SDRC_ERROR); 2065331Samw } 2075331Samw 208*6139Sjb150015 if ((rc = smb_common_close(sr, param->rw_last_write)) != 0) { 2095772Sas200622 smbsr_errno(sr, rc); 210*6139Sjb150015 return (SDRC_ERROR); 2115331Samw } 2125331Samw 213*6139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); 214*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2155331Samw } 2165331Samw 2175331Samw /* 2185331Samw * Write count bytes to a file at the specified offset and then unlock 2195331Samw * them. Write behind is safe because the client should have the range 2205331Samw * locked and this request is allowed to extend the file - note that 221*6139Sjb150015 * offset is limited to 32-bits. 222*6139Sjb150015 * 223*6139Sjb150015 * Spec advice: it is an error for count to be zero. For compatibility, 224*6139Sjb150015 * we take no action and return success. 2255331Samw * 2265331Samw * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 2275331Samw * files. Reject any attempt to use it on other shares. 2285331Samw * 2295331Samw * The response count indicates the actual number of bytes written, which 2305331Samw * will equal the requested count on success. If request and response 2315331Samw * counts differ but there is no error, the client will assume that the 2325331Samw * server encountered a resource issue. 2335331Samw */ 2346030Sjb150015 smb_sdrc_t 235*6139Sjb150015 smb_pre_write_and_unlock(smb_request_t *sr) 2365331Samw { 237*6139Sjb150015 smb_rw_param_t *param; 2385331Samw uint32_t off; 2395331Samw uint16_t remcnt; 240*6139Sjb150015 int rc; 241*6139Sjb150015 242*6139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 243*6139Sjb150015 sr->arg.rw = param; 244*6139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 245*6139Sjb150015 246*6139Sjb150015 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, ¶m->rw_count, &off, 247*6139Sjb150015 &remcnt); 248*6139Sjb150015 249*6139Sjb150015 param->rw_offset = (uint64_t)off; 250*6139Sjb150015 251*6139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr, 252*6139Sjb150015 smb_rw_param_t *, param); 253*6139Sjb150015 254*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 255*6139Sjb150015 } 256*6139Sjb150015 257*6139Sjb150015 void 258*6139Sjb150015 smb_post_write_and_unlock(smb_request_t *sr) 259*6139Sjb150015 { 260*6139Sjb150015 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr, 261*6139Sjb150015 smb_rw_param_t *, sr->arg.rw); 262*6139Sjb150015 263*6139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 264*6139Sjb150015 } 265*6139Sjb150015 266*6139Sjb150015 smb_sdrc_t 267*6139Sjb150015 smb_com_write_and_unlock(smb_request_t *sr) 268*6139Sjb150015 { 269*6139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 270*6139Sjb150015 uint32_t status; 2715331Samw int rc = 0; 2725331Samw 2735331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 2745772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 275*6139Sjb150015 return (SDRC_ERROR); 2765331Samw } 2775331Samw 2785331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 2795331Samw if (sr->fid_ofile == NULL) { 2805772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 281*6139Sjb150015 return (SDRC_ERROR); 2825331Samw } 2835331Samw 284*6139Sjb150015 if (param->rw_count == 0) { 285*6139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0); 286*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2875331Samw } 2885331Samw 289*6139Sjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 2905331Samw 291*6139Sjb150015 if ((rc != 0) || (param->rw_count != param->rw_vdb.len)) { 292*6139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 293*6139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 294*6139Sjb150015 return (SDRC_ERROR); 2955331Samw } 2965331Samw 297*6139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 2985331Samw 2995331Samw if ((rc = smb_write_common(sr, param)) != 0) { 300*6139Sjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 301*6139Sjb150015 smbsr_errno(sr, rc); 302*6139Sjb150015 return (SDRC_ERROR); 3035331Samw } 3045331Samw 305*6139Sjb150015 status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset, 306*6139Sjb150015 (uint64_t)param->rw_count); 307*6139Sjb150015 if (status != NT_STATUS_SUCCESS) { 3085772Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 3095772Sas200622 ERRDOS, ERRnotlocked); 310*6139Sjb150015 return (SDRC_ERROR); 3115331Samw } 3125331Samw 313*6139Sjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0); 314*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3155331Samw } 3165331Samw 3175331Samw /* 3185331Samw * Write bytes to a file (SMB Core). This request was extended in 3195331Samw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 3205331Samw * 14, instead of 12, and including additional offset information. 3215331Samw * 3225331Samw * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 3235331Samw * to truncate a file. A zero length merely transfers zero bytes. 3245331Samw * 3255331Samw * If bit 0 of WriteMode is set, Fid must refer to a disk file and 3265331Samw * the data must be on stable storage before responding. 3275331Samw */ 3286030Sjb150015 smb_sdrc_t 329*6139Sjb150015 smb_pre_write_andx(smb_request_t *sr) 3305331Samw { 331*6139Sjb150015 smb_rw_param_t *param; 3325331Samw uint32_t off_low; 3335331Samw uint32_t off_high; 3345331Samw uint16_t remcnt; 335*6139Sjb150015 int rc; 3365331Samw 337*6139Sjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 338*6139Sjb150015 sr->arg.rw = param; 339*6139Sjb150015 param->rw_magic = SMB_RW_MAGIC; 3405331Samw 3415331Samw if (sr->smb_wct == 14) { 3425331Samw rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid, 343*6139Sjb150015 &off_low, ¶m->rw_mode, &remcnt, ¶m->rw_count, 344*6139Sjb150015 ¶m->rw_dsoff, &off_high); 3455331Samw 346*6139Sjb150015 param->rw_dsoff -= 63; 347*6139Sjb150015 param->rw_offset = ((uint64_t)off_high << 32) | off_low; 3485331Samw } else { 3495331Samw rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid, 350*6139Sjb150015 &off_low, ¶m->rw_mode, &remcnt, ¶m->rw_count, 351*6139Sjb150015 ¶m->rw_dsoff); 3525331Samw 353*6139Sjb150015 param->rw_offset = (uint64_t)off_low; 354*6139Sjb150015 param->rw_dsoff -= 59; 3555331Samw } 3565331Samw 357*6139Sjb150015 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, 358*6139Sjb150015 smb_rw_param_t *, param); 359*6139Sjb150015 360*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 361*6139Sjb150015 } 362*6139Sjb150015 363*6139Sjb150015 void 364*6139Sjb150015 smb_post_write_andx(smb_request_t *sr) 365*6139Sjb150015 { 366*6139Sjb150015 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr, 367*6139Sjb150015 smb_rw_param_t *, sr->arg.rw); 368*6139Sjb150015 369*6139Sjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 370*6139Sjb150015 } 371*6139Sjb150015 372*6139Sjb150015 smb_sdrc_t 373*6139Sjb150015 smb_com_write_andx(smb_request_t *sr) 374*6139Sjb150015 { 375*6139Sjb150015 smb_rw_param_t *param = sr->arg.rw; 376*6139Sjb150015 int rc; 377*6139Sjb150015 378*6139Sjb150015 ASSERT(param); 379*6139Sjb150015 ASSERT(param->rw_magic == SMB_RW_MAGIC); 3805331Samw 3815331Samw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 3825331Samw if (sr->fid_ofile == NULL) { 3835772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 384*6139Sjb150015 return (SDRC_ERROR); 3855331Samw } 3865331Samw 387*6139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) && 3885331Samw STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 3895772Sas200622 smbsr_error(sr, 0, ERRSRV, ERRaccess); 390*6139Sjb150015 return (SDRC_ERROR); 3915331Samw } 3925331Samw 393*6139Sjb150015 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, 394*6139Sjb150015 ¶m->rw_vdb); 395*6139Sjb150015 if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) { 396*6139Sjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 397*6139Sjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 398*6139Sjb150015 return (SDRC_ERROR); 3995331Samw } 4005331Samw 401*6139Sjb150015 param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset; 4025331Samw 403*6139Sjb150015 if (param->rw_count != 0) { 4045331Samw if ((rc = smb_write_common(sr, param)) != 0) { 405*6139Sjb150015 if (sr->smb_error.status != 406*6139Sjb150015 NT_STATUS_FILE_LOCK_CONFLICT) 407*6139Sjb150015 smbsr_errno(sr, rc); 408*6139Sjb150015 return (SDRC_ERROR); 4095331Samw } 4105331Samw } 4115331Samw 4126030Sjb150015 rc = smbsr_encode_result(sr, 6, 0, "bb1.ww6.w", 413*6139Sjb150015 6, sr->andx_com, 15, param->rw_count, 0); 4145331Samw 415*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 4165331Samw } 4175331Samw 4185331Samw /* 4195331Samw * Common function for writing files or IPC/MSRPC named pipes. 4205331Samw * 4215331Samw * Returns errno values. 4225331Samw */ 4236030Sjb150015 static int 424*6139Sjb150015 smb_write_common(smb_request_t *sr, smb_rw_param_t *param) 4255331Samw { 4265331Samw struct smb_ofile *ofile = sr->fid_ofile; 4275331Samw smb_node_t *node; 4285331Samw uint32_t stability = FSSTAB_UNSTABLE; 4295331Samw uint32_t lcount; 4305331Samw int rc = 0; 4315331Samw 4325331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 4335331Samw case STYPE_DISKTREE: 4345331Samw node = ofile->f_node; 4355331Samw 4365331Samw if (node->attr.sa_vattr.va_type != VDIR) { 437*6139Sjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset, 438*6139Sjb150015 param->rw_count, B_TRUE); 439*6139Sjb150015 if (rc != NT_STATUS_SUCCESS) { 440*6139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 441*6139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 442*6139Sjb150015 return (EACCES); 443*6139Sjb150015 } 4445331Samw } 4455331Samw 446*6139Sjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) || 4475331Samw (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 4485331Samw stability = FSSTAB_FILE_SYNC; 4495331Samw } 4505331Samw 4515331Samw rc = smb_fsop_write(sr, sr->user_cr, node, 452*6139Sjb150015 ¶m->rw_vdb.uio, &lcount, &node->attr, &stability); 4535331Samw 4545331Samw if (rc) 4555331Samw return (rc); 4565331Samw 4575331Samw node->flags |= NODE_FLAGS_SYNCATIME; 4585331Samw 4595331Samw if (node->flags & NODE_FLAGS_SET_SIZE) { 460*6139Sjb150015 if ((param->rw_offset + lcount) >= node->n_size) { 4615331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 462*6139Sjb150015 node->n_size = param->rw_offset + lcount; 4635331Samw } 4645331Samw } 4655331Samw 466*6139Sjb150015 param->rw_count = (uint16_t)lcount; 4675331Samw break; 4685331Samw 4695331Samw case STYPE_IPC: 470*6139Sjb150015 param->rw_count = (uint16_t)param->rw_vdb.uio.uio_resid; 4715331Samw 472*6139Sjb150015 if ((rc = smb_rpc_write(sr, ¶m->rw_vdb.uio)) != 0) 473*6139Sjb150015 param->rw_count = 0; 4745331Samw break; 4755331Samw 4765331Samw default: 4775331Samw rc = EACCES; 4785331Samw break; 4795331Samw } 4805331Samw 4815331Samw if (rc != 0) 4825331Samw return (rc); 4835331Samw 4845331Samw mutex_enter(&ofile->f_mutex); 485*6139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 4865331Samw mutex_exit(&ofile->f_mutex); 4875331Samw return (rc); 4885331Samw } 4895331Samw 4905331Samw /* 4915331Samw * Truncate a disk file to the specified offset. 4925331Samw * Typically, w_count will be zero here. 4935331Samw * 4945331Samw * Returns errno values. 4955331Samw */ 4966030Sjb150015 static int 497*6139Sjb150015 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) 4985331Samw { 4995331Samw struct smb_ofile *ofile = sr->fid_ofile; 5005331Samw smb_node_t *node = ofile->f_node; 5015772Sas200622 boolean_t append_only = B_FALSE; 5026030Sjb150015 uint32_t status; 5035331Samw int rc; 5045331Samw 5055331Samw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) 5065331Samw return (0); 5075331Samw 5086030Sjb150015 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, FILE_WRITE_DATA); 5096030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5106030Sjb150015 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, 5115772Sas200622 FILE_APPEND_DATA); 5126030Sjb150015 if (status != NT_STATUS_SUCCESS) 5136030Sjb150015 return (EACCES); 5146030Sjb150015 else 5155772Sas200622 append_only = B_TRUE; 5165772Sas200622 } 5175772Sas200622 5185772Sas200622 smb_rwx_xenter(&node->n_lock); 5195772Sas200622 520*6139Sjb150015 if (append_only && (param->rw_offset < node->n_size)) { 5215772Sas200622 smb_rwx_xexit(&node->n_lock); 5226030Sjb150015 return (EACCES); 5235772Sas200622 } 5245772Sas200622 5255331Samw if (node->attr.sa_vattr.va_type != VDIR) { 526*6139Sjb150015 status = smb_lock_range_access(sr, node, param->rw_offset, 527*6139Sjb150015 param->rw_count, B_TRUE); 5286030Sjb150015 if (status != NT_STATUS_SUCCESS) { 5295772Sas200622 smb_rwx_xexit(&node->n_lock); 530*6139Sjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 531*6139Sjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 5326030Sjb150015 return (EACCES); 5335331Samw } 5345331Samw } 5355331Samw 5365331Samw node->flags |= NODE_FLAGS_SET_SIZE; 537*6139Sjb150015 node->n_size = param->rw_offset; 5385331Samw 5395772Sas200622 smb_rwx_xexit(&node->n_lock); 5405772Sas200622 5415331Samw if ((rc = smb_set_file_size(sr)) != 0) 5425331Samw return (rc); 5435331Samw 5445331Samw mutex_enter(&ofile->f_mutex); 545*6139Sjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 5465331Samw mutex_exit(&ofile->f_mutex); 5475331Samw return (0); 5485331Samw } 5495331Samw 5505331Samw /* 5515331Samw * Set the file size using the value in the node. The file will only be 5525331Samw * updated if NODE_FLAGS_SET_SIZE is set. It is safe to pass a null node 5535331Samw * pointer, we just return success. 5545331Samw * 5555331Samw * The node attributes are refreshed here from the file system. So any 5565331Samw * attributes that are affected by file size changes, i.e. the mtime, 5575331Samw * will be current. 5585331Samw * 5595331Samw * Note that smb_write_andx cannot be used to reduce the file size so, 5605331Samw * if this is required, smb_write is called with a count of zero and 5615331Samw * the appropriate file length in offset. The file should be resized 5625331Samw * to the length specified by the offset. 5635331Samw * 5645331Samw * Returns 0 on success. Otherwise returns EACCES. 5655331Samw */ 5665331Samw int 567*6139Sjb150015 smb_set_file_size(smb_request_t *sr) 5685331Samw { 5695331Samw struct smb_node *node; 5705331Samw smb_attr_t new_attr; 5715331Samw uint32_t dosattr; 5725331Samw 5735331Samw if ((node = sr->fid_ofile->f_node) == 0) 5745331Samw return (0); 5755331Samw 5765331Samw if ((node->flags & NODE_FLAGS_SET_SIZE) == 0) 5775331Samw return (0); 5785331Samw 5795331Samw node->flags &= ~NODE_FLAGS_SET_SIZE; 5805331Samw 5815331Samw dosattr = smb_node_get_dosattr(node); 5825331Samw 5835331Samw if (dosattr & SMB_FA_READONLY) { 5845331Samw if (((node->flags & NODE_FLAGS_CREATED) == 0) || 5855331Samw (sr->session->s_kid != node->n_orig_session_id)) 5865331Samw return (EACCES); 5875331Samw } 5885331Samw 5895331Samw bzero(&new_attr, sizeof (new_attr)); 5905331Samw new_attr.sa_vattr.va_size = node->n_size; 5915331Samw new_attr.sa_mask = SMB_AT_SIZE; 5925331Samw 5935331Samw (void) smb_fsop_setattr(sr, sr->user_cr, node, &new_attr, 5945331Samw &node->attr); 5955331Samw 5965331Samw return (0); 5975331Samw } 598