1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 /* 17 * Dispatch function for SMB2_WRITE 18 */ 19 20 #include <smbsrv/smb2_kproto.h> 21 #include <smbsrv/smb_fsops.h> 22 23 smb_sdrc_t 24 smb2_write(smb_request_t *sr) 25 { 26 smb_ofile_t *of = NULL; 27 smb_vdb_t *vdb = NULL; 28 uint16_t StructSize; 29 uint16_t DataOff; 30 uint32_t Length; 31 uint64_t Offset; 32 smb2fid_t smb2fid; 33 uint32_t Channel; 34 uint32_t Remaining; 35 uint16_t ChanInfoOffset; 36 uint16_t ChanInfoLength; 37 uint32_t Flags; 38 uint32_t XferCount; 39 uint32_t status; 40 int data_chain_off, skip; 41 int stability = 0; 42 int rc = 0; 43 44 /* 45 * SMB2 Write request 46 */ 47 rc = smb_mbc_decodef( 48 &sr->smb_data, 49 "wwlqqqllwwl", 50 &StructSize, /* w */ 51 &DataOff, /* w */ 52 &Length, /* l */ 53 &Offset, /* q */ 54 &smb2fid.persistent, /* q */ 55 &smb2fid.temporal, /* q */ 56 &Channel, /* l */ 57 &Remaining, /* l */ 58 &ChanInfoOffset, /* w */ 59 &ChanInfoLength, /* w */ 60 &Flags); /* l */ 61 if (rc) 62 return (SDRC_ERROR); 63 if (StructSize != 49) 64 return (SDRC_ERROR); 65 66 status = smb2sr_lookup_fid(sr, &smb2fid); 67 if (status) { 68 smb2sr_put_error(sr, status); 69 return (SDRC_SUCCESS); 70 } 71 of = sr->fid_ofile; 72 73 if (Length > smb2_max_rwsize) { 74 smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER); 75 return (SDRC_SUCCESS); 76 } 77 78 /* 79 * Skip any padding before the write data. 80 */ 81 data_chain_off = sr->smb2_cmd_hdr + DataOff; 82 skip = data_chain_off - sr->smb_data.chain_offset; 83 if (skip < 0) { 84 smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER); 85 return (SDRC_SUCCESS); 86 } 87 if (skip > 0) { 88 (void) smb_mbc_decodef(&sr->smb_data, "#.", skip); 89 } 90 91 /* This is automatically free'd. */ 92 vdb = smb_srm_zalloc(sr, sizeof (*vdb)); 93 rc = smb_mbc_decodef(&sr->smb_data, "#B", Length, vdb); 94 if (rc != 0 || vdb->vdb_len != Length) { 95 smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER); 96 return (SDRC_SUCCESS); 97 } 98 vdb->vdb_uio.uio_loffset = (offset_t)Offset; 99 100 XferCount = 0; 101 if (Length == 0) 102 goto doreply; 103 104 switch (of->f_tree->t_res_type & STYPE_MASK) { 105 case STYPE_DISKTREE: 106 case STYPE_PRINTQ: 107 if (!smb_node_is_dir(of->f_node)) { 108 /* Check for conflicting locks. */ 109 rc = smb_lock_range_access(sr, of->f_node, 110 Offset, Length, B_TRUE); 111 if (rc) { 112 rc = ERANGE; 113 break; 114 } 115 } 116 if ((Flags & SMB2_WRITEFLAG_WRITE_THROUGH) || 117 (of->f_node->flags & NODE_FLAGS_WRITE_THROUGH)) { 118 stability = FSYNC; 119 } 120 rc = smb_fsop_write(sr, of->f_cr, of->f_node, 121 &vdb->vdb_uio, &XferCount, stability); 122 if (rc) 123 break; 124 of->f_written = B_TRUE; 125 if (!smb_node_is_dir(of->f_node)) 126 smb_oplock_break_levelII(of->f_node); 127 break; 128 129 case STYPE_IPC: 130 rc = smb_opipe_write(sr, &vdb->vdb_uio); 131 if (rc == 0) 132 XferCount = Length; 133 break; 134 135 default: 136 rc = EACCES; 137 break; 138 } 139 140 if (rc) { 141 smb2sr_put_errno(sr, rc); 142 return (SDRC_SUCCESS); 143 } 144 145 /* 146 * SMB2 Write reply 147 */ 148 doreply: 149 DataOff = SMB2_HDR_SIZE + 16; 150 rc = smb_mbc_encodef( 151 &sr->reply, "wwlll", 152 17, /* StructSize */ /* w */ 153 0, /* reserved */ /* w */ 154 XferCount, /* l */ 155 0, /* DataRemaining */ /* l */ 156 0); /* Channel Info */ /* l */ 157 if (rc) 158 return (SDRC_ERROR); 159 160 mutex_enter(&of->f_mutex); 161 of->f_seek_pos = Offset + XferCount; 162 mutex_exit(&of->f_mutex); 163 164 return (SDRC_SUCCESS); 165 } 166