1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21148c5f43SAlan Wright 22da6c28aaSamw /* 23148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24*1fb4a876SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 25da6c28aaSamw */ 26da6c28aaSamw 27da6c28aaSamw #include <sys/sdt.h> 28bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h> 29da6c28aaSamw #include <smbsrv/smb_fsops.h> 30da6c28aaSamw #include <smbsrv/netbios.h> 31da6c28aaSamw 32da6c28aaSamw 33faa1795aSjb150015 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *); 34da6c28aaSamw 35da6c28aaSamw 36da6c28aaSamw /* 37da6c28aaSamw * Write count bytes at the specified offset in a file. The offset is 38da6c28aaSamw * limited to 32-bits. If the count is zero, the file is truncated to 39da6c28aaSamw * the length specified by the offset. 40da6c28aaSamw * 41da6c28aaSamw * The response count indicates the actual number of bytes written, which 42da6c28aaSamw * will equal the requested count on success. If request and response 43da6c28aaSamw * counts differ but there is no error, the client will assume that the 44da6c28aaSamw * server encountered a resource issue. 45da6c28aaSamw */ 467b59d02dSjb150015 smb_sdrc_t 47faa1795aSjb150015 smb_pre_write(smb_request_t *sr) 48da6c28aaSamw { 49faa1795aSjb150015 smb_rw_param_t *param; 50da6c28aaSamw uint32_t off; 512c2961f8Sjose borrego uint16_t count; 52da6c28aaSamw int rc; 53da6c28aaSamw 54faa1795aSjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 55faa1795aSjb150015 sr->arg.rw = param; 56faa1795aSjb150015 param->rw_magic = SMB_RW_MAGIC; 57da6c28aaSamw 582c2961f8Sjose borrego rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off); 59faa1795aSjb150015 602c2961f8Sjose borrego param->rw_count = (uint32_t)count; 61faa1795aSjb150015 param->rw_offset = (uint64_t)off; 622c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 63faa1795aSjb150015 64faa1795aSjb150015 DTRACE_SMB_2(op__Write__start, smb_request_t *, sr, 65faa1795aSjb150015 smb_rw_param_t *, param); 66faa1795aSjb150015 67faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 68da6c28aaSamw } 69da6c28aaSamw 70faa1795aSjb150015 void 71faa1795aSjb150015 smb_post_write(smb_request_t *sr) 72faa1795aSjb150015 { 73faa1795aSjb150015 DTRACE_SMB_2(op__Write__done, smb_request_t *, sr, 74faa1795aSjb150015 smb_rw_param_t *, sr->arg.rw); 75faa1795aSjb150015 76faa1795aSjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 77faa1795aSjb150015 } 78faa1795aSjb150015 79faa1795aSjb150015 smb_sdrc_t 80faa1795aSjb150015 smb_com_write(smb_request_t *sr) 81faa1795aSjb150015 { 82faa1795aSjb150015 smb_rw_param_t *param = sr->arg.rw; 83faa1795aSjb150015 int rc; 84faa1795aSjb150015 852c2961f8Sjose borrego smbsr_lookup_file(sr); 86da6c28aaSamw if (sr->fid_ofile == NULL) { 87dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 88faa1795aSjb150015 return (SDRC_ERROR); 89da6c28aaSamw } 90da6c28aaSamw 91b89a8333Snatalie li - Sun Microsystems - Irvine United States sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 92b89a8333Snatalie li - Sun Microsystems - Irvine United States 93faa1795aSjb150015 if (param->rw_count == 0) { 94da6c28aaSamw rc = smb_write_truncate(sr, param); 95da6c28aaSamw } else { 96faa1795aSjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 97da6c28aaSamw 982c2961f8Sjose borrego if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 99faa1795aSjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 100faa1795aSjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 101faa1795aSjb150015 return (SDRC_ERROR); 102da6c28aaSamw } 103da6c28aaSamw 1042c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 105da6c28aaSamw 106f96bd5c8SAlan Wright rc = smb_common_write(sr, param); 107da6c28aaSamw } 108da6c28aaSamw 109da6c28aaSamw if (rc != 0) { 110faa1795aSjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 111dc20a302Sas200622 smbsr_errno(sr, rc); 112faa1795aSjb150015 return (SDRC_ERROR); 113da6c28aaSamw } 114da6c28aaSamw 1152c2961f8Sjose borrego rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 1162c2961f8Sjose borrego (uint16_t)param->rw_count, 0); 117faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 118da6c28aaSamw } 119da6c28aaSamw 120da6c28aaSamw /* 121da6c28aaSamw * Write count bytes to a file and then close the file. This function 122da6c28aaSamw * can only be used to write to 32-bit offsets and the client must set 123da6c28aaSamw * WordCount (6 or 12) correctly in order to locate the data to be 124da6c28aaSamw * written. If an error occurs on the write, the file should still be 125da6c28aaSamw * closed. If Count is 0, the file is truncated (or extended) to offset. 126da6c28aaSamw * 127da6c28aaSamw * If the last_write time is non-zero, last_write should be used to set 128da6c28aaSamw * the mtime. Otherwise the file system stamps the mtime. Failure to 129da6c28aaSamw * set mtime should not result in an error response. 130da6c28aaSamw */ 1317b59d02dSjb150015 smb_sdrc_t 132faa1795aSjb150015 smb_pre_write_and_close(smb_request_t *sr) 133da6c28aaSamw { 134faa1795aSjb150015 smb_rw_param_t *param; 135da6c28aaSamw uint32_t off; 1362c2961f8Sjose borrego uint16_t count; 137faa1795aSjb150015 int rc; 138da6c28aaSamw 139faa1795aSjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 140faa1795aSjb150015 sr->arg.rw = param; 141faa1795aSjb150015 param->rw_magic = SMB_RW_MAGIC; 142da6c28aaSamw 143da6c28aaSamw if (sr->smb_wct == 12) { 144da6c28aaSamw rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, 1452c2961f8Sjose borrego &count, &off, ¶m->rw_last_write); 146da6c28aaSamw } else { 147da6c28aaSamw rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 1482c2961f8Sjose borrego &count, &off, ¶m->rw_last_write); 149da6c28aaSamw } 150da6c28aaSamw 1512c2961f8Sjose borrego param->rw_count = (uint32_t)count; 152faa1795aSjb150015 param->rw_offset = (uint64_t)off; 153faa1795aSjb150015 154faa1795aSjb150015 DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr, 155faa1795aSjb150015 smb_rw_param_t *, param); 156faa1795aSjb150015 157faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 158da6c28aaSamw } 159da6c28aaSamw 160faa1795aSjb150015 void 161faa1795aSjb150015 smb_post_write_and_close(smb_request_t *sr) 162faa1795aSjb150015 { 163faa1795aSjb150015 DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr, 164faa1795aSjb150015 smb_rw_param_t *, sr->arg.rw); 165faa1795aSjb150015 166faa1795aSjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 167faa1795aSjb150015 } 168faa1795aSjb150015 169faa1795aSjb150015 smb_sdrc_t 170faa1795aSjb150015 smb_com_write_and_close(smb_request_t *sr) 171faa1795aSjb150015 { 172faa1795aSjb150015 smb_rw_param_t *param = sr->arg.rw; 1732c2961f8Sjose borrego uint16_t count; 174faa1795aSjb150015 int rc = 0; 175faa1795aSjb150015 1762c2961f8Sjose borrego smbsr_lookup_file(sr); 177da6c28aaSamw if (sr->fid_ofile == NULL) { 178dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 179faa1795aSjb150015 return (SDRC_ERROR); 180da6c28aaSamw } 181da6c28aaSamw 182b89a8333Snatalie li - Sun Microsystems - Irvine United States sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 183b89a8333Snatalie li - Sun Microsystems - Irvine United States 184faa1795aSjb150015 if (param->rw_count == 0) { 185da6c28aaSamw rc = smb_write_truncate(sr, param); 186da6c28aaSamw } else { 187da6c28aaSamw /* 188da6c28aaSamw * There may be a bug here: should this be "3.#B"? 189da6c28aaSamw */ 190faa1795aSjb150015 rc = smbsr_decode_data(sr, ".#B", param->rw_count, 191faa1795aSjb150015 ¶m->rw_vdb); 192da6c28aaSamw 1932c2961f8Sjose borrego if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 194faa1795aSjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 195faa1795aSjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 196faa1795aSjb150015 return (SDRC_ERROR); 197da6c28aaSamw } 198da6c28aaSamw 1992c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 200da6c28aaSamw 201f96bd5c8SAlan Wright rc = smb_common_write(sr, param); 202da6c28aaSamw } 203da6c28aaSamw 204da6c28aaSamw if (rc != 0) { 205faa1795aSjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 206dc20a302Sas200622 smbsr_errno(sr, rc); 207faa1795aSjb150015 return (SDRC_ERROR); 208da6c28aaSamw } 209da6c28aaSamw 210c8ec8eeaSjose borrego smb_ofile_close(sr->fid_ofile, param->rw_last_write); 211da6c28aaSamw 2122c2961f8Sjose borrego count = (uint16_t)param->rw_count; 2132c2961f8Sjose borrego rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0); 214faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 215da6c28aaSamw } 216da6c28aaSamw 217da6c28aaSamw /* 218da6c28aaSamw * Write count bytes to a file at the specified offset and then unlock 219da6c28aaSamw * them. Write behind is safe because the client should have the range 220da6c28aaSamw * locked and this request is allowed to extend the file - note that 221faa1795aSjb150015 * offset is limited to 32-bits. 222faa1795aSjb150015 * 223faa1795aSjb150015 * Spec advice: it is an error for count to be zero. For compatibility, 224faa1795aSjb150015 * we take no action and return success. 225da6c28aaSamw * 226da6c28aaSamw * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 227da6c28aaSamw * files. Reject any attempt to use it on other shares. 228da6c28aaSamw * 229da6c28aaSamw * The response count indicates the actual number of bytes written, which 230da6c28aaSamw * will equal the requested count on success. If request and response 231da6c28aaSamw * counts differ but there is no error, the client will assume that the 232da6c28aaSamw * server encountered a resource issue. 233da6c28aaSamw */ 2347b59d02dSjb150015 smb_sdrc_t 235faa1795aSjb150015 smb_pre_write_and_unlock(smb_request_t *sr) 236da6c28aaSamw { 237faa1795aSjb150015 smb_rw_param_t *param; 238da6c28aaSamw uint32_t off; 2392c2961f8Sjose borrego uint16_t count; 240da6c28aaSamw uint16_t remcnt; 241faa1795aSjb150015 int rc; 242faa1795aSjb150015 243faa1795aSjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 244faa1795aSjb150015 sr->arg.rw = param; 245faa1795aSjb150015 param->rw_magic = SMB_RW_MAGIC; 246faa1795aSjb150015 2472c2961f8Sjose borrego rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt); 248faa1795aSjb150015 2492c2961f8Sjose borrego param->rw_count = (uint32_t)count; 250faa1795aSjb150015 param->rw_offset = (uint64_t)off; 251faa1795aSjb150015 252faa1795aSjb150015 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr, 253faa1795aSjb150015 smb_rw_param_t *, param); 254faa1795aSjb150015 255faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 256faa1795aSjb150015 } 257faa1795aSjb150015 258faa1795aSjb150015 void 259faa1795aSjb150015 smb_post_write_and_unlock(smb_request_t *sr) 260faa1795aSjb150015 { 261faa1795aSjb150015 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr, 262faa1795aSjb150015 smb_rw_param_t *, sr->arg.rw); 263faa1795aSjb150015 264faa1795aSjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 265faa1795aSjb150015 } 266faa1795aSjb150015 267faa1795aSjb150015 smb_sdrc_t 268faa1795aSjb150015 smb_com_write_and_unlock(smb_request_t *sr) 269faa1795aSjb150015 { 270faa1795aSjb150015 smb_rw_param_t *param = sr->arg.rw; 271faa1795aSjb150015 uint32_t status; 272da6c28aaSamw int rc = 0; 273da6c28aaSamw 274da6c28aaSamw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 275dc20a302Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 276faa1795aSjb150015 return (SDRC_ERROR); 277da6c28aaSamw } 278da6c28aaSamw 2792c2961f8Sjose borrego smbsr_lookup_file(sr); 280da6c28aaSamw if (sr->fid_ofile == NULL) { 281dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 282faa1795aSjb150015 return (SDRC_ERROR); 283da6c28aaSamw } 284da6c28aaSamw 285b89a8333Snatalie li - Sun Microsystems - Irvine United States sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 286b89a8333Snatalie li - Sun Microsystems - Irvine United States 287faa1795aSjb150015 if (param->rw_count == 0) { 288faa1795aSjb150015 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0); 289faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 290da6c28aaSamw } 291da6c28aaSamw 2922c2961f8Sjose borrego 293faa1795aSjb150015 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 294da6c28aaSamw 2952c2961f8Sjose borrego if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) { 296faa1795aSjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 297faa1795aSjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 298faa1795aSjb150015 return (SDRC_ERROR); 299da6c28aaSamw } 300da6c28aaSamw 3012c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 302da6c28aaSamw 303f96bd5c8SAlan Wright if ((rc = smb_common_write(sr, param)) != 0) { 304faa1795aSjb150015 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 305dc20a302Sas200622 smbsr_errno(sr, rc); 306faa1795aSjb150015 return (SDRC_ERROR); 307da6c28aaSamw } 308da6c28aaSamw 309faa1795aSjb150015 status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset, 310faa1795aSjb150015 (uint64_t)param->rw_count); 311faa1795aSjb150015 if (status != NT_STATUS_SUCCESS) { 312dc20a302Sas200622 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 313148c5f43SAlan Wright ERRDOS, ERROR_NOT_LOCKED); 314faa1795aSjb150015 return (SDRC_ERROR); 315da6c28aaSamw } 316da6c28aaSamw 3172c2961f8Sjose borrego rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 3182c2961f8Sjose borrego (uint16_t)param->rw_count, 0); 319faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 320da6c28aaSamw } 321da6c28aaSamw 322da6c28aaSamw /* 323da6c28aaSamw * Write bytes to a file (SMB Core). This request was extended in 324da6c28aaSamw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 325da6c28aaSamw * 14, instead of 12, and including additional offset information. 326da6c28aaSamw * 327da6c28aaSamw * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 328da6c28aaSamw * to truncate a file. A zero length merely transfers zero bytes. 329da6c28aaSamw * 330da6c28aaSamw * If bit 0 of WriteMode is set, Fid must refer to a disk file and 331da6c28aaSamw * the data must be on stable storage before responding. 3322c2961f8Sjose borrego * 3332c2961f8Sjose borrego * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5: 3342c2961f8Sjose borrego * If CAP_LARGE_WRITEX is set, the byte count may be larger than the 3352c2961f8Sjose borrego * negotiated buffer size and the server is expected to write the 3362c2961f8Sjose borrego * number of bytes specified. 337da6c28aaSamw */ 3387b59d02dSjb150015 smb_sdrc_t 339faa1795aSjb150015 smb_pre_write_andx(smb_request_t *sr) 340da6c28aaSamw { 341faa1795aSjb150015 smb_rw_param_t *param; 342da6c28aaSamw uint32_t off_low; 343da6c28aaSamw uint32_t off_high; 3442c2961f8Sjose borrego uint16_t datalen_low; 3452c2961f8Sjose borrego uint16_t datalen_high; 346da6c28aaSamw uint16_t remcnt; 347faa1795aSjb150015 int rc; 348da6c28aaSamw 349faa1795aSjb150015 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 350faa1795aSjb150015 sr->arg.rw = param; 351faa1795aSjb150015 param->rw_magic = SMB_RW_MAGIC; 352da6c28aaSamw 353da6c28aaSamw if (sr->smb_wct == 14) { 3542c2961f8Sjose borrego rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid, 3552c2961f8Sjose borrego &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 3562c2961f8Sjose borrego &datalen_low, ¶m->rw_dsoff, &off_high); 357da6c28aaSamw 358*1fb4a876SGordon Ross if (param->rw_dsoff >= 63) 359faa1795aSjb150015 param->rw_dsoff -= 63; 360faa1795aSjb150015 param->rw_offset = ((uint64_t)off_high << 32) | off_low; 361*1fb4a876SGordon Ross } else if (sr->smb_wct == 12) { 3622c2961f8Sjose borrego rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid, 3632c2961f8Sjose borrego &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 3642c2961f8Sjose borrego &datalen_low, ¶m->rw_dsoff); 365da6c28aaSamw 366*1fb4a876SGordon Ross if (param->rw_dsoff >= 59) 367faa1795aSjb150015 param->rw_dsoff -= 59; 368*1fb4a876SGordon Ross param->rw_offset = (uint64_t)off_low; 369*1fb4a876SGordon Ross /* off_high not present */ 370*1fb4a876SGordon Ross } else { 371*1fb4a876SGordon Ross rc = -1; 372da6c28aaSamw } 373da6c28aaSamw 3743a6c5f83SAlan Wright param->rw_count = (uint32_t)datalen_low; 3753a6c5f83SAlan Wright 376*1fb4a876SGordon Ross /* 377*1fb4a876SGordon Ross * Work-around a Win7 bug, where it fails to set the 378*1fb4a876SGordon Ross * CAP_LARGE_WRITEX flag during session setup. Assume 379*1fb4a876SGordon Ross * a large write if the data remaining is >= 64k. 380*1fb4a876SGordon Ross */ 381*1fb4a876SGordon Ross if ((sr->session->capabilities & CAP_LARGE_WRITEX) != 0 || 382*1fb4a876SGordon Ross (sr->smb_data.max_bytes > (sr->smb_data.chain_offset + 0xFFFF))) 3833a6c5f83SAlan Wright param->rw_count |= ((uint32_t)datalen_high << 16); 3842c2961f8Sjose borrego 385faa1795aSjb150015 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, 386faa1795aSjb150015 smb_rw_param_t *, param); 387faa1795aSjb150015 388faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 389da6c28aaSamw } 390da6c28aaSamw 391faa1795aSjb150015 void 392faa1795aSjb150015 smb_post_write_andx(smb_request_t *sr) 393faa1795aSjb150015 { 394faa1795aSjb150015 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr, 395faa1795aSjb150015 smb_rw_param_t *, sr->arg.rw); 396faa1795aSjb150015 397faa1795aSjb150015 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 398faa1795aSjb150015 } 399faa1795aSjb150015 400faa1795aSjb150015 smb_sdrc_t 401faa1795aSjb150015 smb_com_write_andx(smb_request_t *sr) 402faa1795aSjb150015 { 403faa1795aSjb150015 smb_rw_param_t *param = sr->arg.rw; 4042c2961f8Sjose borrego uint16_t count_high; 4052c2961f8Sjose borrego uint16_t count_low; 406faa1795aSjb150015 int rc; 407faa1795aSjb150015 408faa1795aSjb150015 ASSERT(param); 409faa1795aSjb150015 ASSERT(param->rw_magic == SMB_RW_MAGIC); 410faa1795aSjb150015 4112c2961f8Sjose borrego smbsr_lookup_file(sr); 412da6c28aaSamw if (sr->fid_ofile == NULL) { 413dc20a302Sas200622 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 414faa1795aSjb150015 return (SDRC_ERROR); 415da6c28aaSamw } 416da6c28aaSamw 417b89a8333Snatalie li - Sun Microsystems - Irvine United States sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 418b89a8333Snatalie li - Sun Microsystems - Irvine United States 419faa1795aSjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) && 420f96bd5c8SAlan Wright STYPE_ISIPC(sr->tid_tree->t_res_type)) { 421dc20a302Sas200622 smbsr_error(sr, 0, ERRSRV, ERRaccess); 422faa1795aSjb150015 return (SDRC_ERROR); 423da6c28aaSamw } 424da6c28aaSamw 425faa1795aSjb150015 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, 426faa1795aSjb150015 ¶m->rw_vdb); 4272c2961f8Sjose borrego 4282c2961f8Sjose borrego if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 429faa1795aSjb150015 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 430faa1795aSjb150015 ERRDOS, ERROR_INVALID_PARAMETER); 431faa1795aSjb150015 return (SDRC_ERROR); 432da6c28aaSamw } 433da6c28aaSamw 4342c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 435da6c28aaSamw 436faa1795aSjb150015 if (param->rw_count != 0) { 437f96bd5c8SAlan Wright if ((rc = smb_common_write(sr, param)) != 0) { 438faa1795aSjb150015 if (sr->smb_error.status != 439faa1795aSjb150015 NT_STATUS_FILE_LOCK_CONFLICT) 440dc20a302Sas200622 smbsr_errno(sr, rc); 441faa1795aSjb150015 return (SDRC_ERROR); 442da6c28aaSamw } 443da6c28aaSamw } 444da6c28aaSamw 4452c2961f8Sjose borrego count_low = param->rw_count & 0xFFFF; 4462c2961f8Sjose borrego count_high = (param->rw_count >> 16) & 0xFF; 4472c2961f8Sjose borrego 4482c2961f8Sjose borrego rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww", 4492c2961f8Sjose borrego 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0); 450da6c28aaSamw 451faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 452da6c28aaSamw } 453da6c28aaSamw 454da6c28aaSamw /* 455da6c28aaSamw * Common function for writing files or IPC/MSRPC named pipes. 456da6c28aaSamw * 457da6c28aaSamw * Returns errno values. 458da6c28aaSamw */ 459f96bd5c8SAlan Wright int 460f96bd5c8SAlan Wright smb_common_write(smb_request_t *sr, smb_rw_param_t *param) 461da6c28aaSamw { 462037cac00Sjoyce mcintosh smb_ofile_t *ofile = sr->fid_ofile; 463da6c28aaSamw smb_node_t *node; 4643db3f65cSamw int stability = 0; 465da6c28aaSamw uint32_t lcount; 466da6c28aaSamw int rc = 0; 467da6c28aaSamw 468da6c28aaSamw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 469da6c28aaSamw case STYPE_DISKTREE: 470f96bd5c8SAlan Wright case STYPE_PRINTQ: 471da6c28aaSamw node = ofile->f_node; 472da6c28aaSamw 473037cac00Sjoyce mcintosh if (!smb_node_is_dir(node)) { 474faa1795aSjb150015 rc = smb_lock_range_access(sr, node, param->rw_offset, 475faa1795aSjb150015 param->rw_count, B_TRUE); 476faa1795aSjb150015 if (rc != NT_STATUS_SUCCESS) { 477faa1795aSjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 478faa1795aSjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 479faa1795aSjb150015 return (EACCES); 480faa1795aSjb150015 } 481da6c28aaSamw } 482da6c28aaSamw 483faa1795aSjb150015 if (SMB_WRMODE_IS_STABLE(param->rw_mode) || 484da6c28aaSamw (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 4853db3f65cSamw stability = FSYNC; 486da6c28aaSamw } 487da6c28aaSamw 488da6c28aaSamw rc = smb_fsop_write(sr, sr->user_cr, node, 489037cac00Sjoyce mcintosh ¶m->rw_vdb.vdb_uio, &lcount, stability); 490da6c28aaSamw 491da6c28aaSamw if (rc) 492da6c28aaSamw return (rc); 493da6c28aaSamw 4945fd03bc0SGordon Ross /* 4955fd03bc0SGordon Ross * Used to have code here to set mtime. 4965fd03bc0SGordon Ross * We have just done a write, so we know 4975fd03bc0SGordon Ross * the file system will update mtime. 4985fd03bc0SGordon Ross * No need to do it again here. 4995fd03bc0SGordon Ross * 5005fd03bc0SGordon Ross * However, keep track of the fact that 5015fd03bc0SGordon Ross * we have written data via this handle. 5025fd03bc0SGordon Ross */ 5035fd03bc0SGordon Ross ofile->f_written = B_TRUE; 504da6c28aaSamw 505cb174861Sjoyce mcintosh if (!smb_node_is_dir(node)) 506cb174861Sjoyce mcintosh smb_oplock_break_levelII(node); 507cb174861Sjoyce mcintosh 5082c2961f8Sjose borrego param->rw_count = lcount; 509da6c28aaSamw break; 510da6c28aaSamw 511da6c28aaSamw case STYPE_IPC: 5122c2961f8Sjose borrego param->rw_count = param->rw_vdb.vdb_uio.uio_resid; 513da6c28aaSamw 5142c2961f8Sjose borrego if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0) 515faa1795aSjb150015 param->rw_count = 0; 516da6c28aaSamw break; 517da6c28aaSamw 518da6c28aaSamw default: 519da6c28aaSamw rc = EACCES; 520da6c28aaSamw break; 521da6c28aaSamw } 522da6c28aaSamw 523da6c28aaSamw if (rc != 0) 524da6c28aaSamw return (rc); 525da6c28aaSamw 526da6c28aaSamw mutex_enter(&ofile->f_mutex); 527faa1795aSjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 528da6c28aaSamw mutex_exit(&ofile->f_mutex); 529da6c28aaSamw return (rc); 530da6c28aaSamw } 531da6c28aaSamw 532da6c28aaSamw /* 533da6c28aaSamw * Truncate a disk file to the specified offset. 534da6c28aaSamw * Typically, w_count will be zero here. 535da6c28aaSamw * 536037cac00Sjoyce mcintosh * Note that smb_write_andx cannot be used to reduce the file size so, 537037cac00Sjoyce mcintosh * if this is required, smb_write is called with a count of zero and 538037cac00Sjoyce mcintosh * the appropriate file length in offset. The file should be resized 539037cac00Sjoyce mcintosh * to the length specified by the offset. 540037cac00Sjoyce mcintosh * 541da6c28aaSamw * Returns errno values. 542da6c28aaSamw */ 5437b59d02dSjb150015 static int 544faa1795aSjb150015 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) 545da6c28aaSamw { 546037cac00Sjoyce mcintosh smb_ofile_t *ofile = sr->fid_ofile; 547da6c28aaSamw smb_node_t *node = ofile->f_node; 548037cac00Sjoyce mcintosh smb_attr_t attr; 5497b59d02dSjb150015 uint32_t status; 550da6c28aaSamw int rc; 551da6c28aaSamw 552f96bd5c8SAlan Wright if (STYPE_ISIPC(sr->tid_tree->t_res_type)) 553da6c28aaSamw return (0); 554da6c28aaSamw 5552c2961f8Sjose borrego mutex_enter(&node->n_mutex); 556037cac00Sjoyce mcintosh if (!smb_node_is_dir(node)) { 557faa1795aSjb150015 status = smb_lock_range_access(sr, node, param->rw_offset, 558faa1795aSjb150015 param->rw_count, B_TRUE); 5597b59d02dSjb150015 if (status != NT_STATUS_SUCCESS) { 5602c2961f8Sjose borrego mutex_exit(&node->n_mutex); 561faa1795aSjb150015 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 562faa1795aSjb150015 ERRDOS, ERROR_LOCK_VIOLATION); 5637b59d02dSjb150015 return (EACCES); 564dc20a302Sas200622 } 565dc20a302Sas200622 } 5662c2961f8Sjose borrego mutex_exit(&node->n_mutex); 567dc20a302Sas200622 568037cac00Sjoyce mcintosh bzero(&attr, sizeof (smb_attr_t)); 569037cac00Sjoyce mcintosh attr.sa_mask = SMB_AT_SIZE; 570037cac00Sjoyce mcintosh attr.sa_vattr.va_size = param->rw_offset; 571037cac00Sjoyce mcintosh rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr); 572037cac00Sjoyce mcintosh if (rc != 0) 573da6c28aaSamw return (rc); 574da6c28aaSamw 575da6c28aaSamw mutex_enter(&ofile->f_mutex); 576faa1795aSjb150015 ofile->f_seek_pos = param->rw_offset + param->rw_count; 577da6c28aaSamw mutex_exit(&ofile->f_mutex); 578da6c28aaSamw return (0); 579da6c28aaSamw } 580