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 */ 21da6c28aaSamw /* 22dc20a302Sas * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27da6c28aaSamw 28da6c28aaSamw #include <sys/syslog.h> 29da6c28aaSamw #include <smbsrv/smb_incl.h> 30da6c28aaSamw #include <smbsrv/smb_fsops.h> 31da6c28aaSamw 32da6c28aaSamw 33*faa1795aSjb int smb_common_read(smb_request_t *, smb_rw_param_t *); 34da6c28aaSamw 35da6c28aaSamw 36da6c28aaSamw /* 37da6c28aaSamw * Read bytes from a file or named pipe (SMB Core). 38da6c28aaSamw * 39da6c28aaSamw * The requested count specifies the number of bytes desired. Offset 40da6c28aaSamw * is limited to 32 bits, so this client request is inappropriate for 41da6c28aaSamw * files with 64 bit offsets. 42da6c28aaSamw * 43da6c28aaSamw * On return, count is the number of bytes actually being returned, which 44da6c28aaSamw * may be less than the count requested only if a read specifies bytes 45da6c28aaSamw * beyond the current file size. In this case only the bytes that exist 46da6c28aaSamw * are returned. A read completely beyond the end of file results in a 47da6c28aaSamw * response of length zero. This is the only circumstance when a zero 48da6c28aaSamw * length response is generated. A count returned which is less than the 49da6c28aaSamw * count requested is the end of file indicator. 50da6c28aaSamw */ 517b59d02dSjb smb_sdrc_t 52*faa1795aSjb smb_pre_read(smb_request_t *sr) 53da6c28aaSamw { 54*faa1795aSjb smb_rw_param_t *param; 55da6c28aaSamw uint32_t off_low; 56da6c28aaSamw uint16_t remcnt; 57da6c28aaSamw int rc; 58da6c28aaSamw 59*faa1795aSjb param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 60*faa1795aSjb sr->arg.rw = param; 61*faa1795aSjb 62da6c28aaSamw rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, 63*faa1795aSjb ¶m->rw_count, &off_low, &remcnt); 64*faa1795aSjb 65*faa1795aSjb param->rw_offset = (uint64_t)off_low; 66*faa1795aSjb param->rw_mincnt = 0; 67*faa1795aSjb 68*faa1795aSjb DTRACE_SMB_2(op__Read__start, smb_request_t *, sr, 69*faa1795aSjb smb_rw_param_t *, param); 70*faa1795aSjb 71*faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 72*faa1795aSjb } 73*faa1795aSjb 74*faa1795aSjb void 75*faa1795aSjb smb_post_read(smb_request_t *sr) 76*faa1795aSjb { 77*faa1795aSjb DTRACE_SMB_2(op__Read__done, smb_request_t *, sr, 78*faa1795aSjb smb_rw_param_t *, sr->arg.rw); 79da6c28aaSamw 80*faa1795aSjb kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 81*faa1795aSjb } 82*faa1795aSjb 83*faa1795aSjb smb_sdrc_t 84*faa1795aSjb smb_com_read(smb_request_t *sr) 85*faa1795aSjb { 86*faa1795aSjb smb_rw_param_t *param = sr->arg.rw; 87*faa1795aSjb int rc; 88da6c28aaSamw 89da6c28aaSamw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 90da6c28aaSamw if (sr->fid_ofile == NULL) { 91dc20a302Sas smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 92*faa1795aSjb return (SDRC_ERROR); 93da6c28aaSamw } 94da6c28aaSamw 95*faa1795aSjb if ((rc = smb_common_read(sr, param)) != 0) { 96dc20a302Sas smbsr_errno(sr, rc); 97*faa1795aSjb return (SDRC_ERROR); 98da6c28aaSamw } 99da6c28aaSamw 1007b59d02dSjb rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 101*faa1795aSjb 5, param->rw_count, VAR_BCC, 0x01, param->rw_count, &sr->raw_data); 102da6c28aaSamw 103*faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 104da6c28aaSamw } 105da6c28aaSamw 106da6c28aaSamw /* 107da6c28aaSamw * Lock and read bytes from a file (SMB Core Plus). The SmbLockAndRead/ 108da6c28aaSamw * SmbLockAndWrite sub-dialect is only valid on disk files: reject any 109da6c28aaSamw * attempt to use it on non-disk shares. 110da6c28aaSamw * 111da6c28aaSamw * The requested count specifies the number of bytes desired. Offset 112da6c28aaSamw * specifies the offset in the file of the first byte to be locked then 113da6c28aaSamw * read. Note that offset is limited to 32 bits, so this client request 114da6c28aaSamw * is inappropriate for files with 64 bit offsets. 115da6c28aaSamw * 116da6c28aaSamw * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted 117da6c28aaSamw * immediately an error should be returned to the client. If an error 118da6c28aaSamw * occurs on the lock, the bytes should not be read. 119da6c28aaSamw * 120da6c28aaSamw * On return, count is the number of bytes actually being returned, which 121da6c28aaSamw * may be less than the count requested only if a read specifies bytes 122da6c28aaSamw * beyond the current file size. In this case only the bytes that exist 123da6c28aaSamw * are returned. A read completely beyond the end of file results in a 124da6c28aaSamw * response of length zero. This is the only circumstance when a zero 125da6c28aaSamw * length response is generated. A count returned which is less than the 126da6c28aaSamw * count requested is the end of file indicator. 127da6c28aaSamw */ 1287b59d02dSjb smb_sdrc_t 129*faa1795aSjb smb_pre_lock_and_read(smb_request_t *sr) 130da6c28aaSamw { 131*faa1795aSjb smb_rw_param_t *param; 132da6c28aaSamw uint16_t remcnt; 133da6c28aaSamw uint32_t off_low; 134da6c28aaSamw int rc; 135da6c28aaSamw 136*faa1795aSjb param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 137*faa1795aSjb sr->arg.rw = param; 138da6c28aaSamw 139da6c28aaSamw rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, 140*faa1795aSjb ¶m->rw_count, &off_low, &remcnt); 141*faa1795aSjb 142*faa1795aSjb param->rw_offset = (uint64_t)off_low; 143*faa1795aSjb param->rw_mincnt = 0; 144*faa1795aSjb 145*faa1795aSjb DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr, 146*faa1795aSjb smb_rw_param_t *, param); 147*faa1795aSjb 148*faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 149*faa1795aSjb } 150*faa1795aSjb 151*faa1795aSjb void 152*faa1795aSjb smb_post_lock_and_read(smb_request_t *sr) 153*faa1795aSjb { 154*faa1795aSjb DTRACE_SMB_2(op__LockAndRead__done, smb_request_t *, sr, 155*faa1795aSjb smb_rw_param_t *, sr->arg.rw); 156*faa1795aSjb 157*faa1795aSjb kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 158*faa1795aSjb } 159da6c28aaSamw 160*faa1795aSjb smb_sdrc_t 161*faa1795aSjb smb_com_lock_and_read(smb_request_t *sr) 162*faa1795aSjb { 163*faa1795aSjb smb_rw_param_t *param = sr->arg.rw; 164*faa1795aSjb DWORD status; 165*faa1795aSjb int rc; 166*faa1795aSjb 167*faa1795aSjb if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 168*faa1795aSjb smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 169*faa1795aSjb return (SDRC_ERROR); 170*faa1795aSjb } 171da6c28aaSamw 172da6c28aaSamw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 173da6c28aaSamw if (sr->fid_ofile == NULL) { 174dc20a302Sas smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 175*faa1795aSjb return (SDRC_ERROR); 176da6c28aaSamw } 177da6c28aaSamw 178*faa1795aSjb status = smb_lock_range(sr, sr->fid_ofile, param->rw_offset, 179*faa1795aSjb (uint64_t)param->rw_count, UINT_MAX, SMB_LOCK_TYPE_READWRITE); 180*faa1795aSjb if (status != NT_STATUS_SUCCESS) { 181*faa1795aSjb smb_lock_range_error(sr, status); 182*faa1795aSjb return (SDRC_ERROR); 183da6c28aaSamw } 184da6c28aaSamw 185*faa1795aSjb if ((rc = smb_common_read(sr, param)) != 0) { 186dc20a302Sas smbsr_errno(sr, rc); 187*faa1795aSjb return (SDRC_ERROR); 188da6c28aaSamw } 189da6c28aaSamw 1907b59d02dSjb rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 191*faa1795aSjb 5, param->rw_count, VAR_BCC, 0x1, param->rw_count, &sr->raw_data); 192da6c28aaSamw 193*faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 194da6c28aaSamw } 195da6c28aaSamw 196da6c28aaSamw /* 197da6c28aaSamw * The SMB_COM_READ_RAW protocol is a negotiated option introduced in 198da6c28aaSamw * SMB Core Plus to maximize performance when reading a large block 199da6c28aaSamw * of data from a server. This request was extended in LM 0.12 to 200da6c28aaSamw * support 64-bit offsets; the server can indicate support by setting 201da6c28aaSamw * CAP_LARGE_FILES in the negotiated capabilities. 202da6c28aaSamw * 203da6c28aaSamw * The client must guarantee that there is (and will be) no other request 204da6c28aaSamw * to the server for the duration of the SMB_COM_READ_RAW, since the 205da6c28aaSamw * server response has no header or trailer. To help ensure that there 206da6c28aaSamw * are no interruptions, we block all I/O for the session during read raw. 207da6c28aaSamw * 208da6c28aaSamw * If this is the first SMB request received since we sent an oplock break 209da6c28aaSamw * to this client, we don't know if it's safe to send the raw data because 210da6c28aaSamw * the requests may have crossed on the wire and the client may have 211da6c28aaSamw * interpreted the oplock break as part of the raw data. To avoid problems, 212da6c28aaSamw * we send a zero length session packet, which will force the client to 213da6c28aaSamw * retry the read. 214da6c28aaSamw * 215da6c28aaSamw * Read errors are handled by sending a zero length response. 216da6c28aaSamw */ 2177b59d02dSjb smb_sdrc_t 218*faa1795aSjb smb_pre_read_raw(smb_request_t *sr) 219da6c28aaSamw { 220*faa1795aSjb smb_rw_param_t *param; 221*faa1795aSjb uint32_t off_low; 222*faa1795aSjb uint32_t off_high; 223*faa1795aSjb uint32_t timeout; 224*faa1795aSjb int rc; 225da6c28aaSamw 226*faa1795aSjb param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 227*faa1795aSjb sr->arg.rw = param; 228da6c28aaSamw 229*faa1795aSjb if (sr->smb_wct == 8) { 230*faa1795aSjb rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid, 231*faa1795aSjb &off_low, ¶m->rw_count, ¶m->rw_mincnt, 232*faa1795aSjb &timeout); 233*faa1795aSjb param->rw_offset = (uint64_t)off_low; 234*faa1795aSjb } else { 235*faa1795aSjb rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid, 236*faa1795aSjb &off_low, ¶m->rw_count, ¶m->rw_mincnt, 237*faa1795aSjb &timeout, &off_high); 238*faa1795aSjb param->rw_offset = ((uint64_t)off_high << 32) | off_low; 239*faa1795aSjb } 240da6c28aaSamw 241*faa1795aSjb DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr, 242*faa1795aSjb smb_rw_param_t *, param); 243da6c28aaSamw 244*faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 245*faa1795aSjb } 246da6c28aaSamw 247*faa1795aSjb void 248*faa1795aSjb smb_post_read_raw(smb_request_t *sr) 249*faa1795aSjb { 250*faa1795aSjb DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr, 251*faa1795aSjb smb_rw_param_t *, sr->arg.rw); 252*faa1795aSjb 253*faa1795aSjb kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 254*faa1795aSjb } 255*faa1795aSjb 256*faa1795aSjb smb_sdrc_t 257*faa1795aSjb smb_com_read_raw(smb_request_t *sr) 258*faa1795aSjb { 259*faa1795aSjb smb_rw_param_t *param = sr->arg.rw; 260*faa1795aSjb smb_node_t *node; 261*faa1795aSjb int rc; 262*faa1795aSjb 263*faa1795aSjb switch (sr->session->s_state) { 264*faa1795aSjb case SMB_SESSION_STATE_NEGOTIATED: 265*faa1795aSjb break; 266da6c28aaSamw 267da6c28aaSamw case SMB_SESSION_STATE_OPLOCK_BREAKING: 268da6c28aaSamw (void) smb_session_send(sr->session, 0, NULL); 269da6c28aaSamw sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED; 270da6c28aaSamw return (SDRC_NO_REPLY); 271da6c28aaSamw 272da6c28aaSamw case SMB_SESSION_STATE_TERMINATED: 273da6c28aaSamw case SMB_SESSION_STATE_DISCONNECTED: 274da6c28aaSamw return (SDRC_NO_REPLY); 275da6c28aaSamw 276*faa1795aSjb case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: 277da6c28aaSamw case SMB_SESSION_STATE_CONNECTED: 278da6c28aaSamw case SMB_SESSION_STATE_ESTABLISHED: 279da6c28aaSamw default: 280da6c28aaSamw return (SDRC_DROP_VC); 281da6c28aaSamw } 282*faa1795aSjb 283*faa1795aSjb sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 284*faa1795aSjb if (sr->fid_ofile == NULL) { 285*faa1795aSjb smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 286*faa1795aSjb return (SDRC_ERROR); 287*faa1795aSjb } 288*faa1795aSjb 289*faa1795aSjb rc = smb_common_read(sr, param); 290*faa1795aSjb 291*faa1795aSjb if (STYPE_ISDSK(sr->tid_tree->t_res_type)) { 292*faa1795aSjb node = sr->fid_ofile->f_node; 293*faa1795aSjb if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) { 294*faa1795aSjb rc = EAGAIN; 295*faa1795aSjb } 296*faa1795aSjb } 297*faa1795aSjb 298*faa1795aSjb if (rc != 0) { 299*faa1795aSjb (void) smb_session_send(sr->session, 0, NULL); 300*faa1795aSjb m_freem(sr->raw_data.chain); 301*faa1795aSjb sr->raw_data.chain = 0; 302*faa1795aSjb } else { 303*faa1795aSjb (void) smb_session_send(sr->session, 0, &sr->raw_data); 304*faa1795aSjb } 305*faa1795aSjb 306*faa1795aSjb return (SDRC_NO_REPLY); 307da6c28aaSamw } 308da6c28aaSamw 309da6c28aaSamw /* 310da6c28aaSamw * Read bytes from a file (SMB Core). This request was extended in 311da6c28aaSamw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 312da6c28aaSamw * 12 and including additional offset information. 313da6c28aaSamw */ 3147b59d02dSjb smb_sdrc_t 315*faa1795aSjb smb_pre_read_andx(smb_request_t *sr) 316da6c28aaSamw { 317*faa1795aSjb smb_rw_param_t *param; 318da6c28aaSamw uint32_t off_low; 319da6c28aaSamw uint32_t off_high; 320da6c28aaSamw uint16_t remcnt; 321da6c28aaSamw int rc; 322da6c28aaSamw 323*faa1795aSjb param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 324*faa1795aSjb sr->arg.rw = param; 325*faa1795aSjb 326da6c28aaSamw if (sr->smb_wct == 12) { 327*faa1795aSjb rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", ¶m->rw_andx, 328*faa1795aSjb &sr->smb_fid, &off_low, ¶m->rw_count, &remcnt, 329*faa1795aSjb &off_high); 330da6c28aaSamw 331*faa1795aSjb param->rw_offset = ((uint64_t)off_high << 32) | off_low; 332da6c28aaSamw } else { 333*faa1795aSjb rc = smbsr_decode_vwv(sr, "b3.wlw6.w", ¶m->rw_andx, 334*faa1795aSjb &sr->smb_fid, &off_low, ¶m->rw_count, &remcnt); 335da6c28aaSamw 336*faa1795aSjb param->rw_offset = (uint64_t)off_low; 337da6c28aaSamw } 338da6c28aaSamw 339*faa1795aSjb param->rw_mincnt = 0; 340*faa1795aSjb 341*faa1795aSjb DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr, 342*faa1795aSjb smb_rw_param_t *, param); 343*faa1795aSjb 344*faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 345*faa1795aSjb } 346da6c28aaSamw 347*faa1795aSjb void 348*faa1795aSjb smb_post_read_andx(smb_request_t *sr) 349*faa1795aSjb { 350*faa1795aSjb DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr, 351*faa1795aSjb smb_rw_param_t *, sr->arg.rw); 352*faa1795aSjb 353*faa1795aSjb kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 354*faa1795aSjb } 355*faa1795aSjb 356*faa1795aSjb smb_sdrc_t 357*faa1795aSjb smb_com_read_andx(smb_request_t *sr) 358*faa1795aSjb { 359*faa1795aSjb smb_rw_param_t *param = sr->arg.rw; 360*faa1795aSjb uint16_t offset2; 361*faa1795aSjb int rc; 362da6c28aaSamw 363da6c28aaSamw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 364da6c28aaSamw if (sr->fid_ofile == NULL) { 365dc20a302Sas smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 366*faa1795aSjb return (SDRC_ERROR); 367da6c28aaSamw } 368da6c28aaSamw 369*faa1795aSjb if ((rc = smb_common_read(sr, param)) != 0) { 370dc20a302Sas smbsr_errno(sr, rc); 371*faa1795aSjb return (SDRC_ERROR); 372da6c28aaSamw } 373da6c28aaSamw 374da6c28aaSamw /* 375da6c28aaSamw * Ensure that the next response offset is zero 376da6c28aaSamw * if there is no secondary command. 377da6c28aaSamw */ 378*faa1795aSjb offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59; 379da6c28aaSamw 380da6c28aaSamw /* 381da6c28aaSamw * The STYPE_IPC response format is different. 382da6c28aaSamw * The unknown value (2) may be to indicate that it 383da6c28aaSamw * is a follow-up to an earlier RPC transaction. 384da6c28aaSamw */ 385da6c28aaSamw if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 3867b59d02dSjb rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC", 387da6c28aaSamw 12, /* wct */ 388*faa1795aSjb param->rw_andx, /* Secondary andx command */ 389da6c28aaSamw offset2, /* offset to next */ 390da6c28aaSamw 0, /* must be 0 */ 391*faa1795aSjb param->rw_count, /* data byte count */ 392da6c28aaSamw 60, /* Offset from start to data */ 393da6c28aaSamw VAR_BCC, /* BCC marker */ 394da6c28aaSamw 0x02, /* unknown */ 395da6c28aaSamw &sr->raw_data); 396da6c28aaSamw } else { 3977b59d02dSjb rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC", 398da6c28aaSamw 12, /* wct */ 399*faa1795aSjb param->rw_andx, /* Secondary andx command */ 400da6c28aaSamw offset2, /* offset to next */ 401da6c28aaSamw -1, /* must be -1 */ 402*faa1795aSjb param->rw_count, /* data byte count */ 403da6c28aaSamw 59, /* Offset from start to data */ 404da6c28aaSamw VAR_BCC, /* BCC marker */ 405da6c28aaSamw &sr->raw_data); 406da6c28aaSamw } 407da6c28aaSamw 408*faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 409da6c28aaSamw } 410da6c28aaSamw 411da6c28aaSamw /* 412da6c28aaSamw * Common function for reading files or IPC/MSRPC named pipes. All 413da6c28aaSamw * protocol read functions should lookup the fid before calling this 414da6c28aaSamw * function. We can't move the fid lookup here because lock-and-read 415da6c28aaSamw * requires the fid to do locking before attempting the read. 416da6c28aaSamw * 417da6c28aaSamw * Returns errno values. 418da6c28aaSamw */ 419da6c28aaSamw int 420*faa1795aSjb smb_common_read(smb_request_t *sr, smb_rw_param_t *param) 421da6c28aaSamw { 422da6c28aaSamw smb_ofile_t *ofile = sr->fid_ofile; 423da6c28aaSamw smb_node_t *node; 424*faa1795aSjb smb_vdb_t *vdb = ¶m->rw_vdb; 425da6c28aaSamw struct mbuf *top; 426da6c28aaSamw int rc; 427da6c28aaSamw 428da6c28aaSamw vdb->tag = 0; 429da6c28aaSamw vdb->uio.uio_iov = &vdb->iovec[0]; 430da6c28aaSamw vdb->uio.uio_iovcnt = MAX_IOVEC; 431*faa1795aSjb vdb->uio.uio_resid = param->rw_count; 432*faa1795aSjb vdb->uio.uio_loffset = (offset_t)param->rw_offset; 433da6c28aaSamw vdb->uio.uio_segflg = UIO_SYSSPACE; 434da6c28aaSamw 435da6c28aaSamw switch (sr->tid_tree->t_res_type & STYPE_MASK) { 436da6c28aaSamw case STYPE_DISKTREE: 437da6c28aaSamw node = ofile->f_node; 438da6c28aaSamw 439da6c28aaSamw if (node->attr.sa_vattr.va_type != VDIR) { 440*faa1795aSjb rc = smb_lock_range_access(sr, node, param->rw_offset, 441*faa1795aSjb param->rw_count, B_FALSE); 442da6c28aaSamw if (rc != NT_STATUS_SUCCESS) { 443da6c28aaSamw rc = ERANGE; 444da6c28aaSamw break; 445da6c28aaSamw } 446da6c28aaSamw } 447da6c28aaSamw 448da6c28aaSamw (void) smb_sync_fsattr(sr, sr->user_cr, node); 449da6c28aaSamw 450da6c28aaSamw sr->raw_data.max_bytes = vdb->uio.uio_resid; 451da6c28aaSamw top = smb_mbuf_allocate(&vdb->uio); 452da6c28aaSamw 453da6c28aaSamw rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio, 454da6c28aaSamw &node->attr); 455da6c28aaSamw 456da6c28aaSamw sr->raw_data.max_bytes -= vdb->uio.uio_resid; 457da6c28aaSamw smb_mbuf_trim(top, sr->raw_data.max_bytes); 458da6c28aaSamw MBC_ATTACH_MBUF(&sr->raw_data, top); 459da6c28aaSamw break; 460da6c28aaSamw 461da6c28aaSamw case STYPE_IPC: 462da6c28aaSamw rc = smb_rpc_read(sr, &vdb->uio); 463da6c28aaSamw break; 464da6c28aaSamw 465da6c28aaSamw default: 466da6c28aaSamw rc = EACCES; 467da6c28aaSamw break; 468da6c28aaSamw } 469da6c28aaSamw 470*faa1795aSjb param->rw_count -= vdb->uio.uio_resid; 471da6c28aaSamw 472da6c28aaSamw if (rc != 0) 473da6c28aaSamw return (rc); 474da6c28aaSamw 475*faa1795aSjb if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) { 476da6c28aaSamw /* 477da6c28aaSamw * mincnt is only used by read-raw and is typically 478da6c28aaSamw * zero. If mincnt is greater than zero and the 479da6c28aaSamw * number of bytes read is less than mincnt, tell 480da6c28aaSamw * the client that we read nothing. 481da6c28aaSamw */ 482*faa1795aSjb param->rw_count = 0; 483da6c28aaSamw } 484da6c28aaSamw 485*faa1795aSjb param->rw_offset += param->rw_count; 486da6c28aaSamw mutex_enter(&sr->fid_ofile->f_mutex); 487*faa1795aSjb ofile->f_seek_pos = param->rw_offset; 488da6c28aaSamw mutex_exit(&sr->fid_ofile->f_mutex); 489da6c28aaSamw return (rc); 490da6c28aaSamw } 491