summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/fs/smbsrv
diff options
context:
space:
mode:
authorjose borrego <Jose.Borrego@Sun.COM>2009-02-27 17:10:20 -0700
committerjose borrego <Jose.Borrego@Sun.COM>2009-02-27 17:10:20 -0700
commit2c2961f8403049d948b9f3e6c35d6488b6b7e1aa (patch)
tree9a3b5e85cf05528de14661b9c54a18a80ac78325 /usr/src/uts/common/fs/smbsrv
parent8475e04352e630e4bd0f59a283286ee2475a14ce (diff)
downloadillumos-gate-2c2961f8403049d948b9f3e6c35d6488b6b7e1aa.tar.gz
6709704 smbtorture RAW-BENCH-OPLOCK test fails (when oplocks enabled)
6800443 ReadX and WriteX should support CAP_LARGE_READX and CAP_LARGE_WRITEX --HG-- rename : usr/src/uts/common/fs/smbsrv/smb_create_directory.c => usr/src/uts/common/fs/smbsrv/smb_directory.c
Diffstat (limited to 'usr/src/uts/common/fs/smbsrv')
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_check_directory.c138
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_close.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c141
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_transact.c15
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_create.c25
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_create_directory.c284
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_delete.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_delete_directory.c132
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_directory.c565
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dispatch.c45
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fem.c180
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find.c13
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_flush.c5
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsops.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_init.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_lock.c12
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c7
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_locking_andx.c10
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mangle_name.c202
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c42
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c56
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_negotiate.c18
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_node.c541
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c44
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c43
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_odir.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_ofile.c44
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_open_andx.c154
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_oplock.c534
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c12
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information2.c7
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_read.c228
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_rename.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_seek.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_server.c7
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_session.c156
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information.c5
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information2.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c20
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c29
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree.c1
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_util.c73
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write.c110
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write_raw.c4
49 files changed, 2257 insertions, 1711 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb_check_directory.c b/usr/src/uts/common/fs/smbsrv/smb_check_directory.c
deleted file mode 100644
index d9164ee988..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_check_directory.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-/*
- * SMB: check_directory
- *
- * This SMB is used to verify that a path exists and is a directory. No
- * error is returned if the given path exists and the client has read
- * access to it. Client machines which maintain a concept of a "working
- * directory" will find this useful to verify the validity of a "change
- * working directory" command. Note that the servers do NOT have a concept
- * of working directory for a particular client. The client must always
- * supply full pathnames relative to the Tid in the SMB header.
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes; min = 2
- * UCHAR BufferFormat; 0x04
- * STRING DirectoryPath[]; Directory path
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes = 0
- *
- * DOS clients, in particular, depend on the SMB_ERR_BAD_PATH return code
- * if the directory is not found.
- *
- * 4.3.3.1 Errors
- *
- * ERRDOS/ERRbadfile
- * ERRDOS/ERRbadpath
- * ERRDOS/ERRnoaccess
- * ERRHRD/ERRdata
- * ERRSRV/ERRinvid
- * ERRSRV/ERRbaduid
- * ERRSRV/ERRaccess
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-smb_sdrc_t
-smb_pre_check_directory(smb_request_t *sr)
-{
- int rc;
-
- rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path);
-
- DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr,
- struct dirop *, &sr->arg.dirop);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
-
-void
-smb_post_check_directory(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_check_directory(smb_request_t *sr)
-{
- int rc;
- struct smb_node *dnode;
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
- ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- sr->arg.dirop.fqi.srch_attr = 0;
-
- rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
- if (rc) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- /*
- * Release hold on dir_snode taken in smbd_fs_query()
- */
-
- smb_node_release(sr->arg.dirop.fqi.dir_snode);
-
- dnode = sr->arg.dirop.fqi.last_snode;
-
- if (sr->arg.dirop.fqi.last_attr.sa_vattr.va_type != VDIR) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
-
- smbsr_errno(sr, ENOTDIR);
- return (SDRC_ERROR);
- }
-
- rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_TRAVERSE);
-
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
-
- if (rc != 0) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- rc = smbsr_encode_empty_result(sr);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_close.c b/usr/src/uts/common/fs/smbsrv/smb_close.c
index 2394905d31..9babe9a3b1 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_close.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_close.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "@(#)smb_close.c 1.6 08/08/08 SMI"
-
#include <smbsrv/smb_incl.h>
@@ -59,7 +57,7 @@ smb_post_close(smb_request_t *sr)
smb_sdrc_t
smb_com_close(smb_request_t *sr)
{
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -97,7 +95,7 @@ smb_post_close_and_tree_disconnect(smb_request_t *sr)
smb_sdrc_t
smb_com_close_and_tree_disconnect(smb_request_t *sr)
{
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
index 0deddbcaa5..2d8c165f39 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -117,10 +117,10 @@ smb_omode_to_amask(uint32_t desired_access)
case SMB_DA_ACCESS_EXECUTE:
return (FILE_GENERIC_EXECUTE);
- }
- /* invalid open mode */
- return ((uint32_t)SMB_INVALID_AMASK);
+ default:
+ return (FILE_GENERIC_ALL);
+ }
}
/*
@@ -149,11 +149,9 @@ smb_denymode_to_sharemode(uint32_t desired_access, char *fname)
return (FILE_SHARE_WRITE);
case SMB_DA_SHARE_DENY_NONE:
+ default:
return (FILE_SHARE_READ | FILE_SHARE_WRITE);
}
-
- /* invalid deny mode */
- return ((uint32_t)SMB_INVALID_SHAREMODE);
}
/*
@@ -176,7 +174,7 @@ smb_ofun_to_crdisposition(uint16_t ofun)
int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4;
if (row == 3)
- return ((uint32_t)SMB_INVALID_CRDISPOSITION);
+ return (FILE_MAXIMUM_DISPOSITION + 1);
return (ofun_cr_map[row][col]);
}
@@ -206,6 +204,11 @@ smb_common_open(smb_request_t *sr)
ERRDOS, ERROR_SHARING_VIOLATION);
}
+ if (status == NT_STATUS_NO_SUCH_FILE) {
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
+ }
+
return (status);
}
@@ -293,28 +296,27 @@ smb_common_open(smb_request_t *sr)
* 4. Opening an existing file or directory
* The request attributes are ignored.
*/
-
static uint32_t
smb_open_subr(smb_request_t *sr)
{
- int created = 0;
- struct smb_node *node = 0;
- struct smb_node *dnode = 0;
- struct smb_node *cur_node;
- struct open_param *op = &sr->arg.open;
- int rc;
- struct smb_ofile *of;
- smb_attr_t new_attr;
- int pathlen;
- int max_requested = 0;
- uint32_t max_allowed;
- uint32_t status = NT_STATUS_SUCCESS;
- int is_dir;
- smb_error_t err;
- int is_stream = 0;
- int lookup_flags = SMB_FOLLOW_LINKS;
- uint32_t daccess;
- uint32_t uniq_fid;
+ int created = 0;
+ smb_node_t *node = NULL;
+ smb_node_t *dnode = NULL;
+ smb_node_t *cur_node;
+ open_param_t *op = &sr->arg.open;
+ int rc;
+ smb_ofile_t *of;
+ smb_attr_t new_attr;
+ int pathlen;
+ int max_requested = 0;
+ uint32_t max_allowed;
+ uint32_t status = NT_STATUS_SUCCESS;
+ int is_dir;
+ smb_error_t err;
+ boolean_t is_stream = B_FALSE;
+ int lookup_flags = SMB_FOLLOW_LINKS;
+ uint32_t daccess;
+ uint32_t uniq_fid;
is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
@@ -479,7 +481,7 @@ smb_open_subr(smb_request_t *sr)
}
} else {
if ((op->create_options & FILE_DIRECTORY_FILE) ||
- (op->my_flags & MYF_MUST_BE_DIRECTORY)) {
+ (op->nt_flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)) {
smb_node_release(node);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
@@ -537,9 +539,10 @@ smb_open_subr(smb_request_t *sr)
}
if (smb_oplock_conflict(node, sr->session, op))
- smb_oplock_break(node);
+ (void) smb_oplock_break(node,
+ SMB_SESSION_GET_ID(sr->session), B_FALSE);
- rw_enter(&node->n_share_lock, RW_WRITER);
+ smb_node_wrlock(node);
if ((op->create_disposition == FILE_SUPERSEDE) ||
(op->create_disposition == FILE_OVERWRITE_IF) ||
@@ -549,8 +552,8 @@ smb_open_subr(smb_request_t *sr)
(FILE_WRITE_DATA | FILE_APPEND_DATA |
FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))) ||
(!smb_sattr_check(node->attr.sa_dosattr,
- op->dattr, NULL))) {
- rw_exit(&node->n_share_lock);
+ op->dattr))) {
+ smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
@@ -564,7 +567,7 @@ smb_open_subr(smb_request_t *sr)
op->desired_access, op->share_access);
if (status == NT_STATUS_SHARING_VIOLATION) {
- rw_exit(&node->n_share_lock);
+ smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
@@ -577,7 +580,7 @@ smb_open_subr(smb_request_t *sr)
if (status != NT_STATUS_SUCCESS) {
smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
- rw_exit(&node->n_share_lock);
+ smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
@@ -599,7 +602,7 @@ smb_open_subr(smb_request_t *sr)
case FILE_OVERWRITE:
if (node->attr.sa_vattr.va_type == VDIR) {
smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
- rw_exit(&node->n_share_lock);
+ smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
@@ -620,7 +623,7 @@ smb_open_subr(smb_request_t *sr)
if (rc) {
smb_fsop_unshrlock(sr->user_cr, node,
uniq_fid);
- rw_exit(&node->n_share_lock);
+ smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
@@ -659,7 +662,6 @@ smb_open_subr(smb_request_t *sr)
break;
}
} else {
-
/* Last component was not found. */
dnode = op->fqi.dir_snode;
@@ -675,11 +677,20 @@ smb_open_subr(smb_request_t *sr)
return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
}
+ if ((is_dir == 0) && (!is_stream) &&
+ smb_is_invalid_filename(op->fqi.last_comp)) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(op->fqi);
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
+ ERRDOS, ERROR_INVALID_NAME);
+ return (NT_STATUS_OBJECT_NAME_INVALID);
+ }
+
/*
* lock the parent dir node in case another create
* request to the same parent directory comes in.
*/
- smb_rwx_rwenter(&dnode->n_lock, RW_WRITER);
+ smb_node_wrlock(dnode);
bzero(&new_attr, sizeof (new_attr));
new_attr.sa_dosattr = op->dattr;
@@ -722,7 +733,7 @@ smb_open_subr(smb_request_t *sr)
&op->fqi.last_snode, &op->fqi.last_attr);
if (rc != 0) {
- smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_unlock(dnode);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
@@ -733,16 +744,16 @@ smb_open_subr(smb_request_t *sr)
op->fqi.last_attr = node->attr;
- rw_enter(&node->n_share_lock, RW_WRITER);
+ smb_node_wrlock(node);
status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
op->desired_access, op->share_access);
if (status == NT_STATUS_SHARING_VIOLATION) {
- rw_exit(&node->n_share_lock);
- smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_unlock(node);
SMB_DEL_NEWOBJ(op->fqi);
smb_node_release(node);
+ smb_node_unlock(dnode);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
return (status);
@@ -757,7 +768,7 @@ smb_open_subr(smb_request_t *sr)
op->fqi.last_comp, &new_attr,
&op->fqi.last_snode, &op->fqi.last_attr);
if (rc != 0) {
- smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_unlock(dnode);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
@@ -765,7 +776,7 @@ smb_open_subr(smb_request_t *sr)
}
node = op->fqi.last_snode;
- rw_enter(&node->n_share_lock, RW_WRITER);
+ smb_node_wrlock(node);
}
created = 1;
@@ -808,44 +819,16 @@ smb_open_subr(smb_request_t *sr)
smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
SMB_DEL_NEWOBJ(op->fqi);
- rw_exit(&node->n_share_lock);
+ smb_node_unlock(node);
smb_node_release(node);
if (created)
- smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_unlock(dnode);
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, err.status, err.errcls, err.errcode);
return (err.status);
}
- if (op->fqi.last_attr.sa_vattr.va_type == VREG) {
- status = smb_oplock_acquire(sr, of, op);
-
- if (status != NT_STATUS_SUCCESS) {
- rw_exit(&node->n_share_lock);
- /*
- * smb_fsop_unshrlock() and smb_fsop_close()
- * are called from smb_ofile_close()
- */
- smb_ofile_close(of, 0);
- smb_ofile_release(of);
- if (created)
- smb_rwx_rwexit(&dnode->n_lock);
-
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
-
- smbsr_error(sr, status,
- ERRDOS, ERROR_SHARING_VIOLATION);
- return (status);
- }
-
- op->dsize = op->fqi.last_attr.sa_vattr.va_size;
- } else { /* VDIR or VLNK */
- op->my_flags &= ~MYF_OPLOCK_MASK;
- op->dsize = 0;
- }
-
/*
* Propagate the write-through mode from the open params
* to the node: see the notes in the function header.
@@ -863,10 +846,18 @@ smb_open_subr(smb_request_t *sr)
sr->smb_fid = of->f_fid;
sr->fid_ofile = of;
- rw_exit(&node->n_share_lock);
+ smb_node_unlock(node);
if (created)
- smb_rwx_rwexit(&dnode->n_lock);
+ smb_node_unlock(dnode);
+
+ if (op->fqi.last_attr.sa_vattr.va_type == VREG) {
+ smb_oplock_acquire(node, of, op);
+ op->dsize = op->fqi.last_attr.sa_vattr.va_size;
+ } else { /* VDIR or VLNK */
+ op->op_oplock_level = SMB_OPLOCK_NONE;
+ op->dsize = 0;
+ }
smb_node_release(dnode);
SMB_NULL_FQI_NODES(op->fqi);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
index dd40d6acbf..2daa29a306 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c
@@ -19,9 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- *
*/
#include <smbsrv/smb_incl.h>
@@ -1373,7 +1372,7 @@ smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
uint16_t devstate;
char *req_fmt;
char *rep_fmt;
- struct vardata_block vdb;
+ smb_vdb_t vdb;
n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
n_setup++;
@@ -1403,8 +1402,7 @@ smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
break;
case TRANS_TRANSACT_NMPIPE:
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
- sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERRbadfid);
@@ -1416,7 +1414,7 @@ smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
if (rc != 0)
goto trans_err_not_supported;
- rc = smb_opipe_transact(sr, &vdb.uio);
+ rc = smb_opipe_transact(sr, &vdb.vdb_uio);
break;
case TRANS_WAIT_NMPIPE:
@@ -1586,6 +1584,10 @@ smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa)
/* for now, only respond to the */
switch (opcode) {
+ case TRANS2_OPEN2:
+ rc = smb_com_trans2_open2(sr, xa);
+ break;
+
case TRANS2_CREATE_DIRECTORY:
rc = smb_com_trans2_create_directory(sr, xa);
break;
@@ -1663,6 +1665,7 @@ smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa)
rc = smb_com_trans2_set_file_information(sr, xa);
break;
default:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
goto trans_err_not_supported;
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_create.c b/usr/src/uts/common/fs/smbsrv/smb_create.c
index b2e1090136..bb8ce0e9e1 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_create.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -186,30 +186,23 @@ smb_common_create(smb_request_t *sr)
if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX))
op->mtime.tv_sec = smb_local2gmt(sr, op->mtime.tv_sec);
op->mtime.tv_nsec = 0;
+ op->dsize = 0;
op->omode = SMB_DA_ACCESS_READ_WRITE | SMB_DA_SHARE_COMPATIBILITY;
op->desired_access = smb_omode_to_amask(op->omode);
op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
- if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
- (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
- ERRDOS, ERROR_INVALID_PARAMETER);
- return (NT_STATUS_INVALID_PARAMETER);
- }
-
- op->dsize = 0;
-
if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
- if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) {
- op->my_flags = MYF_BATCH_OPLOCK;
- } else {
- op->my_flags = MYF_EXCLUSIVE_OPLOCK;
- }
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY)
+ op->op_oplock_level = SMB_OPLOCK_BATCH;
+ else
+ op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
+ } else {
+ op->op_oplock_level = SMB_OPLOCK_NONE;
}
status = smb_common_open(sr);
- if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) {
+ if (op->op_oplock_level == SMB_OPLOCK_NONE) {
sr->smb_flg &=
~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_create_directory.c b/usr/src/uts/common/fs/smbsrv/smb_create_directory.c
deleted file mode 100644
index cd2c5c242d..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_create_directory.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * SMB: create_directory
- *
- * The create directory message is sent to create a new directory. The
- * appropriate Tid and additional pathname are passed. The directory must
- * not exist for it to be created.
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes; min = 2
- * UCHAR BufferFormat; 0x04
- * STRING DirectoryName[]; Directory name
- *
- * Servers require clients to have at least create permission for the
- * subtree containing the directory in order to create a new directory.
- * The creator's access rights to the new directory are be determined by
- * local policy on the server.
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- *
- * USHORT ByteCount; Count of data bytes = 0
- */
-
-#include <smbsrv/nterror.h>
-#include <smbsrv/ntstatus.h>
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-typedef struct {
- char *sp_path; /* Original path */
- char *sp_curp; /* Current pointer into the original path */
- smb_request_t *sp_sr; /* Current request pointer */
-} SmbPath;
-
-
-static int smbpath_next(SmbPath *spp);
-static SmbPath* smbpath_new(smb_request_t *sr);
-
-smb_sdrc_t
-smb_pre_create_directory(smb_request_t *sr)
-{
- int rc;
-
- rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path);
-
- DTRACE_SMB_2(op__CreateDirectory__start, smb_request_t *, sr,
- struct dirop *, &sr->arg.dirop);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
-
-void
-smb_post_create_directory(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__CreateDirectory__done, smb_request_t *, sr);
-}
-
-/*
- * smb_com_create_directory
- *
- * It is possible to get a full pathname here and the client expects any
- * or all of the components to be created if they don't already exist.
- */
-smb_sdrc_t
-smb_com_create_directory(smb_request_t *sr)
-{
- SmbPath* spp;
- DWORD status;
- int rc = 0;
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- if ((status = smb_validate_dirname(sr->arg.dirop.fqi.path)) != 0) {
- smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
- return (SDRC_ERROR);
- }
-
- /*
- * Try each component of the path. It is all right to get an EEXIST
- * on each component except the last.
- */
- spp = smbpath_new(sr);
-
- while (smbpath_next(spp)) {
- rc = smb_common_create_directory(sr);
- if (rc != 0 && rc != EEXIST) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
- }
-
- /* We should have created one directory successfully! */
- if (rc != 0) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- rc = smbsr_encode_empty_result(sr);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
-
-
-/*
- * smb_validate_dirname
- *
- * Very basic directory name validation: checks for colons in a path.
- * Need to skip the drive prefix since it contains a colon.
- *
- * Returns 0 if the name is valid, otherwise NT_STATUS_NOT_A_DIRECTORY.
- */
-DWORD
-smb_validate_dirname(char *path)
-{
- char *name;
-
- if ((name = path) != 0) {
- name += strspn(name, "\\");
-
- if (strchr(name, ':') != 0)
- return (NT_STATUS_NOT_A_DIRECTORY);
- }
-
- return (0);
-}
-
-
-/*
- * smb_common_create_directory
- *
- * Currently called from:
- * smb_com_create_directory
- * smb_com_trans2_create_directory
- *
- * Returns errno values.
- */
-int
-smb_common_create_directory(smb_request_t *sr)
-{
- int rc;
- smb_attr_t new_attr;
- struct smb_node *dnode;
- struct smb_node *node;
-
- sr->arg.dirop.fqi.srch_attr = 0;
-
- rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_NOT_EXIST);
- if (rc)
- return (rc);
-
- /*
- * Because of FQM_PATH_MUST_NOT_EXIST and the successful return
- * value, only fqi.dir_snode has a valid parameter (fqi.last_snode
- * is NULL).
- */
- dnode = sr->arg.dirop.fqi.dir_snode;
-
- /*
- * Explicitly set sa_dosattr, otherwise the file system may
- * automatically apply FILE_ATTRIBUTE_ARCHIVE which, for
- * compatibility with windows servers, should not be set.
- */
- bzero(&new_attr, sizeof (new_attr));
- new_attr.sa_dosattr = FILE_ATTRIBUTE_DIRECTORY;
- new_attr.sa_vattr.va_type = VDIR;
- new_attr.sa_vattr.va_mode = 0777;
- new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR;
-
- if ((rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
- sr->arg.dirop.fqi.last_comp, &new_attr,
- &sr->arg.dirop.fqi.last_snode,
- &sr->arg.dirop.fqi.last_attr)) != 0) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
- return (rc);
- }
-
- node = sr->arg.dirop.fqi.last_snode;
- node->flags |= NODE_FLAGS_CREATED;
-
- sr->arg.open.create_options = FILE_DIRECTORY_FILE;
-
- smb_node_release(node);
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
- return (0);
-}
-
-SmbPath*
-smbpath_new(smb_request_t *sr)
-{
- int pathLen;
- char *xpath;
- SmbPath *spp;
-
- /* Malloc from the request storage area. This is freed automatically */
- /* so we don't need to worry about freeing it later */
- spp = smbsr_malloc(&sr->request_storage, sizeof (SmbPath));
- spp->sp_path = sr->arg.dirop.fqi.path;
- pathLen = strlen(spp->sp_path);
- spp->sp_curp = spp->sp_path;
- xpath = smbsr_malloc(&sr->request_storage, pathLen + 1);
- sr->arg.dirop.fqi.path = xpath;
- spp->sp_sr = sr;
-
- return (spp);
-}
-
-/*
- * Perhaps somewhat dangerous since everything happens as a side effect. The
- * returns 1 if there is a valid component updated to the fqi, 0 otherwise.
- */
-int
-smbpath_next(SmbPath* spp)
-{
- char *xp;
- int xlen;
-
- if (spp == 0)
- return (0);
-
- /* Move the index to the "next" "\" and copy the path to the fqi */
- /* path for the next component. */
-
- /* First look for the next component */
- while (*spp->sp_curp == '\\')
- spp->sp_curp++;
-
- /* Now get to the end of the component */
- xp = spp->sp_curp; /* Remember from where we started */
- while (*spp->sp_curp != '\0' && *spp->sp_curp != '\\') {
- spp->sp_curp++;
- }
-
- /* If we made no progress, we are done */
- if (xp == spp->sp_curp)
- return (0);
-
- /*
- * Now copy the original path up to but not including our current
- * pointer
- */
-
- /*LINTED E_PTRDIFF_OVERFLOW*/
- xlen = spp->sp_curp - spp->sp_path;
- (void) strncpy(spp->sp_sr->arg.dirop.fqi.path, spp->sp_path, xlen);
-
- /* Now NULL terminate it */
- spp->sp_sr->arg.dirop.fqi.path[xlen] = '\0';
- return (1);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete.c b/usr/src/uts/common/fs/smbsrv/smb_delete.c
index 213f04650e..2b07ae3f94 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c
@@ -484,7 +484,7 @@ smb_delete_remove_file(smb_request_t *sr, smb_error_t *err)
fqi = &sr->arg.dirop.fqi;
node = fqi->last_snode;
- smb_oplock_break(node);
+ (void) smb_oplock_break(node, SMB_SESSION_GET_ID(sr->session), B_FALSE);
smb_node_start_crit(node, RW_READER);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c b/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c
deleted file mode 100644
index ecf614ea80..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_delete_directory.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "@(#)smb_delete_directory.c 1.5 08/08/04 SMI"
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-#include <smbsrv/smbinfo.h>
-
-/*
- * smb_com_delete_directory
- *
- * The delete directory message is sent to delete an empty directory. The
- * appropriate Tid and additional pathname are passed. The directory must
- * be empty for it to be deleted.
- *
- * NT supports a hidden permission known as File Delete Child (FDC). If
- * the user has FullControl access to a directory, the user is permitted
- * to delete any object in the directory regardless of the permissions
- * on the object.
- *
- * Client Request Description
- * ================================== =================================
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes; min = 2
- * UCHAR BufferFormat; 0x04
- * STRING DirectoryName[]; Directory name
- *
- * The directory to be deleted cannot be the root of the share specified
- * by Tid.
- *
- * Server Response Description
- * ================================== =================================
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes = 0
- */
-smb_sdrc_t
-smb_pre_delete_directory(smb_request_t *sr)
-{
- int rc;
-
- rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path);
-
- DTRACE_SMB_2(op__DeleteDirectory__start, smb_request_t *, sr,
- struct dirop *, &sr->arg.dirop);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
-
-void
-smb_post_delete_directory(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__DeleteDirectory__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_delete_directory(smb_request_t *sr)
-{
- smb_node_t *dnode;
- int rc;
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- sr->arg.dirop.fqi.srch_attr = 0;
-
- rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
- if (rc) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- dnode = sr->arg.dirop.fqi.last_snode;
-
- if (dnode->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) {
- smb_node_release(dnode);
- smb_node_release(sr->arg.dirop.fqi.dir_snode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
-
- smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- smb_node_release(dnode);
-
- dnode = sr->arg.dirop.fqi.dir_snode;
-
- rc = smb_fsop_rmdir(sr, sr->user_cr, dnode,
- sr->arg.dirop.fqi.last_comp_od, 1);
- if (rc != 0) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
- if (rc == EEXIST)
- smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
- ERRDOS, ERROR_DIR_NOT_EMPTY);
- else
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
-
- rc = smbsr_encode_empty_result(sr);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_directory.c b/usr/src/uts/common/fs/smbsrv/smb_directory.c
new file mode 100644
index 0000000000..3960fd5514
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_directory.c
@@ -0,0 +1,565 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <smbsrv/nterror.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+typedef struct smb_dirpath {
+ char *sp_path; /* Original path */
+ char *sp_curp; /* Current pointer into the original path */
+ smb_request_t *sp_sr; /* Current request pointer */
+} smb_dirpath_t;
+
+static smb_dirpath_t *smb_dirpath_new(smb_request_t *);
+static int smb_dirpath_next(smb_dirpath_t *);
+static boolean_t smb_dirpath_isvalid(const char *);
+
+/*
+ * The create directory message is sent to create a new directory. The
+ * appropriate Tid and additional pathname are passed. The directory must
+ * not exist for it to be created.
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING DirectoryName[]; Directory name
+ *
+ * Servers require clients to have at least create permission for the
+ * subtree containing the directory in order to create a new directory.
+ * The creator's access rights to the new directory are be determined by
+ * local policy on the server.
+ *
+ * Server Response Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ */
+smb_sdrc_t
+smb_pre_create_directory(smb_request_t *sr)
+{
+ int rc;
+
+ rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path);
+
+ DTRACE_SMB_2(op__CreateDirectory__start, smb_request_t *, sr,
+ struct dirop *, &sr->arg.dirop);
+
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+void
+smb_post_create_directory(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__CreateDirectory__done, smb_request_t *, sr);
+}
+
+/*
+ * smb_com_create_directory
+ *
+ * It is possible to get a full pathname here and the client expects any
+ * or all of the components to be created if they don't already exist.
+ */
+smb_sdrc_t
+smb_com_create_directory(smb_request_t *sr)
+{
+ smb_dirpath_t *spp;
+ smb_attr_t *attr;
+ DWORD status;
+ int rc = 0;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
+
+ if (!smb_dirpath_isvalid(sr->arg.dirop.fqi.path)) {
+ smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
+ ERRDOS, ERROR_BAD_PATHNAME);
+ return (SDRC_ERROR);
+ }
+
+ if ((status = smb_validate_dirname(sr->arg.dirop.fqi.path)) != 0) {
+ smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
+ return (SDRC_ERROR);
+ }
+
+ /*
+ * Try each component of the path. EEXIST on path
+ * components is okay except on the last one.
+ */
+ spp = smb_dirpath_new(sr);
+
+ while (smb_dirpath_next(spp)) {
+ rc = smb_common_create_directory(sr);
+
+ switch (rc) {
+ case 0:
+ break;
+ case EEXIST:
+ attr = &sr->arg.dirop.fqi.last_attr;
+
+ if (attr->sa_vattr.va_type != VDIR) {
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
+ ERRDOS, ERROR_PATH_NOT_FOUND);
+ return (SDRC_ERROR);
+ }
+ break;
+ case ENOENT:
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
+ return (SDRC_ERROR);
+ case ENOTDIR:
+ smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
+ ERRDOS, ERROR_PATH_NOT_FOUND);
+ return (SDRC_ERROR);
+ default:
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+ }
+
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ rc = smbsr_encode_empty_result(sr);
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+/*
+ * smb_validate_dirname
+ *
+ * Very basic directory name validation: checks for colons in a path.
+ * Need to skip the drive prefix since it contains a colon.
+ *
+ * Returns 0 if the name is valid, otherwise NT_STATUS_NOT_A_DIRECTORY.
+ */
+DWORD
+smb_validate_dirname(char *path)
+{
+ char *name;
+
+ if ((name = path) != 0) {
+ name += strspn(name, "\\");
+
+ if (strchr(name, ':') != 0)
+ return (NT_STATUS_NOT_A_DIRECTORY);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_common_create_directory
+ *
+ * Currently called from:
+ * smb_com_create_directory
+ * smb_com_trans2_create_directory
+ *
+ * Returns errno values.
+ */
+int
+smb_common_create_directory(smb_request_t *sr)
+{
+ int rc;
+ smb_attr_t new_attr;
+ smb_node_t *dnode;
+ smb_node_t *node;
+
+ sr->arg.dirop.fqi.srch_attr = 0;
+
+ rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_NOT_EXIST);
+ if (rc)
+ return (rc);
+
+ /*
+ * Because of FQM_PATH_MUST_NOT_EXIST and the successful return
+ * value, only fqi.dir_snode has a valid parameter (fqi.last_snode
+ * is NULL).
+ */
+ dnode = sr->arg.dirop.fqi.dir_snode;
+
+ rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_ADD_SUBDIRECTORY);
+ if (rc != NT_STATUS_SUCCESS)
+ return (EACCES);
+
+ /*
+ * Explicitly set sa_dosattr, otherwise the file system may
+ * automatically apply FILE_ATTRIBUTE_ARCHIVE which, for
+ * compatibility with windows servers, should not be set.
+ */
+ bzero(&new_attr, sizeof (new_attr));
+ new_attr.sa_dosattr = FILE_ATTRIBUTE_DIRECTORY;
+ new_attr.sa_vattr.va_type = VDIR;
+ new_attr.sa_vattr.va_mode = 0777;
+ new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR;
+
+ if ((rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
+ sr->arg.dirop.fqi.last_comp, &new_attr,
+ &sr->arg.dirop.fqi.last_snode,
+ &sr->arg.dirop.fqi.last_attr)) != 0) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ return (rc);
+ }
+
+ node = sr->arg.dirop.fqi.last_snode;
+ node->flags |= NODE_FLAGS_CREATED;
+
+ sr->arg.open.create_options = FILE_DIRECTORY_FILE;
+
+ smb_node_release(node);
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ return (0);
+}
+
+static smb_dirpath_t *
+smb_dirpath_new(smb_request_t *sr)
+{
+ int pathLen;
+ char *xpath;
+ smb_dirpath_t *spp;
+
+ /* Malloc from the request storage area. This is freed automatically */
+ /* so we don't need to worry about freeing it later */
+ spp = smbsr_malloc(&sr->request_storage, sizeof (smb_dirpath_t));
+ spp->sp_path = sr->arg.dirop.fqi.path;
+ pathLen = strlen(spp->sp_path);
+ spp->sp_curp = spp->sp_path;
+ xpath = smbsr_malloc(&sr->request_storage, pathLen + 1);
+ sr->arg.dirop.fqi.path = xpath;
+ spp->sp_sr = sr;
+
+ return (spp);
+}
+
+/*
+ * Perhaps somewhat dangerous since everything happens as a side effect. The
+ * returns 1 if there is a valid component updated to the fqi, 0 otherwise.
+ */
+static int
+smb_dirpath_next(smb_dirpath_t *spp)
+{
+ char *xp;
+ int xlen;
+
+ if (spp == 0)
+ return (0);
+
+ /* Move the index to the "next" "\" and copy the path to the fqi */
+ /* path for the next component. */
+
+ /* First look for the next component */
+ while (*spp->sp_curp == '\\')
+ spp->sp_curp++;
+
+ /* Now get to the end of the component */
+ xp = spp->sp_curp; /* Remember from where we started */
+ while (*spp->sp_curp != '\0' && *spp->sp_curp != '\\') {
+ spp->sp_curp++;
+ }
+
+ /* If we made no progress, we are done */
+ if (xp == spp->sp_curp)
+ return (0);
+
+ /*
+ * Now copy the original path up to but not including our current
+ * pointer
+ */
+
+ /*LINTED E_PTRDIFF_OVERFLOW*/
+ xlen = spp->sp_curp - spp->sp_path;
+ (void) strncpy(spp->sp_sr->arg.dirop.fqi.path, spp->sp_path, xlen);
+
+ /* Now NULL terminate it */
+ spp->sp_sr->arg.dirop.fqi.path[xlen] = '\0';
+ return (1);
+}
+
+/*
+ * The delete directory message is sent to delete an empty directory. The
+ * appropriate Tid and additional pathname are passed. The directory must
+ * be empty for it to be deleted.
+ *
+ * NT supports a hidden permission known as File Delete Child (FDC). If
+ * the user has FullControl access to a directory, the user is permitted
+ * to delete any object in the directory regardless of the permissions
+ * on the object.
+ *
+ * Client Request Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING DirectoryName[]; Directory name
+ *
+ * The directory to be deleted cannot be the root of the share specified
+ * by Tid.
+ *
+ * Server Response Description
+ * ================================== =================================
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ */
+smb_sdrc_t
+smb_pre_delete_directory(smb_request_t *sr)
+{
+ int rc;
+
+ rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path);
+
+ DTRACE_SMB_2(op__DeleteDirectory__start, smb_request_t *, sr,
+ struct dirop *, &sr->arg.dirop);
+
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+void
+smb_post_delete_directory(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__DeleteDirectory__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_delete_directory(smb_request_t *sr)
+{
+ smb_node_t *dnode;
+ smb_attr_t *attr;
+ int rc;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
+
+ sr->arg.dirop.fqi.srch_attr = 0;
+
+ rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
+ if (rc) {
+ if (rc == ENOENT)
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
+ else
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ attr = &sr->arg.dirop.fqi.last_attr;
+ if (attr->sa_vattr.va_type != VDIR) {
+ smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
+ ERRDOS, ERROR_PATH_NOT_FOUND);
+ return (SDRC_ERROR);
+ }
+
+ dnode = sr->arg.dirop.fqi.last_snode;
+ rc = smb_fsop_access(sr, sr->user_cr, dnode, DELETE);
+
+ if ((rc != NT_STATUS_SUCCESS) ||
+ (dnode->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
+ smb_node_release(dnode);
+ smb_node_release(sr->arg.dirop.fqi.dir_snode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
+
+ smb_node_release(dnode);
+
+ dnode = sr->arg.dirop.fqi.dir_snode;
+
+ rc = smb_fsop_rmdir(sr, sr->user_cr, dnode,
+ sr->arg.dirop.fqi.last_comp_od, 1);
+ if (rc != 0) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ if (rc == EEXIST)
+ smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
+ ERRDOS, ERROR_DIR_NOT_EMPTY);
+ else
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ rc = smbsr_encode_empty_result(sr);
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+/*
+ * This SMB is used to verify that a path exists and is a directory. No
+ * error is returned if the given path exists and the client has read
+ * access to it. Client machines which maintain a concept of a "working
+ * directory" will find this useful to verify the validity of a "change
+ * working directory" command. Note that the servers do NOT have a concept
+ * of working directory for a particular client. The client must always
+ * supply full pathnames relative to the Tid in the SMB header.
+ *
+ * Client Request Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes; min = 2
+ * UCHAR BufferFormat; 0x04
+ * STRING DirectoryPath[]; Directory path
+ *
+ * Server Response Description
+ * ================================== =================================
+ *
+ * UCHAR WordCount; Count of parameter words = 0
+ * USHORT ByteCount; Count of data bytes = 0
+ *
+ * DOS clients, in particular, depend on ERRbadpath if the directory is
+ * not found.
+ */
+smb_sdrc_t
+smb_pre_check_directory(smb_request_t *sr)
+{
+ int rc;
+
+ rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.path);
+
+ DTRACE_SMB_2(op__CheckDirectory__start, smb_request_t *, sr,
+ struct dirop *, &sr->arg.dirop);
+
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+void
+smb_post_check_directory(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__CheckDirectory__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_check_directory(smb_request_t *sr)
+{
+ smb_node_t *dnode;
+ int rc;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
+ ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
+
+ if (sr->arg.dirop.fqi.path[0] == '\0') {
+ rc = smbsr_encode_empty_result(sr);
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+ }
+
+ if (!smb_dirpath_isvalid(sr->arg.dirop.fqi.path)) {
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
+ ERRDOS, ERROR_PATH_NOT_FOUND);
+ return (SDRC_ERROR);
+ }
+
+ sr->arg.dirop.fqi.srch_attr = 0;
+
+ rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
+ if (rc) {
+ if (rc == ENOENT)
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_PATH_NOT_FOUND);
+ else
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ smb_node_release(sr->arg.dirop.fqi.dir_snode);
+
+ dnode = sr->arg.dirop.fqi.last_snode;
+
+ if (sr->arg.dirop.fqi.last_attr.sa_vattr.va_type != VDIR) {
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
+ ERRDOS, ERROR_PATH_NOT_FOUND);
+ return (SDRC_ERROR);
+ }
+
+ rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_TRAVERSE);
+
+ smb_node_release(dnode);
+ SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+
+ if (rc != 0) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
+
+ rc = smbsr_encode_empty_result(sr);
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+static boolean_t
+smb_dirpath_isvalid(const char *path)
+{
+ struct {
+ char *name;
+ int len;
+ } *bad, bad_paths[] = {
+ { ".\0", 2 },
+ { ".\\\0", 3 },
+ { "..\0", 3 },
+ { "..\\", 3 }
+ };
+
+ char *cp;
+ char *p;
+ int i;
+
+ if (*path == '\0')
+ return (B_TRUE);
+
+ cp = smb_kstrdup(path, MAXPATHLEN);
+ p = strcanon(cp, "\\");
+ p += strspn(p, "\\");
+
+ for (i = 0; i < sizeof (bad_paths) / sizeof (bad_paths[0]); ++i) {
+ bad = &bad_paths[i];
+
+ if (strncmp(p, bad->name, bad->len) == 0) {
+ kmem_free(cp, MAXPATHLEN);
+ return (B_FALSE);
+ }
+ }
+
+ kmem_free(cp, MAXPATHLEN);
+ return (B_TRUE);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
index c5461501c0..18ac05575d 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
@@ -21,13 +21,10 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
- *
- *
- * Dispatching SMB requests.
*/
/*
- * ALMOST EVERYTHING YOU NEED TO KNOW ABOUT A SERVER MESSAGE BLOCK
+ * SMB requests.
*
* Request
* Header
@@ -151,7 +148,7 @@ static kmutex_t smb_dispatch_ksmtx;
static int is_andx_com(unsigned char);
static int smbsr_check_result(struct smb_request *, int, int);
-static smb_dispatch_table_t dispatch[SMB_COM_NUM] = {
+static smb_disp_entry_t dispatch[SMB_COM_NUM] = {
{ SMB_SDT_OPS(create_directory), /* 0x00 000 */
PC_NETWORK_PROGRAM_1_0, 0, RW_READER,
{ "SmbCreateDirectory", KSTAT_DATA_UINT64 } },
@@ -545,9 +542,6 @@ smbsr_cleanup(smb_request_t *sr)
ASSERT((sr->sr_state != SMB_REQ_STATE_CLEANED_UP) &&
(sr->sr_state != SMB_REQ_STATE_COMPLETED));
- if (sr->fid_ofile)
- smbsr_disconnect_file(sr);
-
if (sr->r_xa) {
if (sr->r_xa->xa_flags & SMB_XA_FLAG_COMPLETE)
smb_xa_close(sr->r_xa);
@@ -578,11 +572,14 @@ boolean_t
smb_dispatch_request(struct smb_request *sr)
{
smb_sdrc_t sdrc;
- smb_dispatch_table_t *sdd;
+ smb_disp_entry_t *sdd;
boolean_t disconnect = B_FALSE;
smb_session_t *session;
+ uint32_t capabilities;
+ uint32_t byte_count;
session = sr->session;
+ capabilities = session->capabilities;
ASSERT(sr->tid_tree == 0);
ASSERT(sr->uid_user == 0);
@@ -675,10 +672,24 @@ andx_more:
goto report_error;
}
+ /*
+ * Ignore smb_bcc if CAP_LARGE_READX/CAP_LARGE_WRITEX
+ * and this is SmbReadX/SmbWriteX since this enables
+ * large reads/write and bcc is only 16-bits.
+ */
+ if (((sr->smb_com == SMB_COM_READ_ANDX) &&
+ (capabilities & CAP_LARGE_READX)) ||
+ ((sr->smb_com == SMB_COM_WRITE_ANDX) &&
+ (capabilities & CAP_LARGE_WRITEX))) {
+ byte_count = sr->command.max_bytes - sr->command.chain_offset;
+ } else {
+ byte_count = (uint32_t)sr->smb_bcc;
+ }
+
(void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command,
- sr->command.chain_offset, sr->smb_bcc);
+ sr->command.chain_offset, byte_count);
- sr->command.chain_offset += sr->smb_bcc;
+ sr->command.chain_offset += byte_count;
if (sr->command.chain_offset > sr->command.max_bytes) {
disconnect = B_TRUE;
goto report_error;
@@ -1168,6 +1179,14 @@ smbsr_disconnect_file(smb_request_t *sr)
(void) smb_ofile_release(of);
}
+void
+smbsr_lookup_file(smb_request_t *sr)
+{
+ if (sr->fid_ofile == NULL)
+ sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
+ sr->smb_fid);
+}
+
static int
is_andx_com(unsigned char com)
{
@@ -1241,8 +1260,8 @@ smb_com_invalid(smb_request_t *sr)
static int
smb_dispatch_kstat_update(kstat_t *ksp, int rw)
{
- smb_dispatch_table_t *sdd;
- kstat_named_t *ks_named;
+ smb_disp_entry_t *sdd;
+ kstat_named_t *ks_named;
int i;
if (rw == KSTAT_WRITE)
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fem.c b/usr/src/uts/common/fs/smbsrv/smb_fem.c
index 514c2f2b09..f88ff345af 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_fem.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_fem.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
#include <sys/sdt.h>
@@ -108,6 +106,8 @@ static const fs_operation_def_t smb_oplock_tmpl[] = {
NULL, NULL
};
+static int smb_fem_oplock_break(femarg_t *, caller_context_t *);
+
/*
* smb_fem_init
*
@@ -397,21 +397,19 @@ smb_fem_fcn_symlink(
* CIFS higher-level routines will break oplocks as needed prior
* to getting to the VFS layer.
*/
-
-#define SMB_FEM_OPLOCK_BREAK(arg) \
- smb_oplock_break((smb_node_t *)((arg)->fa_fnode->fn_available));
-
static int
smb_fem_oplock_open(
- femarg_t *arg,
- int mode,
- cred_t *cr,
- struct caller_context *ct)
+ femarg_t *arg,
+ int mode,
+ cred_t *cr,
+ caller_context_t *ct)
{
- if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id)
- SMB_FEM_OPLOCK_BREAK(arg);
+ int rc;
- return (vnext_open(arg, mode, cr, ct));
+ rc = smb_fem_oplock_break(arg, ct);
+ if (rc == 0)
+ rc = vnext_open(arg, mode, cr, ct);
+ return (rc);
}
/*
@@ -421,16 +419,18 @@ smb_fem_oplock_open(
static int
smb_fem_oplock_read(
- femarg_t *arg,
- uio_t *uiop,
- int ioflag,
- cred_t *cr,
- struct caller_context *ct)
+ femarg_t *arg,
+ uio_t *uiop,
+ int ioflag,
+ cred_t *cr,
+ caller_context_t *ct)
{
- if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id)
- SMB_FEM_OPLOCK_BREAK(arg);
+ int rc;
- return (vnext_read(arg, uiop, ioflag, cr, ct));
+ rc = smb_fem_oplock_break(arg, ct);
+ if (rc == 0)
+ rc = vnext_read(arg, uiop, ioflag, cr, ct);
+ return (rc);
}
/*
@@ -440,74 +440,84 @@ smb_fem_oplock_read(
static int
smb_fem_oplock_write(
- femarg_t *arg,
- uio_t *uiop,
- int ioflag,
- cred_t *cr,
- struct caller_context *ct)
+ femarg_t *arg,
+ uio_t *uiop,
+ int ioflag,
+ cred_t *cr,
+ caller_context_t *ct)
{
- if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id)
- SMB_FEM_OPLOCK_BREAK(arg);
+ int rc;
- return (vnext_write(arg, uiop, ioflag, cr, ct));
+ rc = smb_fem_oplock_break(arg, ct);
+ if (rc == 0)
+ rc = vnext_write(arg, uiop, ioflag, cr, ct);
+ return (rc);
}
static int
smb_fem_oplock_setattr(
- femarg_t *arg,
- vattr_t *vap,
- int flags,
- cred_t *cr,
- caller_context_t *ct)
+ femarg_t *arg,
+ vattr_t *vap,
+ int flags,
+ cred_t *cr,
+ caller_context_t *ct)
{
- if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id)
- SMB_FEM_OPLOCK_BREAK(arg);
+ int rc;
- return (vnext_setattr(arg, vap, flags, cr, ct));
+ rc = smb_fem_oplock_break(arg, ct);
+ if (rc == 0)
+ rc = vnext_setattr(arg, vap, flags, cr, ct);
+ return (rc);
}
static int
smb_fem_oplock_rwlock(
- femarg_t *arg,
- int write_lock,
- caller_context_t *ct)
+ femarg_t *arg,
+ int write_lock,
+ caller_context_t *ct)
{
if (write_lock) {
- if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id)
- SMB_FEM_OPLOCK_BREAK(arg);
- }
+ int rc;
+ rc = smb_fem_oplock_break(arg, ct);
+ if (rc != 0)
+ return (rc);
+ }
return (vnext_rwlock(arg, write_lock, ct));
}
static int
smb_fem_oplock_space(
- femarg_t *arg,
- int cmd,
- flock64_t *bfp,
- int flag,
- offset_t offset,
- cred_t *cr,
- caller_context_t *ct)
+ femarg_t *arg,
+ int cmd,
+ flock64_t *bfp,
+ int flag,
+ offset_t offset,
+ cred_t *cr,
+ caller_context_t *ct)
{
- if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id)
- SMB_FEM_OPLOCK_BREAK(arg);
+ int rc;
- return (vnext_space(arg, cmd, bfp, flag, offset, cr, ct));
+ rc = smb_fem_oplock_break(arg, ct);
+ if (rc == 0)
+ rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct);
+ return (rc);
}
static int
smb_fem_oplock_setsecattr(
- femarg_t *arg,
- vsecattr_t *vsap,
- int flag,
- cred_t *cr,
- caller_context_t *ct)
+ femarg_t *arg,
+ vsecattr_t *vsap,
+ int flag,
+ cred_t *cr,
+ caller_context_t *ct)
{
- if (ct == NULL || ct->cc_caller_id != smb_ct.cc_caller_id)
- SMB_FEM_OPLOCK_BREAK(arg);
+ int rc;
- return (vnext_setsecattr(arg, vsap, flag, cr, ct));
+ rc = smb_fem_oplock_break(arg, ct);
+ if (rc == 0)
+ rc = vnext_setsecattr(arg, vsap, flag, cr, ct);
+ return (rc);
}
/*
@@ -526,18 +536,21 @@ smb_fem_oplock_setsecattr(
static int
smb_fem_oplock_vnevent(
- femarg_t *arg,
- vnevent_t vnevent,
- vnode_t *dvp,
- char *name,
- caller_context_t *ct)
+ femarg_t *arg,
+ vnevent_t vnevent,
+ vnode_t *dvp,
+ char *name,
+ caller_context_t *ct)
{
+ int rc;
+
switch (vnevent) {
case VE_REMOVE:
case VE_RENAME_DEST:
case VE_RENAME_SRC:
-
- SMB_FEM_OPLOCK_BREAK(arg);
+ rc = smb_fem_oplock_break(arg, ct);
+ if (rc != 0)
+ return (rc);
break;
default:
@@ -545,3 +558,32 @@ smb_fem_oplock_vnevent(
}
return (vnext_vnevent(arg, vnevent, dvp, name, ct));
}
+
+static int
+smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct)
+{
+ smb_node_t *node;
+ int rc;
+
+ node = (smb_node_t *)((arg)->fa_fnode->fn_available);
+ SMB_NODE_VALID(node);
+
+ if (ct == NULL) {
+ (void) smb_oplock_break(node, 0, B_FALSE);
+ return (0);
+ }
+
+ if (ct->cc_caller_id == smb_ct.cc_caller_id)
+ return (0);
+
+ if (ct->cc_flags & CC_DONTBLOCK) {
+ if (smb_oplock_break(node, 0, B_TRUE))
+ return (0);
+ ct->cc_flags |= CC_WOULDBLOCK;
+ rc = EAGAIN;
+ } else {
+ (void) smb_oplock_break(node, 0, B_FALSE);
+ rc = 0;
+ }
+ return (rc);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find.c b/usr/src/uts/common/fs/smbsrv/smb_find.c
index fd0aa16d4c..409b3ef734 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_find.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_find.c
@@ -324,9 +324,6 @@ smb_com_search(smb_request_t *sr)
if ((rc != 0 || (eos == B_TRUE)))
break;
- if (smb_is_dot_or_dotdot(fileinfo.fi_name))
- continue;
-
(void) memset(name, ' ', sizeof (name));
if (*fileinfo.fi_shortname == '\0') {
(void) strlcpy(name, fileinfo.fi_name,
@@ -604,18 +601,18 @@ smb_com_find_unique(struct smb_request *sr)
smb_odir_t *od;
smb_fileinfo_t fileinfo;
boolean_t eos;
- struct vardata_block *vdb;
+ smb_vdb_t *vdb;
if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
return (SDRC_ERROR);
- vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
+ vdb = kmem_alloc(sizeof (smb_vdb_t), KM_SLEEP);
if ((smbsr_decode_data(sr, "%AV", sr, &path, vdb) != 0) ||
- (vdb->len != 0)) {
- kmem_free(vdb, sizeof (struct vardata_block));
+ (vdb->vdb_len != 0)) {
+ kmem_free(vdb, sizeof (smb_vdb_t));
return (SDRC_ERROR);
}
- kmem_free(vdb, sizeof (struct vardata_block));
+ kmem_free(vdb, sizeof (smb_vdb_t));
(void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_flush.c b/usr/src/uts/common/fs/smbsrv/smb_flush.c
index 0792f592e2..5f86e42dee 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_flush.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_flush.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -84,8 +84,7 @@ smb_com_flush(smb_request_t *sr)
}
if (sr->smb_fid != 0xffff) {
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
- sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERRbadfid);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
index d27b423832..161b4b8e73 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
@@ -1075,7 +1075,7 @@ smb_fsop_rename(
if (from_snode == NULL) {
rc = ENOMEM;
} else {
- (void) smb_node_rename(from_dir_snode, from_snode,
+ smb_node_rename(from_dir_snode, from_snode,
to_dir_snode, to_name);
smb_node_release(from_snode);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_init.c b/usr/src/uts/common/fs/smbsrv/smb_init.c
index 94abdbd4f0..2dce286ede 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c
@@ -59,11 +59,17 @@ static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
* environment. When in doubt use 37KB.
*/
int smb_maxbufsize = SMB_NT_MAXBUF;
-clock_t smb_oplock_timeout = OPLOCK_STD_TIMEOUT;
+int smb_oplock_timeout = OPLOCK_STD_TIMEOUT;
int smb_flush_required = 1;
int smb_dirsymlink_enable = 1;
int smb_announce_quota = 0;
int smb_sign_debug = 0;
+uint_t smb_audit_flags =
+#ifdef DEBUG
+ SMB_AUDIT_NODE;
+#else
+ 0;
+#endif
/*
* *****************************************************************************
diff --git a/usr/src/uts/common/fs/smbsrv/smb_lock.c b/usr/src/uts/common/fs/smbsrv/smb_lock.c
index 034be2c0eb..7c63572aa6 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_lock.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "@(#)smb_lock.c 1.10 08/08/04 SMI"
-
/*
* This module provides range lock functionality for CIFS/SMB clients.
* Lock range service functions process SMB lock and and unlock
@@ -279,9 +277,7 @@ smb_node_destroy_lock_by_ofile(smb_node_t *node, smb_ofile_t *file)
smb_lock_t *nxtl;
list_t destroy_list;
- ASSERT(node);
- ASSERT(node->n_magic == SMB_NODE_MAGIC);
- ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
+ SMB_NODE_VALID(node);
ASSERT(node->n_refcnt);
/*
@@ -352,9 +348,7 @@ smb_range_check(smb_request_t *sr, smb_node_t *node, uint64_t start,
int nbl_op;
int rc;
- ASSERT(node);
- ASSERT(node->n_magic == SMB_NODE_MAGIC);
- ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
+ SMB_NODE_VALID(node);
ASSERT(smb_node_in_crit(node));
diff --git a/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c b/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
index 35edce4965..bf74578aba 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock_byte_range.c
@@ -19,12 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* SMB: lock_byte_range
*
@@ -86,7 +83,7 @@ smb_com_lock_byte_range(struct smb_request *sr)
if (smbsr_decode_vwv(sr, "wll", &sr->smb_fid, &count, &off) != 0)
return (SDRC_ERROR);
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERRbadfid);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c
index c4ea950a91..dd765c0979 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c
@@ -19,12 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* SMB: locking_andx
*
@@ -248,7 +245,7 @@ smb_com_locking_andx(smb_request_t *sr)
if (rc != 0)
return (SDRC_ERROR);
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -262,8 +259,7 @@ smb_com_locking_andx(smb_request_t *sr)
pid = sr->smb_pid; /* Save the original pid */
if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) {
- smb_oplock_release(sr->fid_ofile->f_node, B_FALSE);
-
+ smb_oplock_release(sr->fid_ofile->f_node, sr->fid_ofile);
/*
* According to the protocol:
*
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
index a6075186af..e91bcc11b9 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
@@ -23,9 +23,8 @@
* Use is subject to license terms.
*/
-#pragma ident "@(#)smb_mangle_name.c 1.3 08/08/07 SMI"
-
#include <sys/types.h>
+#include <sys/param.h>
#include <sys/sunddi.h>
#include <sys/errno.h>
#include <smbsrv/string.h>
@@ -35,9 +34,35 @@
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
+#define SMB_NAME83_BASELEN 8
+#define SMB_NAME83_LEN 12
+
+/*
+ * Characters we don't allow in DOS file names.
+ * If a filename contains any of these chars, it should get mangled.
+ *
+ * '.' is also an invalid DOS char but since it's a special
+ * case it doesn't appear in the list.
+ */
+static char *invalid_dos_chars =
+ "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
+ "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+ " \"/\\:|<>*?";
+
+/*
+ * According to MSKB article #142982, Windows deletes invalid chars and
+ * spaces from file name in mangling process; and invalid chars include:
+ * ."/\[]:;=,
+ *
+ * But some of these chars and some other chars (e.g. +) are replaced
+ * with underscore (_). They are introduced here as special chars.
+ */
+static char *special_chars = "[];=,+";
+
+#define isinvalid(c) (strchr(invalid_dos_chars, c) || (c & 0x80))
+
static int smb_match_unknown(char *name, char *pattern);
-static int smb_is_reserved_dos_name(char *name);
-static int smb_match_reserved(char *name, char *rsrv);
+static boolean_t smb_is_reserved_dos_name(const char *name);
/*
* smb_match_name
@@ -156,123 +181,82 @@ smb_match_unknown(char *name, char *pattern)
}
/*
- * smb_match_reserved
+ * Return true if name contains characters that are invalid in a file
+ * name or it is a reserved DOS device name. Otherwise, returns false.
*
- * Checks if the given name matches given
- * DOS reserved name prefix.
- *
- * Returns 1 if match, 0 otherwise
+ * Control characters (values 0 - 31) and the following characters are
+ * invalid:
+ * < > : " / \ | ? *
*/
-static int
-smb_match_reserved(char *name, char *rsrv)
+boolean_t
+smb_is_invalid_filename(const char *name)
{
- char ch;
+ const char *p;
- int len = strlen(rsrv);
- return (!utf8_strncasecmp(rsrv, name, len) &&
- ((ch = *(name + len)) == 0 || ch == '.'));
+ if ((p = strpbrk(name, invalid_dos_chars)) != NULL) {
+ if (*p != ' ')
+ return (B_TRUE);
+ }
+
+ return (smb_is_reserved_dos_name(name));
}
/*
* smb_is_reserved_dos_name
*
- * This function checks if the name is a reserved dos name.
- *
- * The function returns 1 when the name is a reserved dos name;
- * otherwise, it returns 0.
+ * This function checks if the name is a reserved DOS device name.
+ * The device name should not be followed immediately by an extension,
+ * for example, NUL.txt.
*/
-static int
-smb_is_reserved_dos_name(char *name)
+static boolean_t
+smb_is_reserved_dos_name(const char *name)
{
+ static char *cnames[] = { "CLOCK$", "COM1", "COM2", "COM3", "COM4",
+ "COM5", "COM6", "COM7", "COM8", "COM9", "CON" };
+ static char *lnames[] = { "LPT1", "LPT2", "LPT3", "LPT4", "LPT5",
+ "LPT6", "LPT7", "LPT8", "LPT9" };
+ static char *others[] = { "AUX", "NUL", "PRN" };
+ char **reserved;
char ch;
+ int n_reserved;
+ int len;
+ int i;
- /*
- * Eliminate all names reserved by DOS and Windows.
- */
ch = mts_toupper(*name);
switch (ch) {
case 'A':
- if (smb_match_reserved(name, "AUX"))
- return (1);
+ case 'N':
+ case 'P':
+ reserved = others;
+ n_reserved = sizeof (others) / sizeof (others[0]);
break;
-
case 'C':
- if (smb_match_reserved(name, "CLOCK$") ||
- smb_match_reserved(name, "COM1") ||
- smb_match_reserved(name, "COM2") ||
- smb_match_reserved(name, "COM3") ||
- smb_match_reserved(name, "COM4") ||
- smb_match_reserved(name, "CON")) {
- return (1);
- }
-
+ reserved = cnames;
+ n_reserved = sizeof (cnames) / sizeof (cnames[0]);
break;
-
case 'L':
- if ((utf8_strncasecmp("LPT1", name, 4) == 0) ||
- (utf8_strncasecmp("LPT2", name, 4) == 0) ||
- (utf8_strncasecmp("LPT3", name, 4) == 0))
- return (1);
- break;
-
- case 'N':
- if (smb_match_reserved(name, "NUL"))
- return (1);
+ reserved = lnames;
+ n_reserved = sizeof (lnames) / sizeof (lnames[0]);
break;
-
- case 'P':
- if (smb_match_reserved(name, "PRN"))
- return (1);
+ default:
+ return (B_FALSE);
}
- /*
- * If the server is configured to support Catia Version 5
- * deployments, any filename that contains backslash will
- * have already been translated to the UTF-8 encoding of
- * Latin Small Letter Y with Diaeresis. Thus, the check
- * for backslash in the filename is not necessary.
- */
-#ifdef CATIA_SUPPORT
- /* XXX Catia support */
- if ((get_caps() & NFCAPS_CATIA) == 0) {
- while (*name != 0) {
- if (*name == '\\')
- return (1);
- name++;
+ for (i = 0; i < n_reserved; ++i) {
+ len = strlen(reserved[i]);
+
+ if (utf8_strncasecmp(reserved[i], name, len) == 0) {
+ ch = *(name + len);
+ if ((ch == '\0') || (ch == '.'))
+ return (B_TRUE);
}
}
-#endif /* CATIA_SUPPORT */
- return (0);
+ return (B_FALSE);
}
/*
- * Characters we don't allow in DOS file names.
- * If a filename contains any of these chars, it should
- * get mangled.
- *
- * '.' is also an invalid DOS char but since it's a special
- * case it doesn't appear in the list.
- */
-static char *invalid_dos_chars =
- "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
- "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
- " \"/\\:|<>*?";
-
-/*
- * According to MSKB article #142982, Windows deletes invalid chars and
- * spaces from file name in mangling process; and invalid chars include:
- * ."/\[]:;=,
- *
- * But some of these chars and some other chars (e.g. +) are replaced
- * with underscore (_). They are introduced here as special chars.
- */
-static char *special_chars = "[];=,+";
-
-#define isinvalid(c) (strchr(invalid_dos_chars, c) || (c & 0x80))
-
-/*
* smb_needs_mangle
*
* Determines whether the given name needs to get mangled.
@@ -479,28 +463,38 @@ smb_generate_mangle(ino64_t fileid, unsigned char *mangle_buf)
/*
* smb_maybe_mangled_name
*
- * returns true if the passed name can possibly be a mangled name.
- * mangled names should be valid dos file names hence less than 12 characters
- * long and should contain at least one tilde character.
+ * Mangled names should be valid DOS file names: less than 12 characters
+ * long, contain at least one tilde character and conform to an 8.3 name
+ * format.
*
- * note that this function can be further enhanced to check for invalid
- * dos characters/character patterns (such as "file..1.c") but this version
- * should be sufficient in most cases.
+ * Returns true if the name looks like a mangled name.
*/
int
smb_maybe_mangled_name(char *name)
{
- int i, has_tilde = 0;
+ const char *p;
+ boolean_t has_tilde = B_FALSE;
+ int ndots = 0;
+ int i;
+
+ for (p = name, i = 0; (*p != '\0') && (i < SMB_NAME83_LEN); i++, p++) {
+ if ((strchr(special_chars, *p) != NULL) ||
+ (strchr(invalid_dos_chars, *p) != NULL))
+ return (B_FALSE);
+
+ if (*p == '.') {
+ if ((++ndots) > 1)
+ return (B_FALSE);
+ }
- for (i = 0; *name && (i < 12); i++, name++) {
- if ((*name == '~') && (i < 8))
- has_tilde = 1;
+ if ((*p == '~') && (i < SMB_NAME83_BASELEN))
+ has_tilde = B_TRUE;
- if (*name == '.' && has_tilde == 0)
- return (0);
+ if (*p == '.' && !has_tilde)
+ return (B_FALSE);
}
- return ((*name == 0) && has_tilde);
+ return ((*p == 0) && has_tilde);
}
/*
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
index 7a361bb0cc..7e0ee57629 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
@@ -19,11 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
/*
* SMB mbuf marshaling encode/decode.
*/
@@ -147,6 +146,7 @@ smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
uint8_t cval;
uint8_t *cvalp;
uint8_t **cvalpp;
+ uint16_t wval;
uint16_t *wvalp;
uint32_t *lvalp;
uint64_t *llvalp;
@@ -240,29 +240,29 @@ smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
case 'B':
vdp = va_arg(ap, struct vardata_block *);
- vdp->tag = 0;
-
- /*LINTED E_ASSIGN_NARROW_CONV (BYTE)*/
- vdp->len = repc;
- vdp->uio.uio_iov = &vdp->iovec[0];
- vdp->uio.uio_iovcnt = MAX_IOVEC;
- vdp->uio.uio_resid = repc;
- if (mbc_marshal_get_uio(mbc, &vdp->uio) != 0)
+ vdp->vdb_tag = 0;
+ vdp->vdb_len = repc;
+ vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
+ vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
+ vdp->vdb_uio.uio_resid = repc;
+ if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0)
return (-1);
break;
case 'D':
case 'V':
vdp = va_arg(ap, struct vardata_block *);
- if (mbc_marshal_get_char(mbc, &vdp->tag) != 0)
+ if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0)
return (-1);
- if (mbc_marshal_get_short(mbc, &vdp->len) != 0)
+ if (mbc_marshal_get_short(mbc, &wval) != 0)
return (-1);
- vdp->uio.uio_iov = &vdp->iovec[0];
- vdp->uio.uio_iovcnt = MAX_IOVEC;
- vdp->uio.uio_resid = vdp->len;
- if (vdp->len != 0) {
- if (mbc_marshal_get_uio(mbc, &vdp->uio) != 0)
+ vdp->vdb_len = (uint32_t)wval;
+ vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
+ vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
+ vdp->vdb_uio.uio_resid = vdp->vdb_len;
+ if (vdp->vdb_len != 0) {
+ if (mbc_marshal_get_uio(mbc,
+ &vdp->vdb_uio) != 0)
return (-1);
}
break;
@@ -540,9 +540,9 @@ smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
if (mbc_marshal_put_char(mbc, 1) != 0)
return (DECODE_NO_MORE_DATA);
- if (mbc_marshal_put_short(mbc, vdp->len) != 0)
+ if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
return (DECODE_NO_MORE_DATA);
- if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0)
+ if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
return (DECODE_NO_MORE_DATA);
break;
@@ -564,9 +564,9 @@ smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
if (mbc_marshal_put_char(mbc, 5) != 0)
return (DECODE_NO_MORE_DATA);
- if (mbc_marshal_put_short(mbc, vdp->len) != 0)
+ if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
return (DECODE_NO_MORE_DATA);
- if (mbc_marshal_put_uio(mbc, &vdp->uio) != 0)
+ if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
return (DECODE_NO_MORE_DATA);
break;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c
index db2698645f..8dcba3b111 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -59,6 +59,60 @@
#include <smbsrv/smb_incl.h>
#include <smbsrv/mbuf.h>
+#include <smbsrv/smb_kstat.h>
+
+static kmem_cache_t *smb_mbc_cache = NULL;
+
+int
+smb_mbc_init(void)
+{
+ if (smb_mbc_cache == NULL) {
+ smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE,
+ sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
+ }
+ return (0);
+}
+
+void
+smb_mbc_fini(void)
+{
+ if (smb_mbc_cache != NULL) {
+ kmem_cache_destroy(smb_mbc_cache);
+ smb_mbc_cache = NULL;
+ }
+}
+
+mbuf_chain_t *
+smb_mbc_alloc(uint32_t max_bytes)
+{
+ mbuf_chain_t *mbc;
+ mbuf_t *m;
+
+ mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP);
+ bzero(mbc, sizeof (*mbc));
+ mbc->mbc_magic = SMB_MBC_MAGIC;
+
+ if (max_bytes != 0) {
+ MGET(m, M_WAIT, MT_DATA);
+ m->m_len = 0;
+ mbc->chain = m;
+ if (max_bytes > MINCLSIZE)
+ MCLGET(m, M_WAIT);
+ }
+ mbc->max_bytes = max_bytes;
+ return (mbc);
+}
+
+void
+smb_mbc_free(mbuf_chain_t *mbc)
+{
+ SMB_MBC_VALID(mbc);
+
+ m_freem(mbc->chain);
+ mbc->chain = NULL;
+ mbc->mbc_magic = 0;
+ kmem_cache_free(smb_mbc_cache, mbc);
+}
/*
* smb_mbuf_get
diff --git a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
index 01fee7371e..fd82d1bfd0 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c
@@ -23,8 +23,6 @@
* Use is subject to license terms.
*/
-#pragma ident "@(#)smb_negotiate.c 1.6 08/07/21 SMI"
-
/*
* Notes on the virtual circuit (VC) values in the SMB Negotiate
* response and SessionSetupAndx request.
@@ -358,7 +356,12 @@ smb_com_negotiate(smb_request_t *sr)
(void) ksocket_setsockopt(sr->session->sock, SOL_SOCKET,
SO_RCVBUF, (const void *)&smb_nt_tcp_rcvbuf,
sizeof (smb_nt_tcp_rcvbuf), CRED());
+ /*
+ * UNICODE support is required for long share names,
+ * long file names and streams.
+ */
capabilities = CAP_LARGE_FILES
+ | CAP_UNICODE
| CAP_NT_SMBS
| CAP_STATUS32
| CAP_NT_FIND
@@ -366,15 +369,8 @@ smb_com_negotiate(smb_request_t *sr)
| CAP_LEVEL_II_OPLOCKS
| CAP_LOCK_AND_READ
| CAP_RPC_REMOTE_APIS
- | CAP_LARGE_READX;
-
- /*
- * UNICODE support is required to enable support for long
- * share names and long file names and streams.
- */
-
- capabilities |= CAP_UNICODE;
-
+ | CAP_LARGE_READX
+ | CAP_LARGE_WRITEX;
/*
* Turn off Extended Security Negotiation
diff --git a/usr/src/uts/common/fs/smbsrv/smb_node.c b/usr/src/uts/common/fs/smbsrv/smb_node.c
index 41808ad392..484bdecfbd 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c
@@ -22,9 +22,6 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "@(#)smb_node.c 1.9 08/08/07 SMI"
-
/*
* SMB Node State Machine
* ----------------------
@@ -82,18 +79,29 @@
*/
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_kstat.h>
#include <sys/pathname.h>
#include <sys/sdt.h>
#include <sys/nbmlock.h>
-uint32_t smb_is_executable(char *path);
-static void smb_node_delete_on_close(smb_node_t *node);
+uint32_t smb_is_executable(char *);
+static void smb_node_delete_on_close(smb_node_t *);
+static void smb_node_create_audit_buf(smb_node_t *, int);
+static void smb_node_destroy_audit_buf(smb_node_t *);
+static void smb_node_audit(smb_node_t *);
+static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_attr_t *,
+ smb_llist_t *bucket, uint32_t hashkey);
+static void smb_node_free(smb_node_t *);
+static int smb_node_constructor(void *, void *, int);
+static void smb_node_destructor(void *, void *);
+static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
#define VALIDATE_DIR_NODE(_dir_, _node_) \
ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
ASSERT((_dir_)->dir_snode != (_node_));
+static kmem_cache_t *smb_node_cache = NULL;
static boolean_t smb_node_initialized = B_FALSE;
static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1];
@@ -112,6 +120,9 @@ smb_node_init(void)
if (smb_node_initialized)
return (0);
+ smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE,
+ sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor,
+ NULL, NULL, NULL, 0);
for (i = 0; i <= SMBND_HASH_MASK; i++) {
smb_llist_constructor(&smb_node_hash_table[i],
@@ -160,6 +171,8 @@ smb_node_fini(void)
for (i = 0; i <= SMBND_HASH_MASK; i++) {
smb_llist_destructor(&smb_node_hash_table[i]);
}
+ kmem_cache_destroy(smb_node_cache);
+ smb_node_cache = NULL;
smb_node_initialized = B_FALSE;
}
@@ -237,9 +250,7 @@ smb_node_lookup(
fsid = vp->v_vfsp->vfs_fsid;
}
- hashkey = fsid.val[0] + attr->sa_vattr.va_nodeid;
- hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
- node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)];
+ node_hdr = smb_node_get_hash(&fsid, attr, &hashkey);
lock_mode = RW_READER;
smb_llist_enter(node_hdr, lock_mode);
@@ -249,10 +260,12 @@ smb_node_lookup(
ASSERT(node->n_magic == SMB_NODE_MAGIC);
ASSERT(node->n_hash_bucket == node_hdr);
if ((node->n_hashkey == hashkey) && (node->vp == vp)) {
- smb_rwx_xenter(&node->n_lock);
+ mutex_enter(&node->n_mutex);
DTRACE_PROBE1(smb_node_lookup_hit,
smb_node_t *, node);
switch (node->n_state) {
+ case SMB_NODE_STATE_OPLOCK_GRANTED:
+ case SMB_NODE_STATE_OPLOCK_BREAKING:
case SMB_NODE_STATE_AVAILABLE:
/* The node was found. */
node->n_refcnt++;
@@ -268,8 +281,8 @@ smb_node_lookup(
node->attr = *attr;
node->n_size = attr->sa_vattr.va_size;
- smb_audit_node(node);
- smb_rwx_xexit(&node->n_lock);
+ smb_node_audit(node);
+ mutex_exit(&node->n_mutex);
smb_llist_exit(node_hdr);
return (node);
@@ -279,7 +292,7 @@ smb_node_lookup(
* to be destroyed. We act as it hasn't
* been found.
*/
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
break;
default:
/*
@@ -288,7 +301,7 @@ smb_node_lookup(
* been found.
*/
ASSERT(0);
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
break;
}
}
@@ -300,34 +313,9 @@ smb_node_lookup(
}
break;
}
- node = kmem_cache_alloc(sr->sr_server->si_cache_node, KM_SLEEP);
- bzero(node, sizeof (smb_node_t));
-
- node->n_state = SMB_NODE_STATE_AVAILABLE;
- node->n_hash_bucket = node_hdr;
- node->n_sr = sr;
- node->vp = vp;
- VN_HOLD(node->vp);
- node->n_hashkey = hashkey;
- node->n_refcnt = 1;
- node->attr = *attr;
- node->flags |= NODE_FLAGS_ATTR_VALID;
- node->n_size = node->attr.sa_vattr.va_size;
- node->n_orig_session_id = sr->session->s_kid;
+ node = smb_node_alloc(od_name, vp, attr, node_hdr, hashkey);
node->n_orig_uid = crgetuid(sr->user_cr);
- node->n_cache = sr->sr_server->si_cache_node;
-
- ASSERT(od_name);
- (void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
- smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
- offsetof(smb_ofile_t, f_nnd));
- smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
- offsetof(smb_lock_t, l_lnd));
-
-
- if (strcmp(od_name, XATTR_DIR) == 0)
- node->flags |= NODE_XATTR_DIR;
if (op)
node->flags |= smb_is_executable(op->fqi.last_comp);
@@ -344,13 +332,9 @@ smb_node_lookup(
node->unnamed_stream_node = unnamed_node;
}
- smb_rwx_init(&node->n_lock);
- node->n_magic = SMB_NODE_MAGIC;
- smb_audit_buf_node_create(node);
DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
- smb_audit_node(node);
+ smb_node_audit(node);
smb_llist_insert_head(node_hdr, node);
-
smb_llist_exit(node_hdr);
return (node);
}
@@ -364,7 +348,7 @@ smb_node_lookup(
*/
smb_node_t *
-smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode,
+smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr)
{
smb_node_t *xattrdir_node;
@@ -398,20 +382,25 @@ smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode,
* Care also needs to be taken with respect to racing deallocations of a
* structure.
*/
-
void
smb_node_ref(smb_node_t *node)
{
- ASSERT(node);
- ASSERT(node->n_magic == SMB_NODE_MAGIC);
- ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
-
- smb_rwx_xenter(&node->n_lock);
- node->n_refcnt++;
- ASSERT(node->n_refcnt);
- DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
- smb_audit_node(node);
- smb_rwx_xexit(&node->n_lock);
+ SMB_NODE_VALID(node);
+
+ mutex_enter(&node->n_mutex);
+ switch (node->n_state) {
+ case SMB_NODE_STATE_AVAILABLE:
+ case SMB_NODE_STATE_OPLOCK_GRANTED:
+ case SMB_NODE_STATE_OPLOCK_BREAKING:
+ node->n_refcnt++;
+ ASSERT(node->n_refcnt);
+ DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node);
+ smb_node_audit(node);
+ break;
+ default:
+ SMB_PANIC();
+ }
+ mutex_exit(&node->n_mutex);
}
/*
@@ -438,10 +427,9 @@ smb_node_ref(smb_node_t *node)
void
smb_node_release(smb_node_t *node)
{
- ASSERT(node);
- ASSERT(node->n_magic == SMB_NODE_MAGIC);
+ SMB_NODE_VALID(node);
- smb_rwx_xenter(&node->n_lock);
+ mutex_enter(&node->n_mutex);
ASSERT(node->n_refcnt);
DTRACE_PROBE1(smb_node_release, smb_node_t *, node);
if (--node->n_refcnt == 0) {
@@ -449,7 +437,7 @@ smb_node_release(smb_node_t *node)
case SMB_NODE_STATE_AVAILABLE:
node->n_state = SMB_NODE_STATE_DESTROYING;
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
smb_llist_enter(node->n_hash_bucket, RW_WRITER);
smb_llist_remove(node->n_hash_bucket, node);
@@ -459,11 +447,6 @@ smb_node_release(smb_node_t *node)
* Check if the file was deleted
*/
smb_node_delete_on_close(node);
- node->n_magic = (uint32_t)~SMB_NODE_MAGIC;
-
- /* These lists should be empty. */
- smb_llist_destructor(&node->n_ofile_list);
- smb_llist_destructor(&node->n_lock_list);
if (node->dir_snode) {
ASSERT(node->dir_snode->n_magic ==
@@ -477,21 +460,15 @@ smb_node_release(smb_node_t *node)
smb_node_release(node->unnamed_stream_node);
}
- ASSERT(node->vp);
- VN_RELE(node->vp);
-
- smb_audit_buf_node_destroy(node);
- smb_rwx_destroy(&node->n_lock);
- kmem_cache_free(node->n_cache, node);
+ smb_node_free(node);
return;
default:
- ASSERT(0);
- break;
+ SMB_PANIC();
}
}
- smb_audit_node(node);
- smb_rwx_xexit(&node->n_lock);
+ smb_node_audit(node);
+ mutex_exit(&node->n_mutex);
}
static void
@@ -523,39 +500,37 @@ smb_node_delete_on_close(smb_node_t *node)
* smb_node_rename()
*
*/
-int
+void
smb_node_rename(
- smb_node_t *from_dir_snode,
- smb_node_t *ret_snode,
- smb_node_t *to_dir_snode,
+ smb_node_t *from_dnode,
+ smb_node_t *ret_node,
+ smb_node_t *to_dnode,
char *to_name)
{
- ASSERT(from_dir_snode);
- ASSERT(to_dir_snode);
- ASSERT(ret_snode);
- ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC);
- ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC);
- ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC);
- ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
- ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE);
- ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE);
-
- smb_node_ref(to_dir_snode);
- smb_rwx_xenter(&ret_snode->n_lock);
- ret_snode->dir_snode = to_dir_snode;
- smb_rwx_xexit(&ret_snode->n_lock);
- ASSERT(to_dir_snode->dir_snode != ret_snode);
- ASSERT((to_dir_snode->vp->v_xattrdir) ||
- (to_dir_snode->vp->v_type == VDIR));
- smb_node_release(from_dir_snode);
-
- (void) strcpy(ret_snode->od_name, to_name);
-
- /*
- * XXX Need to update attributes?
- */
-
- return (0);
+ SMB_NODE_VALID(from_dnode);
+ SMB_NODE_VALID(to_dnode);
+ SMB_NODE_VALID(ret_node);
+
+ smb_node_ref(to_dnode);
+ mutex_enter(&ret_node->n_mutex);
+ switch (ret_node->n_state) {
+ case SMB_NODE_STATE_AVAILABLE:
+ case SMB_NODE_STATE_OPLOCK_GRANTED:
+ case SMB_NODE_STATE_OPLOCK_BREAKING:
+ ret_node->dir_snode = to_dnode;
+ mutex_exit(&ret_node->n_mutex);
+ ASSERT(to_dnode->dir_snode != ret_node);
+ ASSERT((to_dnode->vp->v_xattrdir) ||
+ (to_dnode->vp->v_type == VDIR));
+ smb_node_release(from_dnode);
+ (void) strcpy(ret_node->od_name, to_name);
+ /*
+ * XXX Need to update attributes?
+ */
+ break;
+ default:
+ SMB_PANIC();
+ }
}
int
@@ -567,12 +542,6 @@ smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
smb_llist_t *node_hdr;
smb_node_t *node;
- /*
- * Take an explicit hold on rootdir. This goes with the
- * corresponding release in smb_node_root_fini()/smb_node_release().
- */
- VN_HOLD(vp);
-
va.sa_mask = SMB_AT_ALL;
error = smb_vop_getattr(vp, NULL, &va, 0, kcred);
if (error) {
@@ -580,42 +549,16 @@ smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
return (error);
}
- hashkey = vp->v_vfsp->vfs_fsid.val[0] + va.sa_vattr.va_nodeid;
- hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
- node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)];
-
- node = kmem_cache_alloc(sv->si_cache_node, KM_SLEEP);
- bzero(node, sizeof (smb_node_t));
-
- node->n_state = SMB_NODE_STATE_AVAILABLE;
- node->n_hash_bucket = node_hdr;
- node->vp = vp;
- node->n_hashkey = hashkey;
- node->n_refcnt = 1;
- node->attr = va;
- node->flags |= NODE_FLAGS_ATTR_VALID;
- node->n_size = node->attr.sa_vattr.va_size;
- node->n_cache = sv->si_cache_node;
- (void) strlcpy(node->od_name, ROOTVOL, sizeof (node->od_name));
+ node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey);
- smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
- offsetof(smb_ofile_t, f_nnd));
- smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
- offsetof(smb_lock_t, l_lnd));
-
- smb_rwx_init(&node->n_lock);
- node->n_magic = SMB_NODE_MAGIC;
- smb_audit_buf_node_create(node);
+ node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey);
sv->si_root_smb_node = node;
-
- smb_audit_node(node);
+ smb_node_audit(node);
smb_llist_enter(node_hdr, RW_WRITER);
smb_llist_insert_head(node_hdr, node);
smb_llist_exit(node_hdr);
-
*root = node;
-
return (0);
}
@@ -630,12 +573,12 @@ smb_node_get_size(smb_node_t *node, smb_attr_t *attr)
if (attr->sa_vattr.va_type == VDIR)
return (0);
- smb_rwx_xenter(&node->n_lock);
+ mutex_enter(&node->n_mutex);
if (node && (node->flags & NODE_FLAGS_SET_SIZE))
size = node->n_size;
else
size = attr->sa_vattr.va_size;
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
return (size);
}
@@ -662,9 +605,13 @@ timeval_cmp(timestruc_t *a, timestruc_t *b)
* will be updated when client close the file.
*/
void
-smb_node_set_time(struct smb_node *node, struct timestruc *crtime,
- struct timestruc *mtime, struct timestruc *atime,
- struct timestruc *ctime, unsigned int what)
+smb_node_set_time(
+ smb_node_t *node,
+ timestruc_t *crtime,
+ timestruc_t *mtime,
+ timestruc_t *atime,
+ timestruc_t *ctime,
+ uint_t what)
{
if (what == 0)
return;
@@ -675,7 +622,7 @@ smb_node_set_time(struct smb_node *node, struct timestruc *crtime,
(what & SMB_AT_CTIME && ctime == 0))
return;
- smb_rwx_xenter(&node->n_lock);
+ mutex_enter(&node->n_mutex);
if ((what & SMB_AT_CRTIME) &&
timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
@@ -731,7 +678,7 @@ smb_node_set_time(struct smb_node *node, struct timestruc *crtime,
} else {
gethrestime(&node->attr.sa_vattr.va_ctime);
}
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
}
@@ -773,12 +720,12 @@ smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr)
FILE_ATTRIBUTE_READONLY |
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
- smb_rwx_xenter(&node->n_lock);
+ mutex_enter(&node->n_mutex);
if (node->attr.sa_dosattr != mode) {
node->attr.sa_dosattr = mode;
node->what |= SMB_AT_DOSATTR;
}
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
}
/*
@@ -812,7 +759,7 @@ smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr)
{
int rc = -1;
- smb_rwx_xenter(&node->n_lock);
+ mutex_enter(&node->n_mutex);
if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
!(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
crhold(cr);
@@ -820,20 +767,20 @@ smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr)
node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
rc = 0;
}
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
return (rc);
}
void
smb_node_reset_delete_on_close(smb_node_t *node)
{
- smb_rwx_xenter(&node->n_lock);
+ mutex_enter(&node->n_mutex);
if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
crfree(node->delete_on_close_cred);
node->delete_on_close_cred = NULL;
}
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
}
/*
@@ -846,15 +793,16 @@ smb_node_reset_delete_on_close(smb_node_t *node)
* sharing conflict, otherwise returns NT_STATUS_SUCCESS.
*/
uint32_t
-smb_node_open_check(struct smb_node *node, cred_t *cr,
- uint32_t desired_access, uint32_t share_access)
+smb_node_open_check(
+ smb_node_t *node,
+ cred_t *cr,
+ uint32_t desired_access,
+ uint32_t share_access)
{
smb_ofile_t *of;
uint32_t status;
- ASSERT(node);
- ASSERT(node->n_magic == SMB_NODE_MAGIC);
- ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
+ SMB_NODE_VALID(node);
smb_llist_enter(&node->n_ofile_list, RW_READER);
of = smb_llist_head(&node->n_ofile_list);
@@ -879,19 +827,16 @@ smb_node_open_check(struct smb_node *node, cred_t *cr,
}
uint32_t
-smb_node_rename_check(struct smb_node *node)
+smb_node_rename_check(smb_node_t *node)
{
- struct smb_ofile *of;
- uint32_t status;
+ smb_ofile_t *of;
+ uint32_t status;
- ASSERT(node);
- ASSERT(node->n_magic == SMB_NODE_MAGIC);
- ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
+ SMB_NODE_VALID(node);
/*
* Intra-CIFS check
*/
-
smb_llist_enter(&node->n_ofile_list, RW_READER);
of = smb_llist_head(&node->n_ofile_list);
while (of) {
@@ -913,7 +858,6 @@ smb_node_rename_check(struct smb_node *node)
/*
* system-wide share check
*/
-
if (nbl_share_conflict(node->vp, NBL_RENAME, NULL))
return (NT_STATUS_SHARING_VIOLATION);
else
@@ -923,12 +867,10 @@ smb_node_rename_check(struct smb_node *node)
uint32_t
smb_node_delete_check(smb_node_t *node)
{
- smb_ofile_t *of;
- uint32_t status;
+ smb_ofile_t *of;
+ uint32_t status;
- ASSERT(node);
- ASSERT(node->n_magic == SMB_NODE_MAGIC);
- ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE);
+ SMB_NODE_VALID(node);
if (node->attr.sa_vattr.va_type == VDIR)
return (NT_STATUS_SUCCESS);
@@ -936,7 +878,6 @@ smb_node_delete_check(smb_node_t *node)
/*
* intra-CIFS check
*/
-
smb_llist_enter(&node->n_ofile_list, RW_READER);
of = smb_llist_head(&node->n_ofile_list);
while (of) {
@@ -958,7 +899,6 @@ smb_node_delete_check(smb_node_t *node)
/*
* system-wide share check
*/
-
if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL))
return (NT_STATUS_SHARING_VIOLATION);
else
@@ -975,7 +915,7 @@ smb_node_delete_check(smb_node_t *node)
void
smb_node_start_crit(smb_node_t *node, krw_t mode)
{
- rw_enter(&node->n_share_lock, mode);
+ rw_enter(&node->n_lock, mode);
nbl_start_crit(node->vp, mode);
}
@@ -989,11 +929,260 @@ void
smb_node_end_crit(smb_node_t *node)
{
nbl_end_crit(node->vp);
- rw_exit(&node->n_share_lock);
+ rw_exit(&node->n_lock);
}
int
smb_node_in_crit(smb_node_t *node)
{
- return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock));
+ return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock));
+}
+
+void
+smb_node_rdlock(smb_node_t *node)
+{
+ rw_enter(&node->n_lock, RW_READER);
+}
+
+void
+smb_node_wrlock(smb_node_t *node)
+{
+ rw_enter(&node->n_lock, RW_WRITER);
+}
+
+void
+smb_node_unlock(smb_node_t *node)
+{
+ rw_exit(&node->n_lock);
+}
+
+uint32_t
+smb_node_get_ofile_count(smb_node_t *node)
+{
+ uint32_t cntr;
+
+ SMB_NODE_VALID(node);
+
+ smb_llist_enter(&node->n_ofile_list, RW_READER);
+ cntr = smb_llist_get_count(&node->n_ofile_list);
+ smb_llist_exit(&node->n_ofile_list);
+ return (cntr);
+}
+
+void
+smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of)
+{
+ SMB_NODE_VALID(node);
+
+ smb_llist_enter(&node->n_ofile_list, RW_WRITER);
+ smb_llist_insert_tail(&node->n_ofile_list, of);
+ smb_llist_exit(&node->n_ofile_list);
+}
+
+void
+smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of)
+{
+ SMB_NODE_VALID(node);
+
+ smb_llist_enter(&node->n_ofile_list, RW_WRITER);
+ smb_llist_remove(&node->n_ofile_list, of);
+ smb_llist_exit(&node->n_ofile_list);
+}
+
+void
+smb_node_inc_open_ofiles(smb_node_t *node)
+{
+ SMB_NODE_VALID(node);
+
+ mutex_enter(&node->n_mutex);
+ node->n_open_count++;
+ mutex_exit(&node->n_mutex);
+}
+
+void
+smb_node_dec_open_ofiles(smb_node_t *node)
+{
+ SMB_NODE_VALID(node);
+
+ mutex_enter(&node->n_mutex);
+ node->n_open_count--;
+ mutex_exit(&node->n_mutex);
+}
+
+uint32_t
+smb_node_get_open_ofiles(smb_node_t *node)
+{
+ uint32_t cnt;
+
+ SMB_NODE_VALID(node);
+
+ mutex_enter(&node->n_mutex);
+ cnt = node->n_open_count;
+ mutex_exit(&node->n_mutex);
+ return (cnt);
+}
+
+/*
+ * smb_node_alloc
+ */
+static smb_node_t *
+smb_node_alloc(
+ char *od_name,
+ vnode_t *vp,
+ smb_attr_t *attr,
+ smb_llist_t *bucket,
+ uint32_t hashkey)
+{
+ smb_node_t *node;
+
+ node = kmem_cache_alloc(smb_node_cache, KM_SLEEP);
+
+ if (node->n_audit_buf != NULL)
+ node->n_audit_buf->anb_index = 0;
+
+ node->attr = *attr;
+ node->flags = NODE_FLAGS_ATTR_VALID;
+ node->n_size = node->attr.sa_vattr.va_size;
+ VN_HOLD(vp);
+ node->vp = vp;
+ node->n_refcnt = 1;
+ node->n_hash_bucket = bucket;
+ node->n_hashkey = hashkey;
+ node->n_orig_uid = 0;
+ node->readonly_creator = NULL;
+ node->waiting_event = 0;
+ node->what = 0;
+ node->n_open_count = 0;
+ node->dir_snode = NULL;
+ node->unnamed_stream_node = NULL;
+ node->delete_on_close_cred = NULL;
+
+ (void) strlcpy(node->od_name, od_name, sizeof (node->od_name));
+ if (strcmp(od_name, XATTR_DIR) == 0)
+ node->flags |= NODE_XATTR_DIR;
+
+ node->n_state = SMB_NODE_STATE_AVAILABLE;
+ node->n_magic = SMB_NODE_MAGIC;
+ return (node);
+}
+
+/*
+ * smb_node_free
+ */
+static void
+smb_node_free(smb_node_t *node)
+{
+ SMB_NODE_VALID(node);
+
+ node->n_magic = 0;
+ VERIFY(!list_link_active(&node->n_lnd));
+ VERIFY(node->n_lock_list.ll_count == 0);
+ VERIFY(node->n_ofile_list.ll_count == 0);
+ VERIFY(node->n_oplock.ol_xthread == NULL);
+ VERIFY(node->n_oplock.ol_waiters_count == 0);
+ VN_RELE(node->vp);
+ kmem_cache_free(smb_node_cache, node);
+}
+
+/*
+ * smb_node_constructor
+ */
+static int
+smb_node_constructor(void *buf, void *un, int kmflags)
+{
+ _NOTE(ARGUNUSED(kmflags, un))
+
+ smb_node_t *node = (smb_node_t *)buf;
+
+ bzero(node, sizeof (smb_node_t));
+
+ smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t),
+ offsetof(smb_ofile_t, f_nnd));
+ smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t),
+ offsetof(smb_lock_t, l_lnd));
+ cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL);
+ rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL);
+ mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL);
+ smb_node_create_audit_buf(node, kmflags);
+ return (0);
+}
+
+/*
+ * smb_node_destructor
+ */
+static void
+smb_node_destructor(void *buf, void *un)
+{
+ _NOTE(ARGUNUSED(un))
+
+ smb_node_t *node = (smb_node_t *)buf;
+
+ smb_node_destroy_audit_buf(node);
+ mutex_destroy(&node->n_mutex);
+ rw_destroy(&node->n_lock);
+ cv_destroy(&node->n_oplock.ol_cv);
+ smb_llist_destructor(&node->n_lock_list);
+ smb_llist_destructor(&node->n_ofile_list);
+}
+
+/*
+ * smb_node_create_audit_buf
+ */
+static void
+smb_node_create_audit_buf(smb_node_t *node, int kmflags)
+{
+ smb_audit_buf_node_t *abn;
+
+ if (smb_audit_flags & SMB_AUDIT_NODE) {
+ abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags);
+ abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
+ node->n_audit_buf = abn;
+ }
+}
+
+/*
+ * smb_node_destroy_audit_buf
+ */
+static void
+smb_node_destroy_audit_buf(smb_node_t *node)
+{
+ if (node->n_audit_buf != NULL) {
+ kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t));
+ node->n_audit_buf = NULL;
+ }
+}
+
+/*
+ * smb_node_audit
+ *
+ * This function saves the calling stack in the audit buffer of the node passed
+ * in.
+ */
+static void
+smb_node_audit(smb_node_t *node)
+{
+ smb_audit_buf_node_t *abn;
+ smb_audit_record_node_t *anr;
+
+ if (node->n_audit_buf) {
+ abn = node->n_audit_buf;
+ anr = abn->anb_records;
+ anr += abn->anb_index;
+ abn->anb_index++;
+ abn->anb_index &= abn->anb_max_index;
+ anr->anr_refcnt = node->n_refcnt;
+ anr->anr_depth = getpcstack(anr->anr_stack,
+ SMB_AUDIT_STACK_DEPTH);
+ }
+}
+
+static smb_llist_t *
+smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey)
+{
+ uint32_t hashkey;
+
+ hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid;
+ hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8);
+ *phashkey = hashkey;
+ return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
index 6e7f50c404..1506a68905 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -170,7 +170,6 @@ smb_pre_nt_create_andx(smb_request_t *sr)
{
struct open_param *op = &sr->arg.open;
uint8_t SecurityFlags;
- uint32_t Flags;
uint32_t ImpersonationLevel;
uint16_t NameLength;
int rc;
@@ -179,7 +178,7 @@ smb_pre_nt_create_andx(smb_request_t *sr)
rc = smbsr_decode_vwv(sr, "5.wlllqlllllb",
&NameLength,
- &Flags,
+ &op->nt_flags,
&op->rootdirfid,
&op->desired_access,
&op->dsize,
@@ -203,17 +202,12 @@ smb_pre_nt_create_andx(smb_request_t *sr)
}
}
- if (Flags) {
- if (Flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
- if (Flags & NT_CREATE_FLAG_REQUEST_OPBATCH) {
- op->my_flags = MYF_BATCH_OPLOCK;
- } else {
- op->my_flags = MYF_EXCLUSIVE_OPLOCK;
- }
- }
-
- if (Flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)
- op->my_flags |= MYF_MUST_BE_DIRECTORY;
+ op->op_oplock_level = SMB_OPLOCK_NONE;
+ if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
+ if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPBATCH)
+ op->op_oplock_level = SMB_OPLOCK_BATCH;
+ else
+ op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
}
DTRACE_SMB_2(op__NtCreateX__start, smb_request_t *, sr,
@@ -240,7 +234,14 @@ smb_com_nt_create_andx(struct smb_request *sr)
if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
!(op->desired_access & DELETE)) {
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERRbadaccess);
+ return (SDRC_ERROR);
+ }
+
+ if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERRbadaccess);
return (SDRC_ERROR);
}
@@ -260,8 +261,7 @@ smb_com_nt_create_andx(struct smb_request *sr)
op->fqi.dir_snode = sr->tid_tree->t_snode;
} else {
sr->smb_fid = (ushort_t)op->rootdirfid;
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
- sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERRbadfid);
@@ -276,17 +276,17 @@ smb_com_nt_create_andx(struct smb_request *sr)
return (SDRC_ERROR);
if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- switch (MYF_OPLOCK_TYPE(op->my_flags)) {
- case MYF_EXCLUSIVE_OPLOCK :
+ switch (op->op_oplock_level) {
+ case SMB_OPLOCK_EXCLUSIVE:
OplockLevel = 1;
break;
- case MYF_BATCH_OPLOCK :
+ case SMB_OPLOCK_BATCH:
OplockLevel = 2;
break;
- case MYF_LEVEL_II_OPLOCK :
+ case SMB_OPLOCK_LEVEL_II:
OplockLevel = 3;
break;
- case MYF_OPLOCK_NONE :
+ case SMB_OPLOCK_NONE:
default:
OplockLevel = 0;
break;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
index c0e8100fb1..94c693a1ad 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -60,7 +60,6 @@ smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
struct open_param *op = &sr->arg.open;
uint8_t SecurityFlags;
uint32_t EaLength;
- uint32_t Flags;
uint32_t ImpersonationLevel;
uint32_t NameLength;
uint32_t sd_len;
@@ -72,7 +71,7 @@ smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
rc = smb_mbc_decodef(&xa->req_param_mb, "%lllqllllllllb",
sr,
- &Flags,
+ &op->nt_flags,
&op->rootdirfid,
&op->desired_access,
&op->dsize,
@@ -99,16 +98,12 @@ smb_pre_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
}
}
- if (Flags) {
- if (Flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
- if (Flags & NT_CREATE_FLAG_REQUEST_OPBATCH)
- op->my_flags = MYF_BATCH_OPLOCK;
- else
- op->my_flags = MYF_EXCLUSIVE_OPLOCK;
- }
-
- if (Flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)
- op->my_flags |= MYF_MUST_BE_DIRECTORY;
+ op->op_oplock_level = SMB_OPLOCK_NONE;
+ if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) {
+ if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPBATCH)
+ op->op_oplock_level = SMB_OPLOCK_BATCH;
+ else
+ op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
}
if (sd_len) {
@@ -155,7 +150,14 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
!(op->desired_access & DELETE)) {
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERRbadaccess);
+ return (SDRC_ERROR);
+ }
+
+ if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERRbadaccess);
return (SDRC_ERROR);
}
@@ -175,8 +177,7 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
op->fqi.dir_snode = sr->tid_tree->t_snode;
} else {
sr->smb_fid = (ushort_t)op->rootdirfid;
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
- sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
ERRDOS, ERRbadfid);
@@ -193,17 +194,17 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
return (SDRC_ERROR);
if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- switch (MYF_OPLOCK_TYPE(op->my_flags)) {
- case MYF_EXCLUSIVE_OPLOCK :
+ switch (op->op_oplock_level) {
+ case SMB_OPLOCK_EXCLUSIVE:
OplockLevel = 1;
break;
- case MYF_BATCH_OPLOCK :
+ case SMB_OPLOCK_BATCH:
OplockLevel = 2;
break;
- case MYF_LEVEL_II_OPLOCK :
+ case SMB_OPLOCK_LEVEL_II:
OplockLevel = 3;
break;
- case MYF_OPLOCK_NONE :
+ case SMB_OPLOCK_NONE:
default:
OplockLevel = 0;
break;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
index 447eceedd1..839748bbd3 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
@@ -195,7 +195,7 @@ smb_nt_transact_notify_change(struct smb_request *sr, struct smb_xa *xa)
&CompletionFilter, &sr->smb_fid, &WatchTree) != 0)
return (SDRC_NOT_IMPLEMENTED);
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
index 1ea9dd57aa..4d4abf86f4 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -79,7 +79,7 @@ smb_nt_transact_query_security_info(struct smb_request *sr, struct smb_xa *xa)
return (SDRC_ERROR);
}
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -171,7 +171,7 @@ smb_nt_transact_set_security_info(struct smb_request *sr, struct smb_xa *xa)
return (SDRC_ERROR);
}
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_odir.c b/usr/src/uts/common/fs/smbsrv/smb_odir.c
index d1adfd614b..571c1efde2 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_odir.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c
@@ -973,7 +973,7 @@ smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od,
/* check search attributes */
dosattr = smb_node_get_dosattr(fnode);
- if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) {
+ if (!smb_sattr_check(dosattr, od->d_sattr)) {
smb_node_release(fnode);
return (ENOENT);
}
@@ -1063,7 +1063,7 @@ smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od,
/* check search attributes */
dosattr = smb_node_get_dosattr(fnode);
- if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) {
+ if (!smb_sattr_check(dosattr, od->d_sattr)) {
smb_node_release(fnode);
return (ENOENT);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
index 7f12c2acbf..de3ec1837b 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -220,6 +220,10 @@ smb_ofile_open(
} else {
ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */
ASSERT(node);
+
+ if (of->f_granted_access == FILE_EXECUTE)
+ of->f_flags |= SMB_OFLAGS_EXECONLY;
+
if (crgetuid(of->f_cr) == node->attr.sa_vattr.va_uid) {
/*
* Add this bit for the file's owner even if it's not
@@ -251,9 +255,8 @@ smb_ofile_open(
if (op->created_readonly)
node->readonly_creator = of;
- smb_llist_enter(&node->n_ofile_list, RW_WRITER);
- smb_llist_insert_tail(&node->n_ofile_list, of);
- smb_llist_exit(&node->n_ofile_list);
+ smb_node_add_ofile(node, of);
+ smb_node_inc_open_ofiles(node);
}
smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
smb_llist_insert_tail(&tree->t_ofile_list, of);
@@ -292,7 +295,6 @@ smb_ofile_close(
* For files created readonly, propagate the readonly
* bit to the ofile now
*/
-
if (of->f_node->readonly_creator == of) {
of->f_node->attr.sa_dosattr |=
FILE_ATTRIBUTE_READONLY;
@@ -303,7 +305,6 @@ smb_ofile_close(
smb_ofile_close_timestamp_update(of, last_wtime);
(void) smb_sync_fsattr(NULL, of->f_cr, of->f_node);
smb_commit_delete_on_close(of);
- smb_oplock_release(of->f_node, B_FALSE);
smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid);
smb_node_destroy_lock_by_ofile(of->f_node, of);
@@ -324,6 +325,11 @@ smb_ofile_close(
ASSERT(of->f_refcnt);
ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
of->f_state = SMB_OFILE_STATE_CLOSED;
+ if (of->f_oplock_granted) {
+ smb_node_dec_open_ofiles(of->f_node);
+ smb_oplock_release(of->f_node, of);
+ of->f_oplock_granted = B_FALSE;
+ }
mutex_exit(&of->f_mutex);
return;
}
@@ -403,6 +409,9 @@ smb_ofile_release(
ASSERT(of->f_magic == SMB_OFILE_MAGIC);
mutex_enter(&of->f_mutex);
+ if (of->f_oplock_exit)
+ if (smb_oplock_exit(of->f_node))
+ of->f_oplock_exit = B_FALSE;
ASSERT(of->f_refcnt);
of->f_refcnt--;
switch (of->f_state) {
@@ -599,13 +608,11 @@ smb_ofile_close_timestamp_update(
*
*/
boolean_t
-smb_ofile_is_open(
- smb_ofile_t *of)
+smb_ofile_is_open(smb_ofile_t *of)
{
boolean_t rc = B_FALSE;
- ASSERT(of);
- ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ SMB_OFILE_VALID(of);
mutex_enter(&of->f_mutex);
if (of->f_state == SMB_OFILE_STATE_OPEN) {
@@ -615,6 +622,17 @@ smb_ofile_is_open(
return (rc);
}
+void
+smb_ofile_set_oplock_granted(smb_ofile_t *of)
+{
+ SMB_OFILE_VALID(of);
+ mutex_enter(&of->f_mutex);
+ ASSERT(!of->f_oplock_granted);
+ of->f_oplock_granted = B_TRUE;
+ of->f_oplock_exit = B_TRUE;
+ mutex_exit(&of->f_mutex);
+}
+
/* *************************** Static Functions ***************************** */
/*
@@ -697,9 +715,7 @@ smb_ofile_delete(
} else {
ASSERT(of->f_ftype == SMB_FTYPE_DISK);
ASSERT(of->f_node != NULL);
- smb_llist_enter(&of->f_node->n_ofile_list, RW_WRITER);
- smb_llist_remove(&of->f_node->n_ofile_list, of);
- smb_llist_exit(&of->f_node->n_ofile_list);
+ smb_node_rem_ofile(of->f_node, of);
smb_node_release(of->f_node);
}
@@ -763,7 +779,7 @@ smb_ofile_open_check(
mutex_enter(&of->f_mutex);
- if (of->f_state != SMB_OFILE_STATE_OPEN) {
+ if (of->f_state != SMB_OFILE_STATE_OPEN) {
mutex_exit(&of->f_mutex);
return (NT_STATUS_INVALID_HANDLE);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
index 74a1d27830..8b8d7802a0 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
@@ -19,19 +19,16 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_incl.h>
-/*
- * This module provides the common open functionality to the various
- * open and create SMB interface functions.
- */
+int smb_open_dsize_check = 0;
/*
- *
* Client Request Description
* ================================== =================================
*
@@ -122,11 +119,7 @@
* SMB_COM_IOCTL
*/
-#include <smbsrv/smb_incl.h>
-
/*
- * SMB: open
- *
* This message is sent to obtain a file handle for a data file. This
* returned Fid is used in subsequent client requests such as read, write,
* close, etc.
@@ -255,15 +248,6 @@ smb_com_open(smb_request_t *sr)
op->desired_access = smb_omode_to_amask(op->omode);
op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
-
- if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
- (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
- ERRDOS, ERROR_INVALID_PARAMETER);
- return (SDRC_ERROR);
- }
-
- op->dsize = 0; /* Don't set spurious size */
op->crtime.tv_sec = op->crtime.tv_nsec = 0;
op->create_disposition = FILE_OPEN;
op->create_options = FILE_NON_DIRECTORY_FILE;
@@ -271,23 +255,24 @@ smb_com_open(smb_request_t *sr)
op->create_options |= FILE_WRITE_THROUGH;
if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
- if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY) {
- op->my_flags = MYF_BATCH_OPLOCK;
- } else {
- op->my_flags = MYF_EXCLUSIVE_OPLOCK;
- }
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY)
+ op->op_oplock_level = SMB_OPLOCK_BATCH;
+ else
+ op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
+ } else {
+ op->op_oplock_level = SMB_OPLOCK_NONE;
}
if (smb_common_open(sr) != NT_STATUS_SUCCESS)
return (SDRC_ERROR);
- if (MYF_OPLOCK_TYPE(op->my_flags) == MYF_OPLOCK_NONE) {
+ if (op->op_oplock_level == SMB_OPLOCK_NONE) {
sr->smb_flg &=
~(SMB_FLAGS_OPLOCK | SMB_FLAGS_OPLOCK_NOTIFY_ANY);
}
- if (op->dsize > UINT_MAX) {
- smbsr_error(sr, 0, ERRDOS, ERRbadfunc);
+ if (smb_open_dsize_check && op->dsize > UINT_MAX) {
+ smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
return (SDRC_ERROR);
}
@@ -300,7 +285,7 @@ smb_com_open(smb_request_t *sr)
file_attr,
smb_gmt2local(sr, node->attr.sa_vattr.va_mtime.tv_sec),
(uint32_t)op->dsize,
- op->omode & SMB_DA_ACCESS_MASK,
+ op->omode,
(uint16_t)0); /* bcc */
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
@@ -318,14 +303,13 @@ smb_pre_open_andx(smb_request_t *sr)
uint16_t flags;
uint32_t creation_time;
uint16_t file_attr, sattr;
- uint16_t ofun;
int rc;
bzero(op, sizeof (sr->arg.open));
rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com,
&sr->andx_off, &flags, &op->omode, &sattr,
- &file_attr, &creation_time, &ofun, &op->dsize, &op->timeo);
+ &file_attr, &creation_time, &op->ofun, &op->dsize, &op->timeo);
if (rc == 0) {
rc = smbsr_decode_data(sr, "%u", sr, &op->fqi.path);
@@ -333,15 +317,17 @@ smb_pre_open_andx(smb_request_t *sr)
op->dattr = file_attr;
if (flags & 2)
- op->my_flags = MYF_EXCLUSIVE_OPLOCK;
+ op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
else if (flags & 4)
- op->my_flags = MYF_BATCH_OPLOCK;
+ op->op_oplock_level = SMB_OPLOCK_BATCH;
+ else
+ op->op_oplock_level = SMB_OPLOCK_NONE;
if ((creation_time != 0) && (creation_time != UINT_MAX))
op->crtime.tv_sec = smb_local2gmt(sr, creation_time);
op->crtime.tv_nsec = 0;
- op->create_disposition = smb_ofun_to_crdisposition(ofun);
+ op->create_disposition = smb_ofun_to_crdisposition(op->ofun);
}
DTRACE_SMB_2(op__OpenX__start, smb_request_t *, sr,
@@ -361,21 +347,13 @@ smb_com_open_andx(smb_request_t *sr)
{
struct open_param *op = &sr->arg.open;
uint16_t file_attr;
- uint16_t granted_access;
int rc;
op->desired_access = smb_omode_to_amask(op->omode);
op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
- if ((op->desired_access == ((uint32_t)SMB_INVALID_AMASK)) ||
- (op->share_access == ((uint32_t)SMB_INVALID_SHAREMODE))) {
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
- ERRDOS, ERROR_INVALID_PARAMETER);
- return (SDRC_ERROR);
- }
-
- if (op->create_disposition == ((uint32_t)SMB_INVALID_CRDISPOSITION)) {
- smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_PARAMETER);
+ if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
+ smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
return (SDRC_ERROR);
}
@@ -386,19 +364,15 @@ smb_com_open_andx(smb_request_t *sr)
if (smb_common_open(sr) != NT_STATUS_SUCCESS)
return (SDRC_ERROR);
- if (op->dsize > UINT_MAX) {
- smbsr_error(sr, 0, ERRDOS, ERRbadfunc);
+ if (smb_open_dsize_check && op->dsize > UINT_MAX) {
+ smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
return (SDRC_ERROR);
}
- if (MYF_OPLOCK_TYPE(op->my_flags) != MYF_OPLOCK_NONE) {
+ if (op->op_oplock_level != SMB_OPLOCK_NONE)
op->action_taken |= SMB_OACT_LOCK;
- } else {
+ else
op->action_taken &= ~SMB_OACT_LOCK;
- }
-
- granted_access = (SMB_TREE_IS_READONLY(sr))
- ? SMB_DA_ACCESS_READ : op->omode & SMB_DA_ACCESS_MASK;
file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
@@ -411,7 +385,7 @@ smb_com_open_andx(smb_request_t *sr)
file_attr,
smb_gmt2local(sr, node->attr.sa_vattr.va_mtime.tv_sec),
(uint32_t)op->dsize,
- granted_access, op->ftype,
+ op->omode, op->ftype,
op->devstate,
op->action_taken, op->fileid,
0);
@@ -424,7 +398,7 @@ smb_com_open_andx(smb_request_t *sr)
file_attr,
0L,
0L,
- granted_access, op->ftype,
+ op->omode, op->ftype,
op->devstate,
op->action_taken, op->fileid,
0);
@@ -432,3 +406,77 @@ smb_com_open_andx(smb_request_t *sr)
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
+
+smb_sdrc_t
+smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa)
+{
+ struct open_param *op = &sr->arg.open;
+ uint32_t creation_time;
+ uint32_t alloc_size;
+ uint16_t flags;
+ uint16_t file_attr;
+ int rc;
+
+ bzero(op, sizeof (sr->arg.open));
+
+ rc = smb_mbc_decodef(&xa->req_param_mb, "%wwwwlwl10.u",
+ sr, &flags, &op->omode, &op->fqi.srch_attr, &file_attr,
+ &creation_time, &op->ofun, &alloc_size, &op->fqi.path);
+ if (rc != 0)
+ return (SDRC_ERROR);
+
+ if ((creation_time != 0) && (creation_time != UINT_MAX))
+ op->crtime.tv_sec = smb_local2gmt(sr, creation_time);
+ op->crtime.tv_nsec = 0;
+
+ op->dattr = file_attr;
+ op->dsize = alloc_size;
+ op->create_options = FILE_NON_DIRECTORY_FILE;
+
+ op->desired_access = smb_omode_to_amask(op->omode);
+ op->share_access = smb_denymode_to_sharemode(op->omode, op->fqi.path);
+
+ op->create_disposition = smb_ofun_to_crdisposition(op->ofun);
+ if (op->create_disposition > FILE_MAXIMUM_DISPOSITION)
+ op->create_disposition = FILE_CREATE;
+
+ if (op->omode & SMB_DA_WRITE_THROUGH)
+ op->create_options |= FILE_WRITE_THROUGH;
+
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
+ if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY)
+ op->op_oplock_level = SMB_OPLOCK_BATCH;
+ else
+ op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
+ } else {
+ op->op_oplock_level = SMB_OPLOCK_NONE;
+ }
+
+ if (smb_common_open(sr) != NT_STATUS_SUCCESS)
+ return (SDRC_ERROR);
+
+ if (op->op_oplock_level != SMB_OPLOCK_NONE)
+ op->action_taken |= SMB_OACT_LOCK;
+ else
+ op->action_taken &= ~SMB_OACT_LOCK;
+
+ file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type))
+ op->dsize = 0;
+
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "wwllwwwwlwl",
+ sr->smb_fid,
+ file_attr,
+ (uint32_t)0, /* creation time */
+ (uint32_t)op->dsize,
+ op->omode,
+ op->ftype,
+ op->devstate,
+ op->action_taken,
+ op->fileid,
+ (uint16_t)0, /* EA error offset */
+ (uint32_t)0); /* EA list length */
+
+ return (SDRC_SUCCESS);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_oplock.c b/usr/src/uts/common/fs/smbsrv/smb_oplock.c
index 3d5efdfb43..9044ee880c 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c
@@ -22,9 +22,6 @@
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "@(#)smb_oplock.c 1.5 08/08/07 SMI"
-
/*
* SMB Locking library functions.
*/
@@ -33,9 +30,7 @@
#include <smbsrv/smb_fsops.h>
#include <inet/tcp.h>
-/*
- * Oplock functionality enable/disable
- */
+static void smb_oplock_enter(smb_node_t *);
/*
* Magic 0xFF 'S' 'M' 'B'
@@ -118,7 +113,8 @@
* smb_oplock_acquire
*
* Attempt to acquire an oplock. Note that the oplock granted may be
- * none, i.e. the oplock was not granted.
+ * none, i.e. the oplock was not granted. The result of the acquisition is
+ * provided in ol->ol_level.
*
* Grant an oplock to the requestor if this session is the only one
* that has the file open, regardless of the number of instances of
@@ -132,100 +128,99 @@
* depending on what action is taken by the other client (unlock or close),
* an oplock may or may not be granted. (The breaking of an oplock is
* done earlier in the calling path.)
- *
- * XXX: Node synchronization is not yet implemented. However, racing
- * opens are handled thus:
- *
- * A racing oplock acquire can happen in the open path between
- * smb_oplock_break() and smb_fsop_open(), but no later. (Once
- * the file is open via smb_fsop_open()/VOP_OPEN,
- * smb_fsop_oplock_install() will not be able to install an oplock,
- * which requires an open count of 1.)
- *
- * Hence, we can safely break any oplock that came in after the
- * smb_oplock_break() done previously in the open path, knowing that
- * no other racing oplock acquisitions should be able to succeed
- * because we already have the file open (see above).
- *
- * The type of oplock being requested is passed in op->my_flags. The result
- * is also returned in op->my_flags.
- *
- * (Note that exclusive and batch oplocks are treated interchangeably.)
- *
- * The Returns NT status codes:
- * NT_STATUS_SUCCESS
- * NT_STATUS_CONNECTION_DISCONNECTED
*/
-DWORD
-smb_oplock_acquire(
- smb_request_t *sr,
- smb_ofile_t *of,
- struct open_param *op)
+void
+smb_oplock_acquire(smb_node_t *node, smb_ofile_t *of, open_param_t *op)
{
- smb_node_t *node;
- unsigned int level;
+ smb_session_t *session;
+ smb_oplock_t *ol;
+ clock_t time;
- ASSERT(sr);
- ASSERT(of);
- ASSERT(op);
- ASSERT(op->fqi.last_attr.sa_vattr.va_type == VREG);
+ SMB_NODE_VALID(node);
+ SMB_OFILE_VALID(of);
- level = op->my_flags & MYF_OPLOCK_MASK;
+ ASSERT(node == SMB_OFILE_GET_NODE(of));
- op->my_flags &= ~MYF_OPLOCK_MASK;
+ session = SMB_OFILE_GET_SESSION(of);
- if ((sr->sr_cfg->skc_oplock_enable == 0) ||
- smb_tree_has_feature(of->f_tree, SMB_TREE_NO_OPLOCKS))
- return (NT_STATUS_SUCCESS);
+ if (!smb_session_oplocks_enable(session) ||
+ smb_tree_has_feature(SMB_OFILE_GET_TREE(of), SMB_TREE_NO_OPLOCKS)) {
+ /* This implies that trees cannot overlap. */
+ op->op_oplock_level = SMB_OPLOCK_NONE;
+ return;
+ }
- if (!((MYF_IS_EXCLUSIVE_OPLOCK(level)) ||
- (MYF_IS_BATCH_OPLOCK(level))))
- return (NT_STATUS_SUCCESS);
+ ol = &node->n_oplock;
+ time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt();
- node = of->f_node;
+ mutex_enter(&node->n_mutex);
- smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+ for (;;) {
+ int rc;
- if (EXCLUSIVE_OPLOCK_IN_FORCE(node) ||
- BATCH_OPLOCK_IN_FORCE(node)) {
+ smb_oplock_enter(node);
- smb_rwx_rwexit(&node->n_lock);
+ if (node->n_state == SMB_NODE_STATE_AVAILABLE) {
+ if ((op->op_oplock_level == SMB_OPLOCK_LEVEL_II) ||
+ (op->op_oplock_level == SMB_OPLOCK_NONE) ||
+ (node->n_open_count > 1)) {
+ mutex_exit(&node->n_mutex);
+ op->op_oplock_level = SMB_OPLOCK_NONE;
+ return;
+ }
+ ol->ol_ofile = of;
+ ol->ol_sess_id = SMB_SESSION_GET_ID(session);
+ ol->ol_level = op->op_oplock_level;
+ ol->ol_xthread = curthread;
+ node->n_state = SMB_NODE_STATE_OPLOCK_GRANTED;
+ mutex_exit(&node->n_mutex);
+ if (smb_fsop_oplock_install(node, of->f_mode) == 0) {
+ smb_ofile_set_oplock_granted(of);
+ return;
+ }
+ mutex_enter(&node->n_mutex);
+ ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED);
+ node->n_state = SMB_NODE_STATE_AVAILABLE;
+ ol->ol_xthread = NULL;
+ op->op_oplock_level = SMB_OPLOCK_NONE;
+ if (ol->ol_waiters_count != 0)
+ cv_broadcast(&ol->ol_cv);
+ break;
+ }
- if (SMB_SAME_SESSION(sr->session,
- node->n_oplock.op_ofile->f_session)) {
- op->my_flags |= level;
- return (NT_STATUS_SUCCESS);
- } else if (SMB_ATTR_ONLY_OPEN(op)) {
- ASSERT(!(op->my_flags & MYF_OPLOCK_MASK));
- return (NT_STATUS_SUCCESS);
+ if (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) {
+ if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id)
+ break;
+ node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING;
+ smb_session_oplock_break(
+ SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile);
}
- smb_oplock_break(node);
+ ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING);
- smb_rwx_rwenter(&node->n_lock, RW_WRITER);
- }
+ ol->ol_waiters_count++;
+ rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time);
+ ol->ol_waiters_count--;
- if (smb_fsop_oplock_install(node, of->f_mode) != 0) {
- smb_rwx_rwexit(&node->n_lock);
- return (NT_STATUS_SUCCESS);
+ if (rc == -1) {
+ /*
+ * Oplock release timed out.
+ */
+ if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) {
+ node->n_state = SMB_NODE_STATE_AVAILABLE;
+ ol->ol_xthread = curthread;
+ mutex_exit(&node->n_mutex);
+ smb_fsop_oplock_uninstall(node);
+ smb_session_oplock_break_timedout(
+ SMB_OFILE_GET_SESSION(ol->ol_ofile));
+ mutex_enter(&node->n_mutex);
+ ol->ol_xthread = NULL;
+ if (ol->ol_waiters_count != 0)
+ cv_broadcast(&ol->ol_cv);
+ }
+ }
}
-
- node->n_oplock.op_ofile = of;
- node->n_oplock.op_ipaddr = sr->session->ipaddr;
- node->n_oplock.op_kid = sr->session->s_kid;
- node->flags &= ~NODE_OPLOCKS_IN_FORCE;
-
- if (MYF_IS_EXCLUSIVE_OPLOCK(level))
- node->flags |= NODE_EXCLUSIVE_OPLOCK;
-
- if (MYF_IS_BATCH_OPLOCK(level))
- node->flags |= NODE_BATCH_OPLOCK;
-
- op->my_flags |= level;
-
- smb_rwx_rwexit(&node->n_lock);
-
- return (NT_STATUS_SUCCESS);
+ mutex_exit(&node->n_mutex);
}
/*
@@ -233,207 +228,116 @@ smb_oplock_acquire(
*
* The oplock break may succeed for multiple reasons: file close, oplock
* release, holder connection dropped, requesting client disconnect etc.
- * Whatever the reason, the oplock should be broken when this function
- * returns. The exceptions are when the client making this request gets
- * disconnected or when another client is handling the break and it gets
- * disconnected.
*
- * Returns NT status codes:
- * NT_STATUS_SUCCESS No oplock in force, i.e. the
- * oplock has been broken.
- * NT_STATUS_CONNECTION_DISCONNECTED Requesting client disconnected.
- * NT_STATUS_INTERNAL_ERROR
+ * Returns:
+ *
+ * B_TRUE The oplock is broken.
+ * B_FALSE The oplock is being broken. This is returned if nowait is set
+ * to B_TRUE;
*/
-
-void
-smb_oplock_break(smb_node_t *node)
+boolean_t
+smb_oplock_break(smb_node_t *node, uint64_t sess_id, boolean_t nowait)
{
- smb_session_t *oplock_session;
- smb_ofile_t *oplock_ofile;
- struct mbuf_chain mbc;
- int retries = 0;
- clock_t elapsed_time;
- clock_t max_time;
- boolean_t flag;
-
- smb_rwx_rwenter(&node->n_lock, RW_WRITER);
-
- if (!OPLOCKS_IN_FORCE(node)) {
- smb_rwx_rwexit(&node->n_lock);
- return;
- }
-
- if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
- elapsed_time = 0;
- max_time = MSEC_TO_TICK(smb_oplock_timeout * OPLOCK_RETRIES);
- /*
- * Another client is already attempting to break the oplock.
- * We wait for it to finish. If the caller was trying to
- * acquire an oplock, he should retry in case the client's
- * connection was dropped while trying to break the oplock.
- *
- * If the holder's connection has been dropped, we yield to
- * allow the thread handling the break to detect it and set
- * the flags.
- */
- while ((node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) &&
- (elapsed_time < max_time)) {
- clock_t timeleft;
-
- timeleft = smb_rwx_rwwait(&node->n_lock, max_time);
- if (timeleft == -1) {
- elapsed_time = max_time;
- } else {
- elapsed_time += max_time - timeleft;
- }
- }
- /*
- * If there are no oplocks in force we're done.
- */
- if (!OPLOCKS_IN_FORCE(node)) {
- smb_rwx_rwexit(&node->n_lock);
- return;
- } else {
- /*
- * This is an anomalous condition.
- * Cancel/release the oplock.
- */
- smb_oplock_release(node, B_TRUE);
- smb_rwx_rwexit(&node->n_lock);
- return;
- }
- }
-
- oplock_ofile = node->n_oplock.op_ofile;
- ASSERT(oplock_ofile);
-
- oplock_session = oplock_ofile->f_session;
- ASSERT(oplock_session);
-
- /*
- * Start oplock break.
- */
-
- node->n_oplock.op_flags |= OPLOCK_FLAG_BREAKING;
-
- smb_rwx_rwexit(&node->n_lock);
-
- max_time = MSEC_TO_TICK(smb_oplock_timeout);
- do {
- MBC_INIT(&mbc, MLEN);
- (void) smb_mbc_encodef(&mbc, "Mb19.wwwwbb3.ww10.",
- SMB_COM_LOCKING_ANDX, oplock_ofile->f_tree->t_tid,
- 0xffff, 0, 0xffff, 8, 0xff, oplock_ofile->f_fid,
- LOCKING_ANDX_OPLOCK_RELEASE);
-
- flag = B_TRUE;
- smb_rwx_rwenter(&oplock_session->s_lock, RW_WRITER);
- while (flag) {
- switch (oplock_session->s_state) {
- case SMB_SESSION_STATE_DISCONNECTED:
- case SMB_SESSION_STATE_TERMINATED:
- smb_rwx_rwexit(&oplock_session->s_lock);
- smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+ smb_oplock_t *ol;
+ clock_t time;
- node->flags &= ~NODE_OPLOCKS_IN_FORCE;
- node->n_oplock.op_flags &=
- ~OPLOCK_FLAG_BREAKING;
- node->n_oplock.op_ofile = NULL;
- bzero(&node->n_oplock.op_ipaddr,
- sizeof (node->n_oplock.op_ipaddr));
- node->n_oplock.op_kid = 0;
+ SMB_NODE_VALID(node);
+ ol = &node->n_oplock;
+ time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt();
- smb_rwx_rwexit(&node->n_lock);
+ mutex_enter(&node->n_mutex);
+ if (ol->ol_sess_id == sess_id) {
+ mutex_exit(&node->n_mutex);
+ return (B_TRUE);
+ }
- return;
+ for (;;) {
+ int rc;
- case SMB_SESSION_STATE_OPLOCK_BREAKING:
- flag = B_FALSE;
- break;
+ smb_oplock_enter(node);
- case SMB_SESSION_STATE_NEGOTIATED:
- oplock_session->s_state =
- SMB_SESSION_STATE_OPLOCK_BREAKING;
- flag = B_FALSE;
- break;
-
- default:
- (void) smb_rwx_rwwait(&oplock_session->s_lock,
- -1);
- break;
- }
+ if (node->n_state == SMB_NODE_STATE_AVAILABLE) {
+ mutex_exit(&node->n_mutex);
+ return (B_TRUE);
}
- smb_rwx_rwexit(&oplock_session->s_lock);
- (void) smb_session_send(oplock_session, 0, &mbc);
-
- elapsed_time = 0;
-
- smb_rwx_rwenter(&node->n_lock, RW_WRITER);
- while ((node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) &&
- (elapsed_time < max_time)) {
- clock_t timeleft;
-
- timeleft = smb_rwx_rwwait(&node->n_lock, max_time);
- if (timeleft == -1) {
- elapsed_time = max_time;
- } else {
- elapsed_time += max_time - timeleft;
- }
+ if (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) {
+ node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING;
+ smb_session_oplock_break(
+ SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile);
}
- if (!OPLOCKS_IN_FORCE(node)) {
+ ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING);
+ if (nowait) {
+ mutex_exit(&node->n_mutex);
+ return (B_FALSE);
+ }
+ ol->ol_waiters_count++;
+ rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time);
+ ol->ol_waiters_count--;
+ if (rc == -1) {
/*
- * smb_oplock_release() was called
+ * Oplock release timed out.
*/
- smb_rwx_rwexit(&node->n_lock);
- return;
+ if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) {
+ node->n_state = SMB_NODE_STATE_AVAILABLE;
+ ol->ol_xthread = curthread;
+ mutex_exit(&node->n_mutex);
+ smb_fsop_oplock_uninstall(node);
+ smb_session_oplock_break_timedout(
+ SMB_OFILE_GET_SESSION(ol->ol_ofile));
+ mutex_enter(&node->n_mutex);
+ ol->ol_xthread = NULL;
+ if (ol->ol_waiters_count != 0)
+ cv_broadcast(&ol->ol_cv);
+ break;
+ }
}
- } while (++retries < OPLOCK_RETRIES);
-
- /*
- * Retries exhausted and timed out.
- * Cancel the oplock and continue.
- */
-
- smb_oplock_release(node, B_TRUE);
-
- smb_rwx_rwexit(&node->n_lock);
+ }
+ mutex_exit(&node->n_mutex);
+ return (B_TRUE);
}
/*
* smb_oplock_release
*
- * This function uninstalls the FEM oplock monitors and
- * clears all flags in relation to an oplock on the
- * given node.
- *
- * The function can be called with the node->n_lock held
- * or not held.
+ * This function releases the oplock on the node passed in. If other threads
+ * were waiting for the oplock to be released they are signaled.
*/
-
-void /*ARGSUSED*/
-smb_oplock_release(smb_node_t *node, boolean_t have_rwx)
+void
+smb_oplock_release(smb_node_t *node, smb_ofile_t *of)
{
- if (!have_rwx)
- smb_rwx_rwenter(&node->n_lock, RW_WRITER);
+ smb_oplock_t *ol;
+
+ SMB_NODE_VALID(node);
+ ol = &node->n_oplock;
+
+ mutex_enter(&node->n_mutex);
+ smb_oplock_enter(node);
+ switch (node->n_state) {
+ case SMB_NODE_STATE_AVAILABLE:
+ break;
+
+ case SMB_NODE_STATE_OPLOCK_GRANTED:
+ case SMB_NODE_STATE_OPLOCK_BREAKING:
+ if (ol->ol_ofile == of) {
+ node->n_state = SMB_NODE_STATE_AVAILABLE;
+ ol->ol_xthread = curthread;
+ mutex_exit(&node->n_mutex);
+ smb_fsop_oplock_uninstall(node);
+ smb_session_oplock_released(
+ SMB_OFILE_GET_SESSION(ol->ol_ofile));
+ mutex_enter(&node->n_mutex);
+ ol->ol_xthread = NULL;
+ if (ol->ol_waiters_count != 0)
+ cv_broadcast(&ol->ol_cv);
+ }
+ break;
- if (!OPLOCKS_IN_FORCE(node)) {
- if (!have_rwx)
- smb_rwx_rwexit(&node->n_lock);
- return;
+ default:
+ SMB_PANIC();
}
-
- smb_fsop_oplock_uninstall(node);
-
- node->flags &= ~NODE_OPLOCKS_IN_FORCE;
- node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING;
- node->n_oplock.op_ofile = NULL;
- bzero(&node->n_oplock.op_ipaddr, sizeof (node->n_oplock.op_ipaddr));
- node->n_oplock.op_kid = 0;
-
- if (!have_rwx)
- smb_rwx_rwexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
}
/*
@@ -443,37 +347,97 @@ smb_oplock_release(smb_node_t *node, boolean_t have_rwx)
* Other CIFS functions may call smb_oplock_conflict() with a session
* pointer so as to do the session check.
*/
-
boolean_t
-smb_oplock_conflict(smb_node_t *node, smb_session_t *session,
- struct open_param *op)
+smb_oplock_conflict(smb_node_t *node, smb_session_t *session, open_param_t *op)
{
- smb_session_t *oplock_session;
- smb_ofile_t *oplock_ofile;
+ boolean_t rb;
+
+ SMB_NODE_VALID(node);
+ SMB_SESSION_VALID(session);
+
+ mutex_enter(&node->n_mutex);
+ smb_oplock_enter(node);
+ switch (node->n_state) {
+ case SMB_NODE_STATE_AVAILABLE:
+ rb = B_FALSE;
+ break;
+
+ case SMB_NODE_STATE_OPLOCK_GRANTED:
+ case SMB_NODE_STATE_OPLOCK_BREAKING:
+ if (SMB_SESSION_GET_ID(session) == node->n_oplock.ol_sess_id) {
+ rb = B_FALSE;
+ break;
+ }
- smb_rwx_rwenter(&node->n_lock, RW_READER);
+ if (op != NULL) {
+ if (((op->desired_access & ~(FILE_READ_ATTRIBUTES |
+ FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) &&
+ (op->create_disposition != FILE_SUPERSEDE) &&
+ (op->create_disposition != FILE_OVERWRITE)) {
+ /* Attributs only */
+ rb = B_FALSE;
+ break;
+ }
+ }
+ rb = B_TRUE;
+ break;
- if (!OPLOCKS_IN_FORCE(node)) {
- smb_rwx_rwexit(&node->n_lock);
- return (B_FALSE);
+ default:
+ SMB_PANIC();
}
+ mutex_exit(&node->n_mutex);
+ return (rb);
+}
- oplock_ofile = node->n_oplock.op_ofile;
- ASSERT(oplock_ofile);
-
- oplock_session = oplock_ofile->f_session;
- ASSERT(oplock_session);
-
- if (SMB_SAME_SESSION(session, oplock_session)) {
- smb_rwx_rwexit(&node->n_lock);
- return (B_FALSE);
+/*
+ * smb_oplock_exit
+ *
+ * The the calling thread has the pointer to its context stored in ol_thread
+ * it resets that field. If any other thread is waiting for that field to
+ * turn to NULL it is signaled.
+ *
+ * Returns:
+ * B_TRUE Oplock unlocked
+ * B_FALSE Oplock still locked
+ */
+boolean_t
+smb_oplock_exit(smb_node_t *node)
+{
+ smb_oplock_t *ol;
+ boolean_t rb;
+
+ SMB_NODE_VALID(node);
+ ol = &node->n_oplock;
+ rb = B_FALSE;
+
+ mutex_enter(&node->n_mutex);
+ if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) {
+ ol->ol_xthread = NULL;
+ if (ol->ol_waiters_count != 0)
+ cv_broadcast(&ol->ol_cv);
+ rb = B_TRUE;
}
+ mutex_exit(&node->n_mutex);
+ return (rb);
+}
- if (SMB_ATTR_ONLY_OPEN(op)) {
- smb_rwx_rwexit(&node->n_lock);
- return (B_FALSE);
- }
+/*
+ * smb_oplock_wait
+ *
+ * The mutex of the node must have benn entered before calling this function.
+ * If the field ol_xthread is not NULL and doesn't contain the pointer to the
+ * context of the calling thread, the caller will sleep until that field is
+ * reset (set to NULL).
+ */
+static void
+smb_oplock_enter(smb_node_t *node)
+{
+ smb_oplock_t *ol = &node->n_oplock;
- smb_rwx_rwexit(&node->n_lock);
- return (B_TRUE);
+ if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) {
+ ol->ol_waiters_count++;
+ while (ol->ol_xthread != NULL)
+ cv_wait(&ol->ol_cv, &node->n_mutex);
+ ol->ol_waiters_count--;
+ }
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
index 0b9eb8cba9..9f65ebc4e4 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
@@ -443,10 +443,16 @@ smb_pathname(
if ((err = pn_getcomponent(&upn, component)) != 0)
break;
- if (smb_maybe_mangled_name(component)) {
+ /*
+ * This mangled name handling is in the wrong place.
+ * The name must be looked up prior to any mangled
+ * name checking.
+ *
+ * Temporary: check for ~ to keep smbtorture quiet.
+ */
+ if (*component != '~' && smb_maybe_mangled_name(component)) {
if ((err = smb_unmangle_name(sr, cred, dnode,
- component, real_name, MAXNAMELEN, 0, 0,
- 1)) != 0)
+ component, real_name, MAXNAMELEN, 0, 0, 1)) != 0)
break;
/*
* Do not pass FIGNORECASE to lookuppnvp().
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
index d8f6d131b5..5a793df1ab 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* SMB: query_information2
*
@@ -89,8 +87,7 @@ smb_com_query_information2(smb_request_t *sr)
uint16_t dattr;
int rc;
-
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_read.c b/usr/src/uts/common/fs/smbsrv/smb_read.c
index 374b32d1bf..289d089450 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_read.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_read.c
@@ -19,17 +19,26 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#include <sys/syslog.h>
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_fsops.h>
-int smb_common_read(smb_request_t *, smb_rw_param_t *);
+/*
+ * The maximum number of bytes to return from SMB Core
+ * SmbRead or SmbLockAndRead.
+ */
+#define SMB_CORE_READ_MAX 4432
+
+/*
+ * The limit in bytes for SmbReadX.
+ */
+#define SMB_READX_MAX 0x10000
+int smb_common_read(smb_request_t *, smb_rw_param_t *);
/*
* Read bytes from a file or named pipe (SMB Core).
@@ -51,6 +60,7 @@ smb_pre_read(smb_request_t *sr)
{
smb_rw_param_t *param;
uint32_t off_low;
+ uint16_t count;
uint16_t remcnt;
int rc;
@@ -58,9 +68,10 @@ smb_pre_read(smb_request_t *sr)
sr->arg.rw = param;
rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
- &param->rw_count, &off_low, &remcnt);
+ &count, &off_low, &remcnt);
param->rw_offset = (uint64_t)off_low;
+ param->rw_count = (uint32_t)count;
param->rw_mincnt = 0;
DTRACE_SMB_2(op__Read__start, smb_request_t *, sr,
@@ -82,9 +93,10 @@ smb_sdrc_t
smb_com_read(smb_request_t *sr)
{
smb_rw_param_t *param = sr->arg.rw;
+ uint16_t count;
int rc;
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -92,13 +104,17 @@ smb_com_read(smb_request_t *sr)
sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+ if (param->rw_count > SMB_CORE_READ_MAX)
+ param->rw_count = SMB_CORE_READ_MAX;
+
if ((rc = smb_common_read(sr, param)) != 0) {
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
+ count = (uint16_t)param->rw_count;
rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
- 5, param->rw_count, VAR_BCC, 0x01, param->rw_count, &sr->raw_data);
+ 5, count, VAR_BCC, 0x01, count, &sr->raw_data);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
@@ -129,17 +145,19 @@ smb_sdrc_t
smb_pre_lock_and_read(smb_request_t *sr)
{
smb_rw_param_t *param;
- uint16_t remcnt;
uint32_t off_low;
+ uint16_t count;
+ uint16_t remcnt;
int rc;
param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
sr->arg.rw = param;
rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
- &param->rw_count, &off_low, &remcnt);
+ &count, &off_low, &remcnt);
param->rw_offset = (uint64_t)off_low;
+ param->rw_count = (uint32_t)count;
param->rw_mincnt = 0;
DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr,
@@ -162,6 +180,7 @@ smb_com_lock_and_read(smb_request_t *sr)
{
smb_rw_param_t *param = sr->arg.rw;
DWORD status;
+ uint16_t count;
int rc;
if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
@@ -169,7 +188,7 @@ smb_com_lock_and_read(smb_request_t *sr)
return (SDRC_ERROR);
}
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -178,19 +197,24 @@ smb_com_lock_and_read(smb_request_t *sr)
sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
- UINT_MAX, SMB_LOCK_TYPE_READWRITE);
+ 0, SMB_LOCK_TYPE_READWRITE);
+
if (status != NT_STATUS_SUCCESS) {
smb_lock_range_error(sr, status);
return (SDRC_ERROR);
}
+ if (param->rw_count > SMB_CORE_READ_MAX)
+ param->rw_count = SMB_CORE_READ_MAX;
+
if ((rc = smb_common_read(sr, param)) != 0) {
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
+ count = (uint16_t)param->rw_count;
rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
- 5, param->rw_count, VAR_BCC, 0x1, param->rw_count, &sr->raw_data);
+ 5, count, VAR_BCC, 0x1, count, &sr->raw_data);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
@@ -214,6 +238,7 @@ smb_com_lock_and_read(smb_request_t *sr)
* we send a zero length session packet, which will force the client to
* retry the read.
*
+ * Do not return errors from SmbReadRaw.
* Read errors are handled by sending a zero length response.
*/
smb_sdrc_t
@@ -223,6 +248,7 @@ smb_pre_read_raw(smb_request_t *sr)
uint32_t off_low;
uint32_t off_high;
uint32_t timeout;
+ uint16_t count;
int rc;
param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
@@ -230,25 +256,43 @@ smb_pre_read_raw(smb_request_t *sr)
if (sr->smb_wct == 8) {
rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
- &off_low, &param->rw_count, &param->rw_mincnt,
- &timeout);
- param->rw_offset = (uint64_t)off_low;
+ &off_low, &count, &param->rw_mincnt, &timeout);
+ if (rc == 0) {
+ param->rw_offset = (uint64_t)off_low;
+ param->rw_count = (uint32_t)count;
+ }
} else {
rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
- &off_low, &param->rw_count, &param->rw_mincnt,
- &timeout, &off_high);
- param->rw_offset = ((uint64_t)off_high << 32) | off_low;
+ &off_low, &count, &param->rw_mincnt, &timeout, &off_high);
+ if (rc == 0) {
+ param->rw_offset = ((uint64_t)off_high << 32) | off_low;
+ param->rw_count = (uint32_t)count;
+ }
}
DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr,
smb_rw_param_t *, param);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+ return (SDRC_SUCCESS);
}
void
smb_post_read_raw(smb_request_t *sr)
{
+ mbuf_chain_t *mbc;
+
+ if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) {
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+
+ while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) !=
+ NULL) {
+ SMB_MBC_VALID(mbc);
+ list_remove(&sr->session->s_oplock_brkreqs, mbc);
+ (void) smb_session_send(sr->session, 0, mbc);
+ smb_mbc_free(mbc);
+ }
+ }
+
DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr,
smb_rw_param_t *, sr->arg.rw);
@@ -259,22 +303,24 @@ smb_sdrc_t
smb_com_read_raw(smb_request_t *sr)
{
smb_rw_param_t *param = sr->arg.rw;
- smb_node_t *node;
- int rc;
switch (sr->session->s_state) {
case SMB_SESSION_STATE_NEGOTIATED:
+ sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE;
break;
case SMB_SESSION_STATE_OPLOCK_BREAKING:
(void) smb_session_send(sr->session, 0, NULL);
- sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
return (SDRC_NO_REPLY);
case SMB_SESSION_STATE_TERMINATED:
case SMB_SESSION_STATE_DISCONNECTED:
return (SDRC_NO_REPLY);
+ case SMB_SESSION_STATE_READ_RAW_ACTIVE:
+ sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+ return (SDRC_DROP_VC);
+
case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
case SMB_SESSION_STATE_CONNECTED:
case SMB_SESSION_STATE_ESTABLISHED:
@@ -282,27 +328,21 @@ smb_com_read_raw(smb_request_t *sr)
return (SDRC_DROP_VC);
}
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
+ (void) smb_session_send(sr->session, 0, NULL);
+ return (SDRC_NO_REPLY);
}
sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
- rc = smb_common_read(sr, param);
-
- if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- node = sr->fid_ofile->f_node;
- if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
- rc = EAGAIN;
- }
- }
+ if (param->rw_mincnt > param->rw_count)
+ param->rw_mincnt = 0;
- if (rc != 0) {
+ if (smb_common_read(sr, param) != 0) {
(void) smb_session_send(sr->session, 0, NULL);
m_freem(sr->raw_data.chain);
- sr->raw_data.chain = 0;
+ sr->raw_data.chain = NULL;
} else {
(void) smb_session_send(sr->session, 0, &sr->raw_data);
}
@@ -314,6 +354,12 @@ smb_com_read_raw(smb_request_t *sr)
* Read bytes from a file (SMB Core). This request was extended in
* LM 0.12 to support 64-bit offsets, indicated by sending a wct of
* 12 and including additional offset information.
+ *
+ * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
+ * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
+ * than the negotiated buffer size. If maxcnt_high is 0xFF, it must
+ * be ignored. Otherwise, maxcnt_high represents the upper 16 bits
+ * of rw_count.
*/
smb_sdrc_t
smb_pre_read_andx(smb_request_t *sr)
@@ -321,6 +367,9 @@ smb_pre_read_andx(smb_request_t *sr)
smb_rw_param_t *param;
uint32_t off_low;
uint32_t off_high;
+ uint32_t maxcnt_high;
+ uint16_t maxcnt_low;
+ uint16_t mincnt;
uint16_t remcnt;
int rc;
@@ -328,16 +377,23 @@ smb_pre_read_andx(smb_request_t *sr)
sr->arg.rw = param;
if (sr->smb_wct == 12) {
- rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", &param->rw_andx,
- &sr->smb_fid, &off_low, &param->rw_count, &remcnt,
- &off_high);
+ rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", &param->rw_andx,
+ &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
+ &remcnt, &off_high);
+
+ param->rw_offset = ((uint64_t)off_high << 32) |
+ (uint64_t)off_low;
- param->rw_offset = ((uint64_t)off_high << 32) | off_low;
+ param->rw_count = (uint32_t)maxcnt_low;
+ if (maxcnt_high < 0xFF)
+ param->rw_count |= maxcnt_high << 16;
} else {
- rc = smbsr_decode_vwv(sr, "b3.wlw6.w", &param->rw_andx,
- &sr->smb_fid, &off_low, &param->rw_count, &remcnt);
+ rc = smbsr_decode_vwv(sr, "b3.wlwwlw", &param->rw_andx,
+ &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
+ &remcnt);
param->rw_offset = (uint64_t)off_low;
+ param->rw_count = (uint32_t)maxcnt_low;
}
param->rw_mincnt = 0;
@@ -361,10 +417,13 @@ smb_sdrc_t
smb_com_read_andx(smb_request_t *sr)
{
smb_rw_param_t *param = sr->arg.rw;
+ uint16_t datalen_high;
+ uint16_t datalen_low;
+ uint16_t data_offset;
uint16_t offset2;
int rc;
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -372,41 +431,50 @@ smb_com_read_andx(smb_request_t *sr)
sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+ if (param->rw_count >= SMB_READX_MAX)
+ param->rw_count = 0;
+
if ((rc = smb_common_read(sr, param)) != 0) {
smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
- /*
- * Ensure that the next response offset is zero
- * if there is no secondary command.
- */
- offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
+ datalen_low = param->rw_count & 0xFFFF;
+ datalen_high = (param->rw_count >> 16) & 0xFF;
/*
- * The STYPE_IPC response format is different.
- * The unknown value (2) may be to indicate that it
- * is a follow-up to an earlier RPC transaction.
+ * If this is a secondary command, the data offset
+ * includes the previous wct + sizeof(wct).
*/
+ data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
+
if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
- rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC",
+ data_offset += 60;
+ offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
+
+ rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
12, /* wct */
- param->rw_andx, /* Secondary andx command */
- offset2, /* offset to next */
- 0, /* must be 0 */
- param->rw_count, /* data byte count */
- 60, /* Offset from start to data */
+ param->rw_andx, /* secondary andx command */
+ offset2, /* offset to next command */
+ 0, /* set to 0 for named pipes */
+ datalen_low, /* data byte count */
+ data_offset, /* offset from start to data */
+ datalen_high, /* data byte count */
VAR_BCC, /* BCC marker */
- 0x02, /* unknown */
+ 0x00, /* padding */
&sr->raw_data);
} else {
- rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC",
+ data_offset += 59;
+ offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
+
+ rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
12, /* wct */
- param->rw_andx, /* Secondary andx command */
- offset2, /* offset to next */
- -1, /* must be -1 */
- param->rw_count, /* data byte count */
- 59, /* Offset from start to data */
+ param->rw_andx, /* secondary andx command */
+ offset2, /* offset to next command */
+ -1, /* must be -1 for regular files */
+ datalen_low, /* data byte count */
+ data_offset, /* offset from start to data */
+ datalen_high, /* data byte count */
VAR_BCC, /* BCC marker */
&sr->raw_data);
}
@@ -431,12 +499,12 @@ smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
struct mbuf *top;
int rc;
- vdb->tag = 0;
- vdb->uio.uio_iov = &vdb->iovec[0];
- vdb->uio.uio_iovcnt = MAX_IOVEC;
- vdb->uio.uio_resid = param->rw_count;
- vdb->uio.uio_loffset = (offset_t)param->rw_offset;
- vdb->uio.uio_segflg = UIO_SYSSPACE;
+ vdb->vdb_tag = 0;
+ vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
+ vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
+ vdb->vdb_uio.uio_resid = param->rw_count;
+ vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
+ vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
switch (sr->tid_tree->t_res_type & STYPE_MASK) {
case STYPE_DISKTREE:
@@ -451,21 +519,33 @@ smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
}
}
+ if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
+ !(sr->smb_flg2 & SMB_FLAGS2_PAGING_IO)) {
+ /*
+ * SMB_FLAGS2_PAGING_IO: permit execute-only reads.
+ *
+ * Reject request if the file has been opened
+ * execute-only and SMB_FLAGS2_PAGING_IO is not set.
+ */
+ rc = EACCES;
+ break;
+ }
+
(void) smb_sync_fsattr(sr, sr->user_cr, node);
- sr->raw_data.max_bytes = vdb->uio.uio_resid;
- top = smb_mbuf_allocate(&vdb->uio);
+ sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
+ top = smb_mbuf_allocate(&vdb->vdb_uio);
- rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio,
+ rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio,
&node->attr);
- sr->raw_data.max_bytes -= vdb->uio.uio_resid;
+ sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
smb_mbuf_trim(top, sr->raw_data.max_bytes);
MBC_ATTACH_MBUF(&sr->raw_data, top);
break;
case STYPE_IPC:
- rc = smb_opipe_read(sr, &vdb->uio);
+ rc = smb_opipe_read(sr, &vdb->vdb_uio);
break;
default:
@@ -473,7 +553,7 @@ smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
break;
}
- param->rw_count -= vdb->uio.uio_resid;
+ param->rw_count -= vdb->vdb_uio.uio_resid;
if (rc != 0)
return (rc);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_rename.c b/usr/src/uts/common/fs/smbsrv/smb_rename.c
index f72ad16e1e..42fe8abac6 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_rename.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "@(#)smb_rename.c 1.6 08/08/04 SMI"
-
#include <smbsrv/nterror.h>
#include <sys/synch.h>
#include <smbsrv/smb_incl.h>
@@ -182,8 +180,8 @@ smb_do_rename(
* has a file open, this will force a flush or close,
* which may affect the outcome of any share checking.
*/
-
- smb_oplock_break(src_node);
+ (void) smb_oplock_break(src_node, SMB_SESSION_GET_ID(sr->session),
+ B_FALSE);
for (count = 0; count <= 3; count++) {
if (count) {
diff --git a/usr/src/uts/common/fs/smbsrv/smb_seek.c b/usr/src/uts/common/fs/smbsrv/smb_seek.c
index 2dcc510ddf..072e9d0014 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_seek.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_seek.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -101,7 +101,7 @@ smb_com_seek(smb_request_t *sr)
if (smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &mode, &off) != 0)
return (SDRC_ERROR);
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c
index 5e7b0f50d3..c0deba767a 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c
@@ -267,6 +267,8 @@ smb_server_svc_init(void)
int rc = 0;
while (rc == 0) {
+ if (rc = smb_mbc_init())
+ continue;
if (rc = smb_vop_init())
continue;
if (rc = smb_node_init())
@@ -291,6 +293,7 @@ smb_server_svc_init(void)
smb_fem_fini();
smb_node_fini();
smb_vop_fini();
+ smb_mbc_fini();
return (rc);
}
@@ -313,6 +316,7 @@ smb_server_svc_fini(void)
smb_fem_fini();
smb_node_fini();
smb_vop_fini();
+ smb_mbc_fini();
smb_llist_destructor(&smb_servers);
rc = 0;
}
@@ -375,8 +379,6 @@ smb_server_create(void)
sizeof (smb_ofile_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
sv->si_cache_odir = kmem_cache_create("smb_odir_cache",
sizeof (smb_odir_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
- sv->si_cache_node = kmem_cache_create("smb_node_cache",
- sizeof (smb_node_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
smb_thread_init(&sv->si_thread_timers,
"smb_timers", smb_server_timers, sv,
@@ -487,7 +489,6 @@ smb_server_delete(void)
kmem_cache_destroy(sv->si_cache_tree);
kmem_cache_destroy(sv->si_cache_ofile);
kmem_cache_destroy(sv->si_cache_odir);
- kmem_cache_destroy(sv->si_cache_node);
smb_thread_destroy(&sv->si_thread_timers);
smb_thread_destroy(&sv->si_thread_unexport);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c
index 78c396429d..f3c7a4b2b0 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c
@@ -38,10 +38,12 @@ static volatile uint64_t smb_kids;
uint32_t smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT;
+static void smb_session_cancel(smb_session_t *);
static int smb_session_message(smb_session_t *);
static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
uint8_t *, size_t);
static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *);
+static void smb_session_oplock_broken(smb_session_t *);
static void smb_request_init_command_mbuf(smb_request_t *sr);
void dump_smb_inaddr(smb_inaddr_t *ipaddr);
@@ -438,7 +440,6 @@ smb_request_cancel(smb_request_t *sr)
mutex_enter(&sr->sr_awaiting->l_mutex);
cv_broadcast(&sr->sr_awaiting->l_cv);
mutex_exit(&sr->sr_awaiting->l_mutex);
-
break;
case SMB_REQ_STATE_WAITING_EVENT:
@@ -462,8 +463,7 @@ smb_request_cancel(smb_request_t *sr)
* SMB_REQ_STATE_INITIALIZING:
*/
default:
- ASSERT(0);
- break;
+ SMB_PANIC();
}
mutex_exit(&sr->sr_mutex);
}
@@ -669,6 +669,9 @@ smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv,
smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
offsetof(smb_xa_t, xa_lnd));
+ list_create(&session->s_oplock_brkreqs, sizeof (mbuf_chain_t),
+ offsetof(mbuf_chain_t, mbc_lnd));
+
smb_net_txl_constructor(&session->s_txlst);
smb_rwx_init(&session->s_lock);
@@ -708,12 +711,22 @@ smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv,
void
smb_session_delete(smb_session_t *session)
{
+ mbuf_chain_t *mbc;
+
ASSERT(session->s_magic == SMB_SESSION_MAGIC);
- session->s_magic = (uint32_t)~SMB_SESSION_MAGIC;
+ session->s_magic = 0;
smb_rwx_destroy(&session->s_lock);
smb_net_txl_destructor(&session->s_txlst);
+
+ while ((mbc = list_head(&session->s_oplock_brkreqs)) != NULL) {
+ SMB_MBC_VALID(mbc);
+ list_remove(&session->s_oplock_brkreqs, mbc);
+ smb_mbc_free(mbc);
+ }
+ list_destroy(&session->s_oplock_brkreqs);
+
smb_slist_destructor(&session->s_req_list);
smb_llist_destructor(&session->s_user_list);
smb_llist_destructor(&session->s_xa_list);
@@ -726,7 +739,7 @@ smb_session_delete(smb_session_t *session)
kmem_cache_free(session->s_cache, session);
}
-void
+static void
smb_session_cancel(smb_session_t *session)
{
smb_xa_t *xa, *nextxa;
@@ -751,7 +764,9 @@ smb_session_cancel(smb_session_t *session)
smb_xa_close(xa);
xa = nextxa;
}
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
smb_user_logoff_all(session);
+ smb_rwx_rwexit(&session->s_lock);
}
/*
@@ -785,8 +800,7 @@ smb_session_cancel_requests(
}
void
-smb_session_worker(
- void *arg)
+smb_session_worker(void *arg)
{
smb_request_t *sr;
@@ -794,7 +808,7 @@ smb_session_worker(
ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
-
+ sr->sr_worker = curthread;
mutex_enter(&sr->sr_mutex);
switch (sr->sr_state) {
case SMB_REQ_STATE_SUBMITTED:
@@ -1117,13 +1131,15 @@ smb_request_free(smb_request_t *sr)
{
ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
ASSERT(sr->session);
- ASSERT(sr->fid_ofile == NULL);
ASSERT(sr->r_xa == NULL);
- if (sr->tid_tree)
+ if (sr->fid_ofile != NULL)
+ smb_ofile_release(sr->fid_ofile);
+
+ if (sr->tid_tree != NULL)
smb_tree_release(sr->tid_tree);
- if (sr->uid_user)
+ if (sr->uid_user != NULL)
smb_user_release(sr->uid_user);
smb_slist_remove(&sr->session->s_req_list, sr);
@@ -1157,3 +1173,121 @@ char ipstr[INET6_ADDRSTRLEN];
else
cmn_err(CE_WARN, "error converting ip address");
}
+
+boolean_t
+smb_session_oplocks_enable(smb_session_t *session)
+{
+ SMB_SESSION_VALID(session);
+ if (session->s_cfg.skc_oplock_enable == 0)
+ return (B_FALSE);
+ else
+ return (B_TRUE);
+}
+
+/*
+ * smb_session_breaking_oplock
+ *
+ * This MUST be a cross-session call, i.e. the caller must be in a different
+ * context than the one passed.
+ */
+void
+smb_session_oplock_break(smb_session_t *session, smb_ofile_t *of)
+{
+ mbuf_chain_t *mbc;
+
+ SMB_SESSION_VALID(session);
+
+ mbc = smb_mbc_alloc(MLEN);
+
+ (void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.ww10.",
+ SMB_COM_LOCKING_ANDX,
+ SMB_TREE_GET_TID(SMB_OFILE_GET_TREE(of)),
+ 0xFFFF, 0, 0xFFFF, 8, 0xFF,
+ SMB_OFILE_GET_FID(of),
+ LOCKING_ANDX_OPLOCK_RELEASE);
+
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_NEGOTIATED:
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ session->s_state = SMB_SESSION_STATE_OPLOCK_BREAKING;
+ session->s_oplock_brkcntr++;
+ (void) smb_session_send(session, 0, mbc);
+ smb_mbc_free(mbc);
+ break;
+
+ case SMB_SESSION_STATE_READ_RAW_ACTIVE:
+ list_insert_tail(&session->s_oplock_brkreqs, mbc);
+ break;
+
+ case SMB_SESSION_STATE_DISCONNECTED:
+ case SMB_SESSION_STATE_TERMINATED:
+ smb_mbc_free(mbc);
+ break;
+
+ default:
+ SMB_PANIC();
+ }
+ smb_rwx_rwexit(&session->s_lock);
+}
+
+/*
+ * smb_session_oplock_released
+ *
+ * This function MUST be called in the context of the session of the client
+ * holding the oplock. The lock of the session must have been entered in
+ * RW_READER or RW_WRITER mode.
+ */
+void
+smb_session_oplock_released(smb_session_t *session)
+{
+ krw_t mode;
+
+ SMB_SESSION_VALID(session);
+
+ mode = smb_rwx_rwupgrade(&session->s_lock);
+ smb_session_oplock_broken(session);
+ smb_rwx_rwdowngrade(&session->s_lock, mode);
+}
+
+/*
+ * smb_session_oplock_break_timedout
+ *
+ * This function MUST be called when the client holding the oplock to file
+ * failed to release it in the time alloted. It is a cross-session call (The
+ * caller must be calling in the context of another session).
+ */
+void
+smb_session_oplock_break_timedout(smb_session_t *session)
+{
+ SMB_SESSION_VALID(session);
+
+ smb_rwx_rwenter(&session->s_lock, RW_WRITER);
+ smb_session_oplock_broken(session);
+ smb_rwx_rwexit(&session->s_lock);
+}
+
+/*
+ * smb_session_oplock_broken
+ *
+ * Does the actual work.
+ */
+static void
+smb_session_oplock_broken(smb_session_t *session)
+{
+ switch (session->s_state) {
+ case SMB_SESSION_STATE_OPLOCK_BREAKING:
+ if (--session->s_oplock_brkcntr == 0)
+ session->s_state = SMB_SESSION_STATE_NEGOTIATED;
+ break;
+
+ case SMB_SESSION_STATE_NEGOTIATED:
+ case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
+ case SMB_SESSION_STATE_DISCONNECTED:
+ case SMB_SESSION_STATE_TERMINATED:
+ break;
+
+ default:
+ SMB_PANIC();
+ }
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_set_information.c
index b68cd6ab27..9e5275bbb2 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_set_information.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_information.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -132,7 +132,8 @@ smb_com_set_information(smb_request_t *sr)
/*
* for the benefit of attribute setting later on
*/
- smb_oplock_break(node);
+ (void) smb_oplock_break(node, SMB_SESSION_GET_ID(sr->session),
+ B_FALSE);
}
/*
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
index 3d7f072275..68528f77eb 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -82,7 +82,7 @@ smb_com_set_information2(smb_request_t *sr)
if (rc != 0)
return (SDRC_ERROR);
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
index ae2012e6fd..e14deb008a 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
@@ -99,7 +99,7 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
return (SDRC_ERROR);
}
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -227,6 +227,7 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
break;
case SMB_QUERY_FILE_BASIC_INFO:
+ case SMB_FILE_BASIC_INFORMATION:
/*
* NT includes 6 undocumented bytes at the end of this
* response, which are required by NetBench 5.01.
@@ -242,8 +243,8 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
break;
case SMB_QUERY_FILE_STANDARD_INFO:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w",
- SMB_QUERY_FILE_STANDARD_INFO);
+ case SMB_FILE_STANDARD_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
/*
* Add 2 bytes to pad data to long. It is
* necessary because Win2k expects the padded bytes.
@@ -371,6 +372,19 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
datasz, 0, 0, 0, 0);
break;
+ case SMB_FILE_ATTR_TAG_INFORMATION:
+ /*
+ * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
+ * second dword should be the reparse tag. Otherwise
+ * the tag value should be set to zero.
+ * We don't support reparse points, so we set the tag
+ * to zero.
+ */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
+ (uint32_t)dattr, 0);
+ break;
+
default:
kmem_free(filebuf, MAXNAMELEN+1);
kmem_free(mangled_name, MAXNAMELEN);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
index 29f079f4fd..c916daf040 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -375,7 +375,11 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
!= 0) {
kmem_free(name, MAXNAMELEN);
- smbsr_errno(sr, rc);
+ if (rc == ENOENT)
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
+ else
+ smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
@@ -389,7 +393,11 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
kmem_free(short_name, MAXNAMELEN);
kmem_free(name83, MAXNAMELEN);
- smbsr_errno(sr, rc);
+ if (rc == ENOENT)
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
+ else
+ smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
@@ -457,6 +465,7 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
break;
case SMB_QUERY_FILE_BASIC_INFO:
+ case SMB_FILE_BASIC_INFORMATION:
/*
* NT includes 6 undocumented bytes at the end of this
* response, which are required by NetBench 5.01.
@@ -472,6 +481,7 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
break;
case SMB_QUERY_FILE_STANDARD_INFO:
+ case SMB_FILE_STANDARD_INFORMATION:
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
/*
* Add 2 bytes to pad data to long. It is
@@ -573,6 +583,19 @@ smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
ap->sa_vattr.va_nodeid);
break;
+ case SMB_FILE_ATTR_TAG_INFORMATION:
+ /*
+ * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
+ * second dword should be the reparse tag. Otherwise
+ * the tag value should be set to zero.
+ * We don't support reparse points, so we set the tag
+ * to zero.
+ */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
+ (uint32_t)dattr, 0);
+ break;
+
default:
smb_node_release(node);
kmem_free(name, MAXNAMELEN);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
index 45c964c78a..23444f5984 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -125,7 +125,7 @@ smb_com_trans2_set_file_information(struct smb_request *sr, struct smb_xa *xa)
return (SDRC_ERROR);
}
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
kmem_free(info, sizeof (smb_trans2_setinfo_t));
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
index deab006e45..be82d499e1 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
@@ -19,12 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "@(#)smb_trans2_set_path_information.c 1.9 08/08/08 SMI"
-
/*
* SMB: trans2_set_path_information
*
@@ -164,7 +161,8 @@ smb_com_trans2_set_path_information(struct smb_request *sr, struct smb_xa *xa)
/*
* for the benefit of attribute setting later on
*/
- smb_oplock_break(ret_snode);
+ (void) smb_oplock_break(ret_snode,
+ SMB_SESSION_GET_ID(sr->session), B_FALSE);
}
info->node = ret_snode;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c
index b8a6082211..d053031952 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c
@@ -549,6 +549,7 @@ smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
* aclaccess (those from the ACL object for the share). This
* is done during the alloc.
*/
+
tree = smb_tree_alloc(user, sharename, si->shr_path, STYPE_DISKTREE,
snode, hostaccess & aclaccess);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c b/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
index 0fea514041..aab82acfff 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_unlock_byte_range.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* SMB: unlock_byte_range
*
@@ -78,7 +76,7 @@ smb_com_unlock_byte_range(smb_request_t *sr)
if (smbsr_decode_vwv(sr, "wll", &sr->smb_fid, &Length, &Offset) != 0)
return (SDRC_ERROR);
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_util.c b/usr/src/uts/common/fs/smbsrv/smb_util.c
index b9bf87eae8..2c2aa5f2eb 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_util.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_util.c
@@ -40,10 +40,6 @@
#include <sys/sid.h>
#include <sys/priv_names.h>
-#ifdef DEBUG
-uint_t smb_tsd_key;
-#endif
-
static boolean_t
smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks);
@@ -143,24 +139,6 @@ smb_convert_unicode_wildcards(char *path)
}
/*
- * smb_is_dot_or_dotdot
- *
- * Use when checking for the "." and ".." entries in a directory.
- * Returns B_TRUE if the name is "." or "..". Otherwise returns B_FALSE.
- */
-boolean_t
-smb_is_dot_or_dotdot(const char *name)
-{
- if (*name != '.')
- return (B_FALSE);
-
- if ((name[1] == 0) || (name[1] == '.' && name[2] == 0))
- return (B_TRUE);
-
- return (B_FALSE);
-}
-
-/*
* smb_sattr_check
*
* Check file attributes against a search attribute (sattr) mask.
@@ -195,14 +173,8 @@ smb_is_dot_or_dotdot(const char *name)
* Returns true if the file and sattr match; otherwise, returns false.
*/
boolean_t
-smb_sattr_check(uint16_t dosattr, uint16_t sattr, char *name)
+smb_sattr_check(uint16_t dosattr, uint16_t sattr)
{
- if (name) {
- if (smb_is_dot_or_dotdot(name) &&
- !(sattr & FILE_ATTRIBUTE_HIDDEN))
- return (B_FALSE);
- }
-
if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) &&
!(sattr & FILE_ATTRIBUTE_DIRECTORY))
return (B_FALSE);
@@ -1794,37 +1766,6 @@ smb_timegm(struct tm *tm)
return (tsec);
}
-#ifdef DEBUG
-uint32_t smb_audit_flags = SMB_AUDIT_NODE;
-#else
-uint32_t smb_audit_flags = 0;
-#endif
-
-void
-smb_audit_buf_node_create(smb_node_t *node)
-{
- smb_audit_buf_node_t *abn;
-
- if (smb_audit_flags & SMB_AUDIT_NODE) {
- abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), KM_SLEEP);
- abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1;
- node->n_audit_buf = abn;
- }
-}
-
-void
-smb_audit_buf_node_destroy(smb_node_t *node)
-{
- smb_audit_buf_node_t *abn;
-
- abn = node->n_audit_buf;
-
- if (abn) {
- node->n_audit_buf = NULL;
- kmem_free(abn, sizeof (smb_audit_buf_node_t));
- }
-}
-
/*
* smb_cred_set_sid
*
@@ -2091,3 +2032,15 @@ smb_cred_create_privs(cred_t *user_cr, uint32_t privileges)
return (cr);
}
+
+/*
+ * smb_panic
+ *
+ * Logs the file name, function name and line number passed in and panics the
+ * system.
+ */
+void
+smb_panic(char *file, const char *func, int line)
+{
+ cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write.c b/usr/src/uts/common/fs/smbsrv/smb_write.c
index 7af9ed9b72..1fc27b1f9e 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_write.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_write.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,6 +33,13 @@
#define SMB_WRMODE_WRITE_THRU 0x0001
#define SMB_WRMODE_IS_STABLE(M) ((M) & SMB_WRMODE_WRITE_THRU)
+/*
+ * The limit in bytes that the marshalling will grow the buffer
+ * chain to accomodate incoming data on SmbWriteX requests.
+ * This sets the upper limit for the data-count per SmbWriteX
+ * request.
+ */
+#define SMB_WRITEX_MAX 102400
static int smb_write_common(smb_request_t *, smb_rw_param_t *);
static int smb_write_truncate(smb_request_t *, smb_rw_param_t *);
@@ -53,16 +60,18 @@ smb_pre_write(smb_request_t *sr)
{
smb_rw_param_t *param;
uint32_t off;
+ uint16_t count;
int rc;
param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
sr->arg.rw = param;
param->rw_magic = SMB_RW_MAGIC;
- rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &param->rw_count, &off);
+ rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off);
+ param->rw_count = (uint32_t)count;
param->rw_offset = (uint64_t)off;
- param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset;
+ param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
DTRACE_SMB_2(op__Write__start, smb_request_t *, sr,
smb_rw_param_t *, param);
@@ -85,7 +94,7 @@ smb_com_write(smb_request_t *sr)
smb_rw_param_t *param = sr->arg.rw;
int rc;
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -98,13 +107,13 @@ smb_com_write(smb_request_t *sr)
} else {
rc = smbsr_decode_data(sr, "D", &param->rw_vdb);
- if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) {
+ if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
ERRDOS, ERROR_INVALID_PARAMETER);
return (SDRC_ERROR);
}
- param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset;
+ param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
rc = smb_write_common(sr, param);
}
@@ -115,7 +124,8 @@ smb_com_write(smb_request_t *sr)
return (SDRC_ERROR);
}
- rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0);
+ rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
+ (uint16_t)param->rw_count, 0);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
@@ -135,6 +145,7 @@ smb_pre_write_and_close(smb_request_t *sr)
{
smb_rw_param_t *param;
uint32_t off;
+ uint16_t count;
int rc;
param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
@@ -143,12 +154,13 @@ smb_pre_write_and_close(smb_request_t *sr)
if (sr->smb_wct == 12) {
rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
- &param->rw_count, &off, &param->rw_last_write);
+ &count, &off, &param->rw_last_write);
} else {
rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
- &param->rw_count, &off, &param->rw_last_write);
+ &count, &off, &param->rw_last_write);
}
+ param->rw_count = (uint32_t)count;
param->rw_offset = (uint64_t)off;
DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr,
@@ -170,9 +182,10 @@ smb_sdrc_t
smb_com_write_and_close(smb_request_t *sr)
{
smb_rw_param_t *param = sr->arg.rw;
+ uint16_t count;
int rc = 0;
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -189,13 +202,13 @@ smb_com_write_and_close(smb_request_t *sr)
rc = smbsr_decode_data(sr, ".#B", param->rw_count,
&param->rw_vdb);
- if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) {
+ if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
ERRDOS, ERROR_INVALID_PARAMETER);
return (SDRC_ERROR);
}
- param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset;
+ param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
rc = smb_write_common(sr, param);
}
@@ -208,7 +221,8 @@ smb_com_write_and_close(smb_request_t *sr)
smb_ofile_close(sr->fid_ofile, param->rw_last_write);
- rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0);
+ count = (uint16_t)param->rw_count;
+ rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
@@ -234,6 +248,7 @@ smb_pre_write_and_unlock(smb_request_t *sr)
{
smb_rw_param_t *param;
uint32_t off;
+ uint16_t count;
uint16_t remcnt;
int rc;
@@ -241,9 +256,9 @@ smb_pre_write_and_unlock(smb_request_t *sr)
sr->arg.rw = param;
param->rw_magic = SMB_RW_MAGIC;
- rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &param->rw_count, &off,
- &remcnt);
+ rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt);
+ param->rw_count = (uint32_t)count;
param->rw_offset = (uint64_t)off;
DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr,
@@ -273,7 +288,7 @@ smb_com_write_and_unlock(smb_request_t *sr)
return (SDRC_ERROR);
}
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -286,15 +301,16 @@ smb_com_write_and_unlock(smb_request_t *sr)
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
+
rc = smbsr_decode_data(sr, "D", &param->rw_vdb);
- if ((rc != 0) || (param->rw_count != param->rw_vdb.len)) {
+ if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) {
smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
ERRDOS, ERROR_INVALID_PARAMETER);
return (SDRC_ERROR);
}
- param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset;
+ param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
if ((rc = smb_write_common(sr, param)) != 0) {
if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
@@ -310,7 +326,8 @@ smb_com_write_and_unlock(smb_request_t *sr)
return (SDRC_ERROR);
}
- rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->rw_count, 0);
+ rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
+ (uint16_t)param->rw_count, 0);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
@@ -324,6 +341,11 @@ smb_com_write_and_unlock(smb_request_t *sr)
*
* If bit 0 of WriteMode is set, Fid must refer to a disk file and
* the data must be on stable storage before responding.
+ *
+ * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5:
+ * If CAP_LARGE_WRITEX is set, the byte count may be larger than the
+ * negotiated buffer size and the server is expected to write the
+ * number of bytes specified.
*/
smb_sdrc_t
smb_pre_write_andx(smb_request_t *sr)
@@ -331,6 +353,8 @@ smb_pre_write_andx(smb_request_t *sr)
smb_rw_param_t *param;
uint32_t off_low;
uint32_t off_high;
+ uint16_t datalen_low;
+ uint16_t datalen_high;
uint16_t remcnt;
int rc;
@@ -339,21 +363,24 @@ smb_pre_write_andx(smb_request_t *sr)
param->rw_magic = SMB_RW_MAGIC;
if (sr->smb_wct == 14) {
- rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid,
- &off_low, &param->rw_mode, &remcnt, &param->rw_count,
- &param->rw_dsoff, &off_high);
+ rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid,
+ &off_low, &param->rw_mode, &remcnt, &datalen_high,
+ &datalen_low, &param->rw_dsoff, &off_high);
param->rw_dsoff -= 63;
param->rw_offset = ((uint64_t)off_high << 32) | off_low;
} else {
- rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid,
- &off_low, &param->rw_mode, &remcnt, &param->rw_count,
- &param->rw_dsoff);
+ rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid,
+ &off_low, &param->rw_mode, &remcnt, &datalen_high,
+ &datalen_low, &param->rw_dsoff);
param->rw_offset = (uint64_t)off_low;
param->rw_dsoff -= 59;
}
+ param->rw_count = ((uint32_t)datalen_high << 16) |
+ (uint32_t)datalen_low;
+
DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr,
smb_rw_param_t *, param);
@@ -373,12 +400,14 @@ smb_sdrc_t
smb_com_write_andx(smb_request_t *sr)
{
smb_rw_param_t *param = sr->arg.rw;
+ uint16_t count_high;
+ uint16_t count_low;
int rc;
ASSERT(param);
ASSERT(param->rw_magic == SMB_RW_MAGIC);
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);
@@ -392,15 +421,17 @@ smb_com_write_andx(smb_request_t *sr)
return (SDRC_ERROR);
}
+ sr->smb_data.max_bytes = SMB_WRITEX_MAX;
rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
&param->rw_vdb);
- if ((rc != 0) || (param->rw_vdb.len != param->rw_count)) {
+
+ if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
ERRDOS, ERROR_INVALID_PARAMETER);
return (SDRC_ERROR);
}
- param->rw_vdb.uio.uio_loffset = (offset_t)param->rw_offset;
+ param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
if (param->rw_count != 0) {
if ((rc = smb_write_common(sr, param)) != 0) {
@@ -411,8 +442,11 @@ smb_com_write_andx(smb_request_t *sr)
}
}
- rc = smbsr_encode_result(sr, 6, 0, "bb1.ww6.w",
- 6, sr->andx_com, 15, param->rw_count, 0);
+ count_low = param->rw_count & 0xFFFF;
+ count_high = (param->rw_count >> 16) & 0xFF;
+
+ rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww",
+ 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
@@ -451,7 +485,7 @@ smb_write_common(smb_request_t *sr, smb_rw_param_t *param)
}
rc = smb_fsop_write(sr, sr->user_cr, node,
- &param->rw_vdb.uio, &lcount, &node->attr, stability);
+ &param->rw_vdb.vdb_uio, &lcount, &node->attr, stability);
if (rc)
return (rc);
@@ -465,13 +499,13 @@ smb_write_common(smb_request_t *sr, smb_rw_param_t *param)
}
}
- param->rw_count = (uint16_t)lcount;
+ param->rw_count = lcount;
break;
case STYPE_IPC:
- param->rw_count = (uint16_t)param->rw_vdb.uio.uio_resid;
+ param->rw_count = param->rw_vdb.vdb_uio.uio_resid;
- if ((rc = smb_opipe_write(sr, &param->rw_vdb.uio)) != 0)
+ if ((rc = smb_opipe_write(sr, &param->rw_vdb.vdb_uio)) != 0)
param->rw_count = 0;
break;
@@ -517,10 +551,10 @@ smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param)
append_only = B_TRUE;
}
- smb_rwx_xenter(&node->n_lock);
+ mutex_enter(&node->n_mutex);
if (append_only && (param->rw_offset < node->n_size)) {
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
return (EACCES);
}
@@ -528,7 +562,7 @@ smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param)
status = smb_lock_range_access(sr, node, param->rw_offset,
param->rw_count, B_TRUE);
if (status != NT_STATUS_SUCCESS) {
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
ERRDOS, ERROR_LOCK_VIOLATION);
return (EACCES);
@@ -538,7 +572,7 @@ smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param)
node->flags |= NODE_FLAGS_SET_SIZE;
node->n_size = param->rw_offset;
- smb_rwx_xexit(&node->n_lock);
+ mutex_exit(&node->n_mutex);
if ((rc = smb_set_file_size(sr, node)) != 0)
return (rc);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
index 6b8f3e7d69..8abb990749 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -254,7 +254,7 @@ smb_com_write_raw(struct smb_request *sr)
off = ((offset_t)off_high << 32) | off_low;
addl_xfer_count = count - data_length;
- sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
+ smbsr_lookup_file(sr);
if (sr->fid_ofile == NULL) {
smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
return (SDRC_ERROR);