smb_read.c revision dc20a3024900c47dd2ee44b9707e6df38f7d62a5
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * CDDL HEADER START
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The contents of this file are subject to the terms of the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Common Development and Distribution License (the "License").
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * You may not use this file except in compliance with the License.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * or http://www.opensolaris.org/os/licensing.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * See the License for the specific language governing permissions
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * and limitations under the License.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * When distributing Covered Code, include this CDDL HEADER in each
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If applicable, add the following below this CDDL HEADER, with the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * fields enclosed by brackets "[]" replaced with your own identifying
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * information: Portions Copyright [yyyy] [name of copyright owner]
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * CDDL HEADER END
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Use is subject to license terms.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#pragma ident "%Z%%M% %I% %E% SMI"
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include <sys/syslog.h>
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include <smbsrv/smb_incl.h>
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw#include <smbsrv/smb_fsops.h>
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwtypedef struct smb_read_param {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint64_t r_offset;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint16_t r_count;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint16_t r_mincnt;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw} smb_read_param_t;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwint smb_common_read(struct smb_request *sr, smb_read_param_t *param);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Read bytes from a file or named pipe (SMB Core).
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The requested count specifies the number of bytes desired. Offset
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * is limited to 32 bits, so this client request is inappropriate for
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * files with 64 bit offsets.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * On return, count is the number of bytes actually being returned, which
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * may be less than the count requested only if a read specifies bytes
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * beyond the current file size. In this case only the bytes that exist
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * are returned. A read completely beyond the end of file results in a
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * response of length zero. This is the only circumstance when a zero
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * length response is generated. A count returned which is less than the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * count requested is the end of file indicator.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwint
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwsmb_com_read(struct smb_request *sr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smb_read_param_t param;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint32_t off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint16_t remcnt;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int rc;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &param.r_count, &off_low, &remcnt);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (rc != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smbsr_decode_error(sr);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_offset = (uint64_t)off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_mincnt = 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (sr->fid_ofile == NULL) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((rc = smb_common_read(sr, &param)) != 0) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as smbsr_errno(sr, rc);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 5, param.r_count, VAR_BCC, 0x01, param.r_count, &sr->raw_data);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_NORMAL_REPLY);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Lock and read bytes from a file (SMB Core Plus). The SmbLockAndRead/
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * attempt to use it on non-disk shares.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The requested count specifies the number of bytes desired. Offset
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * specifies the offset in the file of the first byte to be locked then
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * read. Note that offset is limited to 32 bits, so this client request
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * is inappropriate for files with 64 bit offsets.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * immediately an error should be returned to the client. If an error
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * occurs on the lock, the bytes should not be read.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * On return, count is the number of bytes actually being returned, which
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * may be less than the count requested only if a read specifies bytes
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * beyond the current file size. In this case only the bytes that exist
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * are returned. A read completely beyond the end of file results in a
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * response of length zero. This is the only circumstance when a zero
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * length response is generated. A count returned which is less than the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * count requested is the end of file indicator.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwint
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwsmb_com_lock_and_read(struct smb_request *sr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smb_read_param_t param;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint16_t remcnt;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint32_t off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw DWORD result;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int rc;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &param.r_count, &off_low, &remcnt);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (rc != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smbsr_decode_error(sr);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_offset = (uint64_t)off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_mincnt = 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (sr->fid_ofile == NULL) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw result = smb_lock_range(sr, sr->fid_ofile, param.r_offset,
55bf511df53aad0fdb7eb3fa349f0308cc05234cas (uint64_t)param.r_count, UINT_MAX, SMB_LOCK_TYPE_READWRITE);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (result != NT_STATUS_SUCCESS) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as smb_lock_range_error(sr, result);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((rc = smb_common_read(sr, &param)) != 0) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as smbsr_errno(sr, rc);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 5, param.r_count, VAR_BCC, 0x1, param.r_count, &sr->raw_data);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_NORMAL_REPLY);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * SMB Core Plus to maximize performance when reading a large block
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * of data from a server. This request was extended in LM 0.12 to
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * support 64-bit offsets; the server can indicate support by setting
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * CAP_LARGE_FILES in the negotiated capabilities.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The client must guarantee that there is (and will be) no other request
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * to the server for the duration of the SMB_COM_READ_RAW, since the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * server response has no header or trailer. To help ensure that there
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * are no interruptions, we block all I/O for the session during read raw.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * If this is the first SMB request received since we sent an oplock break
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * to this client, we don't know if it's safe to send the raw data because
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * the requests may have crossed on the wire and the client may have
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * interpreted the oplock break as part of the raw data. To avoid problems,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * we send a zero length session packet, which will force the client to
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * retry the read.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Read errors are handled by sending a zero length response.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwint
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwsmb_com_read_raw(struct smb_request *sr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smb_read_param_t param;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smb_node_t *node;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint32_t off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint32_t off_high;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint32_t timeout;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int rc;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (sr->session->s_state) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw case SMB_SESSION_STATE_NEGOTIATED:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (sr->smb_wct == 8) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &off_low, &param.r_count, &param.r_mincnt,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &timeout);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_offset = (uint64_t)off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw } else {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &off_low, &param.r_count, &param.r_mincnt, &timeout,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &off_high);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_offset = ((uint64_t)off_high << 32) | off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (rc != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smbsr_decode_error(sr);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sr->smb_fid);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (sr->fid_ofile == NULL) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ERRDOS, ERRbadfid);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smb_common_read(sr, &param);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * XXX Do we need to handle errors here? What if we have an
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * access error (either permissions or range lock violations?
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw node = sr->fid_ofile->f_node;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = EAGAIN;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (rc != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) smb_session_send(sr->session, 0, NULL);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw m_freem(sr->raw_data.chain);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sr->raw_data.chain = 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw } else {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) smb_session_send(sr->session, 0, &sr->raw_data);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_NO_REPLY);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw case SMB_SESSION_STATE_OPLOCK_BREAKING:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) smb_session_send(sr->session, 0, NULL);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_NO_REPLY);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ASSERT(0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_DROP_VC);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw case SMB_SESSION_STATE_TERMINATED:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ASSERT(0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_NO_REPLY);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw case SMB_SESSION_STATE_DISCONNECTED:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_NO_REPLY);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw case SMB_SESSION_STATE_CONNECTED:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw case SMB_SESSION_STATE_ESTABLISHED:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw default:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ASSERT(0);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_DROP_VC);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Read bytes from a file (SMB Core). This request was extended in
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * 12 and including additional offset information.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwint
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwsmb_com_read_andx(struct smb_request *sr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smb_read_param_t param;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint32_t off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint32_t off_high;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint16_t remcnt;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint16_t offset2;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw uint8_t secondary;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int rc;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (sr->smb_wct == 12) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", &secondary,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &sr->smb_fid, &off_low, &param.r_count, &remcnt, &off_high);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_offset = ((uint64_t)off_high << 32) | off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw } else {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smbsr_decode_vwv(sr, "b3.wlw6.w", &secondary,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &sr->smb_fid, &off_low, &param.r_count, &remcnt);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_offset = (uint64_t)off_low;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (rc != 0) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smbsr_decode_error(sr);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_mincnt = 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (sr->fid_ofile == NULL) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if ((rc = smb_common_read(sr, &param)) != 0) {
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as smbsr_errno(sr, rc);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /* NOTREACHED */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Ensure that the next response offset is zero
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * if there is no secondary command.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw offset2 = (secondary == 0xFF) ? 0 : param.r_count + 59;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The STYPE_IPC response format is different.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The unknown value (2) may be to indicate that it
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * is a follow-up to an earlier RPC transaction.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC",
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 12, /* wct */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw secondary, /* Secondary andx command */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw offset2, /* offset to next */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 0, /* must be 0 */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_count, /* data byte count */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 60, /* Offset from start to data */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw VAR_BCC, /* BCC marker */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 0x02, /* unknown */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &sr->raw_data);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw } else {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC",
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 12, /* wct */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw secondary, /* Secondary andx command */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw offset2, /* offset to next */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw -1, /* must be -1 */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param.r_count, /* data byte count */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw 59, /* Offset from start to data */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw VAR_BCC, /* BCC marker */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &sr->raw_data);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_NORMAL_REPLY);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Common function for reading files or IPC/MSRPC named pipes. All
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * protocol read functions should lookup the fid before calling this
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * function. We can't move the fid lookup here because lock-and-read
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * requires the fid to do locking before attempting the read.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Returns errno values.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwint
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwsmb_common_read(struct smb_request *sr, smb_read_param_t *param)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smb_ofile_t *ofile = sr->fid_ofile;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smb_node_t *node;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw struct vardata_block *vdb;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw struct mbuf *top;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw int rc;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw vdb->tag = 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw vdb->uio.uio_iov = &vdb->iovec[0];
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw vdb->uio.uio_iovcnt = MAX_IOVEC;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw vdb->uio.uio_resid = param->r_count;
55bf511df53aad0fdb7eb3fa349f0308cc05234cas vdb->uio.uio_loffset = (offset_t)param->r_offset;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw vdb->uio.uio_segflg = UIO_SYSSPACE;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw switch (sr->tid_tree->t_res_type & STYPE_MASK) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw case STYPE_DISKTREE:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw node = ofile->f_node;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (node->attr.sa_vattr.va_type != VDIR) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smb_lock_range_access(sr, node, param->r_offset,
dc20a3024900c47dd2ee44b9707e6df38f7d62a5as param->r_count, B_FALSE);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (rc != NT_STATUS_SUCCESS) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = ERANGE;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw break;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw (void) smb_sync_fsattr(sr, sr->user_cr, node);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sr->raw_data.max_bytes = vdb->uio.uio_resid;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw top = smb_mbuf_allocate(&vdb->uio);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio,
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw &node->attr);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw sr->raw_data.max_bytes -= vdb->uio.uio_resid;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw smb_mbuf_trim(top, sr->raw_data.max_bytes);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw MBC_ATTACH_MBUF(&sr->raw_data, top);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw break;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw case STYPE_IPC:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = smb_rpc_read(sr, &vdb->uio);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw break;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw default:
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw rc = EACCES;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw break;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param->r_count -= vdb->uio.uio_resid;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw kmem_free(vdb, sizeof (struct vardata_block));
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (rc != 0)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (rc);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw if (param->r_mincnt != 0 && param->r_count < param->r_mincnt) {
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw /*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * mincnt is only used by read-raw and is typically
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * zero. If mincnt is greater than zero and the
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * number of bytes read is less than mincnt, tell
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * the client that we read nothing.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param->r_count = 0;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw }
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw param->r_offset += param->r_count;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw mutex_enter(&sr->fid_ofile->f_mutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw ofile->f_seek_pos = param->r_offset;
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw mutex_exit(&sr->fid_ofile->f_mutex);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (rc);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The Read Block Multiplexed protocol is used to maximize performance
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * when reading a large block of data from server to client while still
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * allowing other operations to take place between the client and server
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * in parallel.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw *
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * The mpx sub protocol is not supported because we support only
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * connection oriented transports and NT supports SMB_COM_READ_MPX
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * only over connectionless transports.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw */
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*ARGSUSED*/
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwint
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwsmb_com_read_mpx(struct smb_request *sr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_UNIMPLEMENTED);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw/*ARGSUSED*/
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwint
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amwsmb_com_read_mpx_secondary(struct smb_request *sr)
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw{
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw return (SDRC_UNIMPLEMENTED);
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw}