changeset 10001:d540bbbe2461

6853206 zfs set sharesmb=off fails to unshare the dataset 6830187 False message when saving a Excel 2003 file 6576380 Win98: Attributes Read-only, Hidden, and Archive cannot be unchecked once it is set 6819639 Can't unmount zfs file system after CIFS server connects to a share 6854186 SMB Query File Information level ALT_NAME_INFO returns incorrect name and namelen. 6854769 SVCCTL does not support SMF service list when using Delphi applications 6850508 Unable to join Windows 2008 domain (SP2 or later)
author joyce mcintosh <Joyce.McIntosh@Sun.COM>
date Tue, 30 Jun 2009 08:31:17 -0700
parents 241a51d8720c
children 2a588c9bb482
files usr/src/cmd/krb5/kadmin/kclient/kclient.sh usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c usr/src/lib/smbsrv/libsmb/common/libsmb.h usr/src/lib/smbsrv/libsmb/common/smb_kmod.c usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c usr/src/uts/common/fs/smbsrv/smb_common_open.c usr/src/uts/common/fs/smbsrv/smb_delete.c usr/src/uts/common/fs/smbsrv/smb_directory.c usr/src/uts/common/fs/smbsrv/smb_fsops.c usr/src/uts/common/fs/smbsrv/smb_lock.c usr/src/uts/common/fs/smbsrv/smb_node.c usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c usr/src/uts/common/fs/smbsrv/smb_odir.c usr/src/uts/common/fs/smbsrv/smb_ofile.c usr/src/uts/common/fs/smbsrv/smb_open_andx.c usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c usr/src/uts/common/fs/smbsrv/smb_query_information.c usr/src/uts/common/fs/smbsrv/smb_query_information2.c usr/src/uts/common/fs/smbsrv/smb_read.c usr/src/uts/common/fs/smbsrv/smb_rename.c usr/src/uts/common/fs/smbsrv/smb_seek.c usr/src/uts/common/fs/smbsrv/smb_server.c usr/src/uts/common/fs/smbsrv/smb_set_information.c usr/src/uts/common/fs/smbsrv/smb_set_information2.c usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c usr/src/uts/common/fs/smbsrv/smb_tree.c usr/src/uts/common/fs/smbsrv/smb_util.c usr/src/uts/common/fs/smbsrv/smb_vops.c usr/src/uts/common/fs/smbsrv/smb_vss.c usr/src/uts/common/fs/smbsrv/smb_write.c usr/src/uts/common/fs/smbsrv/smb_write_raw.c usr/src/uts/common/smbsrv/cifs.h usr/src/uts/common/smbsrv/ndl/svcctl.ndl usr/src/uts/common/smbsrv/ntifs.h usr/src/uts/common/smbsrv/smb_fsops.h usr/src/uts/common/smbsrv/smb_kproto.h usr/src/uts/common/smbsrv/smb_ktypes.h usr/src/uts/common/smbsrv/smb_vops.h usr/src/uts/common/smbsrv/winsvc.h
diffstat 48 files changed, 2317 insertions(+), 1336 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/krb5/kadmin/kclient/kclient.sh	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/cmd/krb5/kadmin/kclient/kclient.sh	Tue Jun 30 08:31:17 2009 -0700
@@ -1178,7 +1178,7 @@
 	upcase_nodename=$hostname
 	netbios_nodename="${upcase_nodename}\$"
 	fqdn=$hostname.$domain
-	upn=host/${fqdn}
+	upn=host/${fqdn}@${realm}
 
 	grep=/usr/xpg4/bin/grep
 
@@ -1255,10 +1255,6 @@
 		printf "$(gettext "Search for domain functionality failed, exiting").\n" >&2
 		error_message
 	fi
-	# Longhorn and above can't perform an init auth from service
-	# keys if the realm is included in the UPN.  w2k3 and below
-	# can't perform an init auth when the realm is excluded.
-	[[ $level -lt 3 ]] && upn=${upn}@${realm}
 
 	if ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" \
 	    -s sub sAMAccountName="$netbios_nodename" dn > /dev/null 2>&1
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c	Tue Jun 30 08:31:17 2009 -0700
@@ -132,7 +132,7 @@
 		rc = smb_kmod_share(path, name);
 		break;
 	case SMB_SHROP_DELETE:
-		rc = smb_kmod_unshare(name);
+		rc = smb_kmod_unshare(path, name);
 		break;
 	default:
 		rc = EINVAL;
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c	Tue Jun 30 08:31:17 2009 -0700
@@ -533,53 +533,108 @@
 /*
  * svcctl_scm_enum_services
  *
- * Enumerates all SMF services.
+ * Enumerates SMF services: handles wide-char or ascii requests.
+ *
+ * Returns the number of services written to buf.
  */
-void
-svcctl_scm_enum_services(svcctl_manager_context_t *mgr_ctx,
-    unsigned char *services)
+uint32_t
+svcctl_scm_enum_services(svcctl_manager_context_t *mgr_ctx, uint8_t *buf,
+    size_t buflen, uint32_t *resume_handle, boolean_t use_wchar)
 {
-	svcctl_svc_node_t *node = NULL;
-	int base_offset, offset, i;
-	mts_wchar_t *wide_name;
-	char *name;
+	svcctl_svc_node_t *node;
+	int base_offset, offset;
+	mts_wchar_t *w_name;
+	char *a_name;
+	char *node_name;
+	size_t namelen;
+	uint32_t numsvcs = mgr_ctx->mc_scf_numsvcs;
+	uint32_t ns;
+	/*LINTED E_BAD_PTR_CAST_ALIGN*/
+	svc_enum_status_t *svc = (svc_enum_status_t *)buf;
 
-	/*LINTED E_BAD_PTR_CAST_ALIGN*/
-	svc_enum_status_t *svc = (svc_enum_status_t *)services;
+	if (buf == NULL || buflen == 0 || *resume_handle >= numsvcs) {
+		*resume_handle = 0;
+		return (0);
+	}
 
-	base_offset = mgr_ctx->mc_scf_numsvcs * sizeof (svc_enum_status_t);
+	base_offset = numsvcs * sizeof (svc_enum_status_t);
+	if (buflen < mgr_ctx->mc_bytes_needed) {
+		while (base_offset > (buflen / 4)) {
+			--numsvcs;
+			base_offset = numsvcs * sizeof (svc_enum_status_t);
+		}
+	}
 
 	offset = base_offset;
 	node = uu_avl_first(mgr_ctx->mc_svcs);
 
-	for (i = 0; ((i < mgr_ctx->mc_scf_numsvcs) && (node != NULL)); ++i) {
-		svc[i].svc_name = offset;
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		wide_name = (mts_wchar_t *)&services[offset];
-		name = node->sn_name;
-		(void) mts_mbstowcs(wide_name, name, (strlen(name) + 1));
+	for (ns = 0; ((ns < *resume_handle) && (node != NULL)); ++ns)
+		node = uu_avl_next(mgr_ctx->mc_svcs, node);
+
+	if (node == NULL) {
+		*resume_handle = 0;
+		return (0);
+	}
+
+	for (ns = 0; ((ns < numsvcs) && (node != NULL)); ++ns) {
+		node_name = node->sn_name;
+		namelen = strlen(node_name) + 1;
+		svc[ns].svc_name = offset;
 
-		offset += SVCCTL_WNSTRLEN(name);
+		if (use_wchar) {
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			w_name = (mts_wchar_t *)&buf[offset];
+			(void) mts_mbstowcs(w_name, node_name, namelen);
+			offset += SVCCTL_WNSTRLEN(node_name);
+		} else {
+			a_name = (char *)&buf[offset];
+			(void) strlcpy(a_name, node_name, namelen);
+			offset += namelen;
+		}
+
+		if (offset >= buflen)
+			break;
 
-		svc[i].display_name = offset;
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		wide_name = (mts_wchar_t *)&services[offset];
-		name = node->sn_fmri;
-		(void) mts_mbstowcs(wide_name, name, (strlen(name) + 1));
-
-		offset += SVCCTL_WNSTRLEN(name);
+		node_name = node->sn_fmri;
+		namelen = strlen(node_name) + 1;
+		svc[ns].display_name = offset;
 
-		svc[i].svc_status.cur_state =
+		if (use_wchar) {
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			w_name = (mts_wchar_t *)&buf[offset];
+			(void) mts_mbstowcs(w_name, node_name, namelen);
+			offset += SVCCTL_WNSTRLEN(node_name);
+		} else {
+			a_name = (char *)&buf[offset];
+			(void) strlcpy(a_name, node_name, namelen);
+			offset += namelen;
+		}
+
+		if (offset >= buflen)
+			break;
+
+		svc[ns].svc_status.cur_state =
 		    svcctl_scm_map_status(node->sn_state);
-		svc[i].svc_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
-		svc[i].svc_status.ctrl_accepted = 0;
-		svc[i].svc_status.w32_exitcode = 0;
-		svc[i].svc_status.svc_specified_exitcode = 0;
-		svc[i].svc_status.check_point = 0;
-		svc[i].svc_status.wait_hint = 0;
+		svc[ns].svc_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
+		svc[ns].svc_status.ctrl_accepted = 0;
+		svc[ns].svc_status.w32_exitcode = 0;
+		svc[ns].svc_status.svc_specified_exitcode = 0;
+		svc[ns].svc_status.check_point = 0;
+		svc[ns].svc_status.wait_hint = 0;
 
 		node = uu_avl_next(mgr_ctx->mc_svcs, node);
 	}
+
+	if (node == NULL) {
+		*resume_handle = 0;
+	} else {
+		*resume_handle += ns;
+
+		if (*resume_handle >= mgr_ctx->mc_scf_numsvcs)
+			*resume_handle = 0;
+	}
+
+	return (ns);
 }
 
 /*
@@ -651,7 +706,9 @@
 		char *win_svc_name;
 		char *solaris_svc_name;
 	} win2solaris_svc_map[] = {
-		{ "eventlog", "system/system-log:default" }
+		{ "eventlog", "system/system-log:default" },
+		{ "RemoteRegistry", "system/svc/restarter:default" },
+		{ "spooler",  "application/print/ppd-cache-update:default" }
 	};
 
 	size = sizeof (win2solaris_svc_map)/sizeof (win2solaris_svc_map[0]);
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h	Tue Jun 30 08:31:17 2009 -0700
@@ -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.
  */
 
@@ -95,7 +95,8 @@
 void svcctl_scm_scf_handle_fini(svcctl_manager_context_t *);
 int svcctl_scm_refresh(svcctl_manager_context_t *);
 void svcctl_scm_bytes_needed(svcctl_manager_context_t *);
-void svcctl_scm_enum_services(svcctl_manager_context_t *, unsigned char *);
+uint32_t svcctl_scm_enum_services(svcctl_manager_context_t *, uint8_t *,
+    size_t, uint32_t *, boolean_t);
 uint32_t svcctl_scm_validate_service(svcctl_manager_context_t *, char *);
 svcctl_svc_node_t *svcctl_scm_find_service(svcctl_manager_context_t *, char *);
 uint32_t svcctl_scm_map_status(const char *);
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c	Tue Jun 30 08:31:17 2009 -0700
@@ -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.
  */
 
@@ -36,8 +36,12 @@
 #include <strings.h>
 #include <smbsrv/ntstatus.h>
 #include <smbsrv/nmpipes.h>
+#include <smbsrv/ntifs.h>
 #include "svcctl_scm.h"
 
+#define	SVCCTL_SECURITY_BUFSIZE		256
+#define	SVCCTL_ENUMSERVICES_MINBUFSIZE	1024
+
 #define	SVCCTL_OPENSVC_OP_UNIMPLEMENTED(S)	\
 	((S) & SERVICE_CHANGE_CONFIG)	||	\
 	((S) & SERVICE_PAUSE_CONTINUE)	||	\
@@ -46,26 +50,47 @@
 	((S) & SERVICE_ENUMERATE_DEPENDENTS)
 
 static int svcctl_s_Close(void *, ndr_xa_t *);
+static int svcctl_s_ControlService(void *, ndr_xa_t *);
+static int svcctl_s_DeleteService(void *, ndr_xa_t *);
+static int svcctl_s_QueryServiceSecurity(void *, ndr_xa_t *);
+static int svcctl_s_SetServiceSecurity(void *, ndr_xa_t *);
 static int svcctl_s_OpenManager(void *, ndr_xa_t *);
 static int svcctl_s_OpenService(void *, ndr_xa_t *);
 static int svcctl_s_QueryServiceStatus(void *, ndr_xa_t *);
 static int svcctl_s_QueryServiceConfig(void *, ndr_xa_t *);
+static int svcctl_s_StartService(void *, ndr_xa_t *);
+static int svcctl_s_EnumDependentServices(void *, ndr_xa_t *);
 static int svcctl_s_EnumServicesStatus(void *, ndr_xa_t *);
 static int svcctl_s_GetServiceDisplayNameW(void *, ndr_xa_t *);
 static int svcctl_s_GetServiceKeyNameW(void *, ndr_xa_t *);
+static int svcctl_s_OpenSCManagerA(void *, ndr_xa_t *);
+static int svcctl_s_OpenServiceA(void *, ndr_xa_t *);
+static int svcctl_s_EnumServicesStatusA(void *, ndr_xa_t *);
 static int svcctl_s_QueryServiceConfig2W(void *, ndr_xa_t *);
+static int svcctl_s_QueryServiceStatusEx(void *, ndr_xa_t *);
 
 static ndr_stub_table_t svcctl_stub_table[] = {
 	{ svcctl_s_Close,		SVCCTL_OPNUM_Close },
+	{ svcctl_s_ControlService,	SVCCTL_OPNUM_ControlService },
+	{ svcctl_s_DeleteService,	SVCCTL_OPNUM_DeleteService },
+	{ svcctl_s_QueryServiceSecurity, SVCCTL_OPNUM_QueryServiceSecurity },
+	{ svcctl_s_SetServiceSecurity,	SVCCTL_OPNUM_SetServiceSecurity },
 	{ svcctl_s_OpenManager,		SVCCTL_OPNUM_OpenManager },
 	{ svcctl_s_OpenService,		SVCCTL_OPNUM_OpenService },
 	{ svcctl_s_QueryServiceStatus,	SVCCTL_OPNUM_QueryServiceStatus },
 	{ svcctl_s_QueryServiceConfig,	SVCCTL_OPNUM_QueryServiceConfig },
+	{ svcctl_s_StartService,	SVCCTL_OPNUM_StartService },
+	{ svcctl_s_EnumDependentServices,
+		SVCCTL_OPNUM_EnumDependentServices },
 	{ svcctl_s_EnumServicesStatus,	SVCCTL_OPNUM_EnumServicesStatus },
 	{ svcctl_s_GetServiceDisplayNameW,
 		SVCCTL_OPNUM_GetServiceDisplayNameW },
 	{ svcctl_s_GetServiceKeyNameW,	SVCCTL_OPNUM_GetServiceKeyNameW },
+	{ svcctl_s_OpenSCManagerA,	SVCCTL_OPNUM_OpenSCManagerA },
+	{ svcctl_s_OpenServiceA,	SVCCTL_OPNUM_OpenServiceA },
+	{ svcctl_s_EnumServicesStatusA,	SVCCTL_OPNUM_EnumServicesStatusA },
 	{ svcctl_s_QueryServiceConfig2W, SVCCTL_OPNUM_QueryServiceConfig2W },
+	{ svcctl_s_QueryServiceStatusEx, SVCCTL_OPNUM_QueryServiceStatusEx },
 	{0}
 };
 
@@ -297,6 +322,169 @@
 }
 
 /*
+ * svcctl_s_ControlService
+ */
+static int
+svcctl_s_ControlService(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_ControlService *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+	svcctl_manager_context_t *mgr_ctx;
+	svcctl_service_context_t *svc_ctx;
+	svcctl_svc_node_t *svc;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		bzero(param, sizeof (struct svcctl_ControlService));
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
+	mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
+	if (mgr_ctx == NULL) {
+		bzero(param, sizeof (struct svcctl_ControlService));
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	switch (param->control) {
+	case SERVICE_CONTROL_STOP:
+	case SERVICE_CONTROL_PAUSE:
+	case SERVICE_CONTROL_CONTINUE:
+	case SERVICE_CONTROL_INTERROGATE:
+	case SERVICE_CONTROL_SHUTDOWN:
+	case SERVICE_CONTROL_PARAMCHANGE:
+	case SERVICE_CONTROL_NETBINDADD:
+	case SERVICE_CONTROL_NETBINDREMOVE:
+	case SERVICE_CONTROL_NETBINDENABLE:
+	case SERVICE_CONTROL_NETBINDDISABLE:
+		break;
+	default:
+		bzero(param, sizeof (struct svcctl_ControlService));
+		param->status = ERROR_INVALID_PARAMETER;
+		return (NDR_DRC_OK);
+	}
+
+	svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
+	if (svc == NULL || svc->sn_state == NULL) {
+		bzero(param, sizeof (struct svcctl_ControlService));
+		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
+		return (NDR_DRC_OK);
+	}
+
+	param->service_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
+	param->service_status.cur_state = svcctl_scm_map_status(svc->sn_state);
+	param->service_status.ctrl_accepted = 0;
+	param->service_status.w32_exitcode = 0;
+	param->service_status.svc_specified_exitcode = 0;
+	param->service_status.check_point = 0;
+	param->service_status.wait_hint = 0;
+
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*
+ * svcctl_s_DeleteService
+ */
+static int
+svcctl_s_DeleteService(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_DeleteService *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*
+ * svcctl_s_QueryServiceSecurity
+ */
+static int
+svcctl_s_QueryServiceSecurity(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_QueryServiceSecurity *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+	uint32_t sec_info;
+	uint32_t bytes_needed = 0;
+	uint32_t status;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		status = ERROR_INVALID_HANDLE;
+		goto query_service_security_error;
+	}
+
+	sec_info = param->security_info & SMB_ALL_SECINFO;
+	if (sec_info == 0) {
+		status = ERROR_INVALID_PARAMETER;
+		goto query_service_security_error;
+	}
+
+	if (param->buf_size < SVCCTL_SECURITY_BUFSIZE) {
+		bytes_needed = SVCCTL_SECURITY_BUFSIZE;
+		status = ERROR_INSUFFICIENT_BUFFER;
+		goto query_service_security_error;
+	}
+
+	param->buffer = NDR_MALLOC(mxa, SVCCTL_SECURITY_BUFSIZE);
+	if (param->buffer == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto query_service_security_error;
+	}
+
+	bzero(param->buffer, sizeof (SVCCTL_SECURITY_BUFSIZE));
+	param->buf_size = SVCCTL_SECURITY_BUFSIZE;
+	param->bytes_needed = 0;
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+
+query_service_security_error:
+	bzero(param, sizeof (struct svcctl_QueryServiceSecurity));
+	param->buf_size = 0;
+	param->buffer = NDR_MALLOC(mxa, sizeof (uint32_t));
+	param->bytes_needed = bytes_needed;
+	param->status = status;
+	return (NDR_DRC_OK);
+}
+
+
+/*
+ * svcctl_s_SetServiceSecurity
+ */
+static int
+svcctl_s_SetServiceSecurity(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_SetServiceSecurity *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	if ((param->security_info & SMB_ALL_SECINFO) == 0) {
+		param->status = ERROR_INVALID_PARAMETER;
+		return (NDR_DRC_OK);
+	}
+
+	param->status = ERROR_ACCESS_DENIED;
+	return (NDR_DRC_OK);
+}
+
+/*
  * svcctl_s_OpenManager
  *
  * Request to open the service control manager.
@@ -423,14 +611,14 @@
 	svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
 	mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
 	if (mgr_ctx == NULL) {
-		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
+		bzero(param, sizeof (struct svcctl_QueryServiceStatus));
 		param->status = ERROR_INVALID_HANDLE;
 		return (NDR_DRC_OK);
 	}
 
 	svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
 	if (svc == NULL || svc->sn_state == NULL) {
-		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
+		bzero(param, sizeof (struct svcctl_QueryServiceStatus));
 		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
 		return (NDR_DRC_OK);
 	}
@@ -448,16 +636,89 @@
 }
 
 /*
+ * svcctl_s_EnumDependentServices
+ *
+ * Enumerate the list of services that depend on the specified service.
+ */
+static int
+svcctl_s_EnumDependentServices(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_EnumDependentServices *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+	svcctl_manager_context_t *mgr_ctx;
+	svcctl_service_context_t *svc_ctx;
+	svcctl_svc_node_t *svc;
+	int input_bufsize = 0;
+	uint32_t status;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		status = ERROR_INVALID_HANDLE;
+		goto enum_dependent_services_error;
+	}
+
+	svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
+	mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
+	if (mgr_ctx == NULL) {
+		status = ERROR_INVALID_HANDLE;
+		goto enum_dependent_services_error;
+	}
+
+	svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
+	if (svc == NULL || svc->sn_state == NULL) {
+		status = ERROR_SERVICE_DOES_NOT_EXIST;
+		goto enum_dependent_services_error;
+	}
+
+	switch (param->svc_state) {
+	case SERVICE_STOPPED:
+	case SERVICE_START_PENDING:
+	case SERVICE_STOP_PENDING:
+	case SERVICE_RUNNING:
+	case SERVICE_CONTINUE_PENDING:
+	case SERVICE_PAUSE_PENDING:
+	case SERVICE_PAUSED:
+		break;
+	default:
+		status = ERROR_INVALID_PARAMETER;
+		goto enum_dependent_services_error;
+	}
+
+	if ((input_bufsize = param->buf_size) == 0) {
+		bzero(param, sizeof (struct svcctl_EnumDependentServices));
+		param->buf_size = input_bufsize;
+		param->services = NDR_STRDUP(mxa, "");
+		param->bytes_needed = 1024;
+		param->svc_num = 0;
+		param->status = ERROR_MORE_DATA;
+		return (NDR_DRC_OK);
+	}
+
+	param->services = NDR_MALLOC(mxa, input_bufsize);
+	if (param->services == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto enum_dependent_services_error;
+	}
+
+	bzero(param->services, input_bufsize);
+	param->buf_size = input_bufsize;
+	param->bytes_needed = 0;
+	param->svc_num = 0;
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+
+enum_dependent_services_error:
+	bzero(param, sizeof (struct svcctl_EnumDependentServices));
+	param->services = NDR_STRDUP(mxa, "");
+	param->status = status;
+	return (NDR_DRC_OK);
+}
+
+/*
  * svcctl_s_EnumServicesStatus
  *
- * Enumerate the list of services we support. Currently, this list
- * is built in a fixed-size 1024 byte buffer - be careful not to
- * over-run the buffer.
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_INVALID_HANDLE
- *	ERROR_NOT_ENOUGH_MEMORY
+ * Enumerate the list of services we support.
  */
 static int
 svcctl_s_EnumServicesStatus(void *arg, ndr_xa_t *mxa)
@@ -465,50 +726,67 @@
 	struct svcctl_EnumServicesStatus *param = arg;
 	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
 	ndr_handle_t *hd;
-	int input_bufsize = 0;
 	svcctl_manager_context_t *mgr_ctx;
+	uint32_t buf_size = 0;
+	uint32_t svc_num;
+	uint32_t resume_handle = 0;
+	uint32_t status;
+
+	if (param->resume_handle != NULL)
+		resume_handle = *param->resume_handle;
 
 	hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
 	if (hd == NULL) {
-		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
-		param->services = NDR_STRDUP(mxa, "");
-		param->status = ERROR_INVALID_HANDLE;
-		return (NDR_DRC_OK);
+		status = ERROR_INVALID_HANDLE;
+		goto enum_services_status_error;
 	}
 
 	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
 	if (svcctl_scm_refresh(mgr_ctx) != 0) {
-		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
-		param->services = NDR_STRDUP(mxa, "");
-		param->status = ERROR_INVALID_DATA;
-		return (NDR_DRC_OK);
+		status = ERROR_INVALID_HANDLE;
+		goto enum_services_status_error;
 	}
 
-	input_bufsize = param->buf_size;
-	param->services = NDR_MALLOC(mxa, input_bufsize);
+	buf_size = param->buf_size;
+	param->services = NDR_MALLOC(mxa, buf_size);
 	if (param->services == NULL) {
-		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
-		param->services = NDR_STRDUP(mxa, "");
-		param->status = ERROR_NOT_ENOUGH_MEMORY;
-		return (NDR_DRC_OK);
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto enum_services_status_error;
 	}
-	bzero(param->services, input_bufsize);
+	bzero(param->services, buf_size);
 
-	if (input_bufsize <= mgr_ctx->mc_bytes_needed) {
+	if (buf_size < SVCCTL_ENUMSERVICES_MINBUFSIZE) {
 		param->bytes_needed = mgr_ctx->mc_bytes_needed;
 		param->svc_num = 0;
-		param->resume_handle = 0;
+		if (param->resume_handle)
+			*param->resume_handle = 0;
 		param->status = ERROR_MORE_DATA;
 		return (NDR_DRC_OK);
 	}
 
-	svcctl_scm_enum_services(mgr_ctx, param->services);
+	svc_num = svcctl_scm_enum_services(mgr_ctx, param->services,
+	    buf_size, &resume_handle, B_TRUE);
+
+	param->buf_size = buf_size;
+	param->svc_num = svc_num;
 
-	param->buf_size = input_bufsize;
-	param->bytes_needed = 0;
-	param->svc_num = mgr_ctx->mc_scf_numsvcs;
-	param->resume_handle = 0;
-	param->status = ERROR_SUCCESS;
+	if (resume_handle != 0) {
+		if (param->resume_handle != NULL)
+			*param->resume_handle = resume_handle;
+		param->bytes_needed = mgr_ctx->mc_bytes_needed;
+		param->status = ERROR_MORE_DATA;
+	} else {
+		if (param->resume_handle)
+			*param->resume_handle = 0;
+		param->bytes_needed = 0;
+		param->status = ERROR_SUCCESS;
+	}
+	return (NDR_DRC_OK);
+
+enum_services_status_error:
+	bzero(param, sizeof (struct svcctl_EnumServicesStatus));
+	param->services = NDR_STRDUP(mxa, "");
+	param->status = status;
 	return (NDR_DRC_OK);
 }
 
@@ -574,7 +852,7 @@
 	if (param->buf_size < bytes_needed) {
 		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
 		param->cfg_bytes = bytes_needed;
-		param->status = ERROR_MORE_DATA;
+		param->status = ERROR_INSUFFICIENT_BUFFER;
 		return (NDR_DRC_OK);
 	}
 
@@ -584,6 +862,41 @@
 }
 
 /*
+ * svcctl_s_StartService
+ */
+static int
+svcctl_s_StartService(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_StartService *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+	svcctl_manager_context_t *mgr_ctx;
+	svcctl_service_context_t *svc_ctx;
+	svcctl_svc_node_t *svc;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
+	mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
+	if (mgr_ctx == NULL) {
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
+	if (svc == NULL || svc->sn_fmri == NULL)
+		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
+	else
+		param->status = ERROR_SERVICE_ALREADY_RUNNING;
+	return (NDR_DRC_OK);
+}
+
+
+/*
  * svcctl_s_GetServiceDisplayNameW
  *
  * Returns:
@@ -678,6 +991,172 @@
 }
 
 /*
+ * svcctl_s_OpenSCManagerA
+ *
+ * Request to open the service control manager.
+ * The caller must have administrator rights in order to open this
+ * interface.  We don't support write (SC_MANAGER_LOCK) access.
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_ACCESS_DENIED
+ *
+ * On success, returns a handle for use with subsequent svcctl requests.
+ */
+static int
+svcctl_s_OpenSCManagerA(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_OpenSCManagerA *param = arg;
+	ndr_hdid_t *id = NULL;
+	int rc;
+
+	rc = ndr_is_admin(mxa);
+
+	if ((rc == 0) || (param->desired_access & SC_MANAGER_LOCK) != 0) {
+		bzero(&param->handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_ACCESS_DENIED;
+		return (NDR_DRC_OK);
+	}
+
+	id = svcctl_mgr_hdalloc(mxa);
+	if (id) {
+		bcopy(id, &param->handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_SUCCESS;
+	} else {
+		bzero(&param->handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_ACCESS_DENIED;
+	}
+
+	return (NDR_DRC_OK);
+}
+
+/*
+ * svcctl_s_OpenServiceA
+ *
+ * Return a handle for use with subsequent svcctl requests.
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_INVALID_HANDLE
+ *	ERROR_SERVICE_DOES_NOT_EXIST
+ *	ERROR_CALL_NOT_IMPLEMENTED
+ */
+static int
+svcctl_s_OpenServiceA(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_OpenServiceA *param = arg;
+	ndr_hdid_t *mgrid = (ndr_hdid_t *)&param->manager_handle;
+	ndr_hdid_t *id = NULL;
+	ndr_handle_t *hd;
+	DWORD status;
+	svcctl_manager_context_t *mgr_ctx;
+	char *svc_name = (char *)param->service_name->value;
+	boolean_t unimplemented_operations = B_FALSE;
+
+	/* Allow service handle allocations for only status & config queries */
+	unimplemented_operations =
+	    SVCCTL_OPENSVC_OP_UNIMPLEMENTED(param->desired_access);
+
+	if (unimplemented_operations) {
+		bzero(&param->service_handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_CALL_NOT_IMPLEMENTED;
+		return (NDR_DRC_OK);
+	}
+
+	hd = svcctl_hdlookup(mxa, mgrid, SVCCTL_MANAGER_CONTEXT);
+	if (hd == NULL) {
+		bzero(&param->service_handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
+	status = svcctl_scm_validate_service(mgr_ctx, svc_name);
+	if (status != ERROR_SUCCESS) {
+		bzero(&param->service_handle, sizeof (svcctl_handle_t));
+		param->status = status;
+		return (NDR_DRC_OK);
+	}
+
+	id = svcctl_svc_hdalloc(mxa, mgrid, svc_name);
+	if (id) {
+		bcopy(id, &param->service_handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_SUCCESS;
+	} else {
+		bzero(&param->service_handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_ACCESS_DENIED;
+	}
+
+	return (NDR_DRC_OK);
+}
+
+/*
+ * svcctl_s_EnumServicesStatusA
+ *
+ * Enumerate the list of services we support as ASCII.
+ */
+static int
+svcctl_s_EnumServicesStatusA(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_EnumServicesStatusA *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
+	ndr_handle_t *hd;
+	svcctl_manager_context_t *mgr_ctx;
+	uint32_t buf_size;
+	uint32_t svc_num;
+	uint32_t resume_handle = 0;
+	uint32_t status;
+
+	buf_size = param->buf_size;
+	if (param->resume_handle != NULL)
+		resume_handle = *param->resume_handle;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
+	if (hd == NULL) {
+		status = ERROR_INVALID_HANDLE;
+		goto enum_services_status_error;
+	}
+
+	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
+	if (svcctl_scm_refresh(mgr_ctx) != 0) {
+		status = ERROR_INVALID_HANDLE;
+		goto enum_services_status_error;
+	}
+
+	param->services = NDR_MALLOC(mxa, buf_size);
+	if (param->services == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto enum_services_status_error;
+	}
+	bzero(param->services, buf_size);
+
+	svc_num = svcctl_scm_enum_services(mgr_ctx, param->services,
+	    buf_size, &resume_handle, B_FALSE);
+
+	param->buf_size = buf_size;
+	param->svc_num = svc_num;
+
+	if (resume_handle != 0) {
+		if (param->resume_handle != NULL)
+			*param->resume_handle = resume_handle;
+		param->bytes_needed = mgr_ctx->mc_bytes_needed;
+		param->status = ERROR_MORE_DATA;
+	} else {
+		if (param->resume_handle)
+			*param->resume_handle = 0;
+		param->bytes_needed = 0;
+		param->status = ERROR_SUCCESS;
+	}
+	return (NDR_DRC_OK);
+
+enum_services_status_error:
+	bzero(param, sizeof (struct svcctl_EnumServicesStatusA));
+	param->services = NDR_STRDUP(mxa, "");
+	param->status = status;
+	return (NDR_DRC_OK);
+}
+
+/*
  * svcctl_s_QueryServiceConfig2W
  *
  * Returns:
@@ -741,7 +1220,7 @@
 
 		if (input_bufsize <= bytes_needed) {
 			param->bytes_needed = bytes_needed;
-			param->status = ERROR_MORE_DATA;
+			param->status = ERROR_INSUFFICIENT_BUFFER;
 			return (NDR_DRC_OK);
 		}
 
@@ -780,3 +1259,83 @@
 	param->status = ERROR_SUCCESS;
 	return (NDR_DRC_OK);
 }
+
+/*
+ * svcctl_s_QueryServiceStatusEx
+ */
+static int
+svcctl_s_QueryServiceStatusEx(void *arg, ndr_xa_t *mxa)
+{
+	struct svcctl_QueryServiceStatusEx *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+	svcctl_manager_context_t *mgr_ctx;
+	svcctl_service_context_t *svc_ctx;
+	svcctl_svc_node_t *svc;
+	svc_status_ex_t *svc_status_ex;
+	uint32_t input_bufsize;
+	uint32_t bytes_needed;
+	DWORD status;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		status = ERROR_INVALID_HANDLE;
+		goto query_service_status_ex_error;
+	}
+
+	svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
+	mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
+	if (mgr_ctx == NULL) {
+		status = ERROR_INVALID_HANDLE;
+		goto query_service_status_ex_error;
+	}
+
+	if (param->info_level != SC_STATUS_PROCESS_INFO) {
+		status = ERROR_INVALID_PARAMETER;
+		goto query_service_status_ex_error;
+	}
+
+	bytes_needed = sizeof (struct svcctl_QueryServiceStatusEx);
+
+	if ((input_bufsize = param->buf_size) < bytes_needed) {
+		bzero(param, sizeof (struct svcctl_QueryServiceStatusEx));
+		param->buf_size = input_bufsize;
+		param->buffer = NDR_STRDUP(mxa, "");
+		param->bytes_needed = bytes_needed;
+		param->status = ERROR_INSUFFICIENT_BUFFER;
+		return (NDR_DRC_OK);
+	}
+
+	if ((svc_status_ex = NDR_MALLOC(mxa, bytes_needed)) == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto query_service_status_ex_error;
+	}
+
+	svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
+	if (svc == NULL || svc->sn_state == NULL) {
+		status = ERROR_SERVICE_DOES_NOT_EXIST;
+		goto query_service_status_ex_error;
+	}
+
+	svc_status_ex->service_type = SERVICE_WIN32_SHARE_PROCESS;
+	svc_status_ex->cur_state = svcctl_scm_map_status(svc->sn_state);
+	svc_status_ex->ctrl_accepted = 0;
+	svc_status_ex->w32_exitcode = 0;
+	svc_status_ex->svc_specified_exitcode = 0;
+	svc_status_ex->check_point = 0;
+	svc_status_ex->wait_hint = 0;
+	svc_status_ex->process_id = 1;
+	svc_status_ex->service_flags = 1;
+
+	param->buffer = (uint8_t *)svc_status_ex;
+	param->buf_size = bytes_needed;
+	param->bytes_needed = 0;
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+
+query_service_status_ex_error:
+	bzero(param, sizeof (struct svcctl_QueryServiceStatusEx));
+	param->buffer = NDR_STRDUP(mxa, "");
+	param->status = status;
+	return (NDR_DRC_OK);
+}
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Tue Jun 30 08:31:17 2009 -0700
@@ -847,7 +847,7 @@
 int smb_kmod_nbtreceive(void);
 void smb_kmod_unbind(void);
 int smb_kmod_share(char *, char *);
-int smb_kmod_unshare(char *);
+int smb_kmod_unshare(char *, char *);
 int smb_kmod_get_usernum(uint32_t *);
 int smb_kmod_get_userlist(smb_ulist_t *);
 
--- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Tue Jun 30 08:31:17 2009 -0700
@@ -163,7 +163,7 @@
 }
 
 int
-smb_kmod_unshare(char *name)
+smb_kmod_unshare(char *path, char *name)
 {
 	smb_ioc_share_t *ioc;
 	int rc = ENOMEM;
@@ -171,6 +171,7 @@
 	ioc = malloc(sizeof (smb_ioc_share_t));
 
 	if (ioc != NULL) {
+		(void) strlcpy(ioc->path, path, sizeof (ioc->path));
 		(void) strlcpy(ioc->name, name, sizeof (ioc->name));
 		rc = smb_kmod_ioctl(SMB_IOC_UNSHARE, &ioc->hdr,
 		    sizeof (smb_ioc_share_t));
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c	Tue Jun 30 08:31:17 2009 -0700
@@ -2036,15 +2036,8 @@
 	if (smb_ads_get_spnset(fqhost, spn_set) != 0)
 		return (-1);
 
-	/*
-	 * Windows 2008 DC expects the UPN attribute to be host/fqhn while
-	 * both Windows 2000 & 2003 expect it to be host/fqhn@realm.
-	 */
-	if (dclevel >= SMB_ADS_DCLEVEL_W2K8)
-		user_principal = smb_krb5_get_spn(SMBKRB5_SPN_IDX_HOST, fqhost);
-	else
-		user_principal = smb_krb5_get_upn(spn_set[SMBKRB5_SPN_IDX_HOST],
-		    ah->domain);
+	user_principal = smb_krb5_get_upn(spn_set[SMBKRB5_SPN_IDX_HOST],
+	    ah->domain);
 
 	if (user_principal == NULL) {
 		smb_ads_free_spnset(spn_set);
@@ -2556,6 +2549,7 @@
 	 * the TRUSTED_FOR_DELEGATION userAccountControl flag.
 	 */
 	if (smb_ads_update_computer_cntrl_attr(ah,
+	    SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
 	    SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION, dn)
 	    == LDAP_INSUFFICIENT_ACCESS) {
 		usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Tue Jun 30 08:31:17 2009 -0700
@@ -41,6 +41,7 @@
 static uint32_t smb_open_subr(smb_request_t *);
 extern uint32_t smb_is_executable(char *);
 static void smb_delete_new_object(smb_request_t *);
+static int smb_set_open_timestamps(smb_request_t *, smb_ofile_t *, boolean_t);
 
 static char *smb_pathname_strdup(smb_request_t *, const char *);
 static char *smb_pathname_strcat(char *, const char *);
@@ -242,6 +243,8 @@
  * 1. The creator of a readonly file can write to/modify the size of the file
  * using the original create fid, even though the file will appear as readonly
  * to all other fids and via a CIFS getattr call.
+ * The readonly bit therefore cannot be set in the filesystem until the file
+ * is closed (smb_ofile_close). It is accounted for via ofile and node flags.
  *
  * 2. A setinfo operation (using either an open fid or a path) to set/unset
  * readonly will be successful regardless of whether a creator of a readonly
@@ -305,18 +308,17 @@
 	smb_error_t	err;
 	boolean_t	is_stream = B_FALSE;
 	int		lookup_flags = SMB_FOLLOW_LINKS;
-	uint32_t	daccess;
 	uint32_t	uniq_fid;
 	smb_pathname_t	*pn = &op->fqi.fq_path;
 
 	is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
 
+	/*
+	 * If the object being created or opened is a directory
+	 * the Disposition parameter must be one of FILE_CREATE,
+	 * FILE_OPEN, or FILE_OPEN_IF
+	 */
 	if (is_dir) {
-		/*
-		 * The object being created or opened is a directory,
-		 * and the Disposition parameter must be one of
-		 * FILE_CREATE, FILE_OPEN, or FILE_OPEN_IF
-		 */
 		if ((op->create_disposition != FILE_CREATE) &&
 		    (op->create_disposition != FILE_OPEN_IF) &&
 		    (op->create_disposition != FILE_OPEN)) {
@@ -430,19 +432,27 @@
 	 * and do not follow links.  Otherwise, follow
 	 * the link to the target.
 	 */
-	daccess = op->desired_access & ~FILE_READ_ATTRIBUTES;
-
-	if (daccess == DELETE)
+	if ((op->desired_access & ~FILE_READ_ATTRIBUTES) == DELETE)
 		lookup_flags &= ~SMB_FOLLOW_LINKS;
 
 	rc = smb_fsop_lookup_name(sr, kcred, lookup_flags,
 	    sr->tid_tree->t_snode, op->fqi.fq_dnode, op->fqi.fq_last_comp,
-	    &op->fqi.fq_fnode, &op->fqi.fq_fattr);
+	    &op->fqi.fq_fnode);
 
 	if (rc == 0) {
 		last_comp_found = B_TRUE;
 		(void) strcpy(op->fqi.fq_od_name,
 		    op->fqi.fq_fnode->od_name);
+		rc = smb_node_getattr(sr, op->fqi.fq_fnode,
+		    &op->fqi.fq_fattr);
+		if (rc != 0) {
+			smb_node_release(op->fqi.fq_fnode);
+			smb_node_release(op->fqi.fq_dnode);
+			SMB_NULL_FQI_NODES(op->fqi);
+			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+			    ERRDOS, ERROR_INTERNAL_ERROR);
+			return (sr->smb_error.status);
+		}
 	} else if (rc == ENOENT) {
 		last_comp_found = B_FALSE;
 		op->fqi.fq_fnode = NULL;
@@ -454,6 +464,7 @@
 		return (sr->smb_error.status);
 	}
 
+
 	/*
 	 * The uniq_fid is a CIFS-server-wide unique identifier for an ofile
 	 * which is used to uniquely identify open instances for the
@@ -541,7 +552,7 @@
 		 */
 		if (SMB_PATHFILE_IS_READONLY(sr, node)) {
 			/* Files data only */
-			if (node->attr.sa_vattr.va_type != VDIR) {
+			if (!smb_node_is_dir(node)) {
 				if (op->desired_access & (FILE_WRITE_DATA |
 				    FILE_APPEND_DATA)) {
 					smb_node_release(node);
@@ -566,7 +577,7 @@
 			if ((!(op->desired_access &
 			    (FILE_WRITE_DATA | FILE_APPEND_DATA |
 			    FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))) ||
-			    (!smb_sattr_check(node->attr.sa_dosattr,
+			    (!smb_sattr_check(op->fqi.fq_fattr.sa_dosattr,
 			    op->dattr))) {
 				smb_node_unlock(node);
 				smb_node_release(node);
@@ -615,7 +626,7 @@
 		case FILE_SUPERSEDE:
 		case FILE_OVERWRITE_IF:
 		case FILE_OVERWRITE:
-			if (node->attr.sa_vattr.va_type == VDIR) {
+			if (smb_node_is_dir(node)) {
 				smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
 				smb_node_unlock(node);
 				smb_node_release(node);
@@ -626,45 +637,35 @@
 				return (NT_STATUS_ACCESS_DENIED);
 			}
 
-			if (node->attr.sa_vattr.va_size != op->dsize) {
-				node->flags &= ~NODE_FLAGS_SET_SIZE;
-				bzero(&new_attr, sizeof (new_attr));
-				new_attr.sa_vattr.va_size = op->dsize;
-				new_attr.sa_mask = SMB_AT_SIZE;
-
-				rc = smb_fsop_setattr(sr, sr->user_cr,
-				    node, &new_attr, &op->fqi.fq_fattr);
-
-				if (rc) {
-					smb_fsop_unshrlock(sr->user_cr, node,
-					    uniq_fid);
-					smb_node_unlock(node);
-					smb_node_release(node);
-					smb_node_release(dnode);
-					SMB_NULL_FQI_NODES(op->fqi);
-					smbsr_errno(sr, rc);
-					return (sr->smb_error.status);
-				}
-
-				op->dsize = op->fqi.fq_fattr.sa_vattr.va_size;
-			}
-
 			op->dattr |= FILE_ATTRIBUTE_ARCHIVE;
+			/* Don't apply readonly bit until smb_ofile_close */
 			if (op->dattr & FILE_ATTRIBUTE_READONLY) {
 				op->created_readonly = B_TRUE;
 				op->dattr &= ~FILE_ATTRIBUTE_READONLY;
 			}
 
-			smb_node_set_dosattr(node, op->dattr);
-			(void) smb_sync_fsattr(sr, sr->user_cr, node);
+			bzero(&new_attr, sizeof (new_attr));
+			new_attr.sa_dosattr = op->dattr;
+			new_attr.sa_vattr.va_size = op->dsize;
+			new_attr.sa_mask = SMB_AT_DOSATTR | SMB_AT_SIZE;
+			rc = smb_fsop_setattr(sr, sr->user_cr, node, &new_attr);
+			if (rc != 0) {
+				smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
+				smb_node_unlock(node);
+				smb_node_release(node);
+				smb_node_release(dnode);
+				SMB_NULL_FQI_NODES(op->fqi);
+				smbsr_errno(sr, rc);
+				return (sr->smb_error.status);
+			}
 
 			/*
-			 * If file is being replaced,
-			 * we should remove existing streams
+			 * If file is being replaced, remove existing streams
 			 */
 			if (SMB_IS_STREAM(node) == 0) {
-				if (smb_fsop_remove_streams(sr, sr->user_cr,
-				    node) != 0) {
+				rc = smb_fsop_remove_streams(sr, sr->user_cr,
+				    node);
+				if (rc != 0) {
 					smb_fsop_unshrlock(sr->user_cr, node,
 					    uniq_fid);
 					smb_node_unlock(node);
@@ -716,22 +717,13 @@
 		 */
 		smb_node_wrlock(dnode);
 
-		bzero(&new_attr, sizeof (new_attr));
-		new_attr.sa_dosattr = op->dattr;
-		new_attr.sa_mask |= SMB_AT_DOSATTR;
+		/* Don't apply readonly bit until smb_ofile_close */
+		if (op->dattr & FILE_ATTRIBUTE_READONLY) {
+			op->dattr &= ~FILE_ATTRIBUTE_READONLY;
+			op->created_readonly = B_TRUE;
+		}
 
-		/*
-		 * A file created with the readonly bit should not
-		 * stop the creator writing to the file until it is
-		 * closed.  Although the readonly bit will not be set
-		 * on the file until it is closed, it will be accounted
-		 * for on other fids and on queries based on the node
-		 * state.
-		 */
-		if (op->dattr & FILE_ATTRIBUTE_READONLY)
-			new_attr.sa_dosattr &= ~FILE_ATTRIBUTE_READONLY;
-
-
+		bzero(&new_attr, sizeof (new_attr));
 		if ((op->crtime.tv_sec != 0) &&
 		    (op->crtime.tv_sec != UINT_MAX)) {
 
@@ -740,12 +732,14 @@
 		}
 
 		if (is_dir == 0) {
-			new_attr.sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
+			op->dattr |= FILE_ATTRIBUTE_ARCHIVE;
+			new_attr.sa_dosattr = op->dattr;
 			new_attr.sa_vattr.va_type = VREG;
 			new_attr.sa_vattr.va_mode = is_stream ? S_IRUSR :
 			    S_IRUSR | S_IRGRP | S_IROTH |
 			    S_IWUSR | S_IWGRP | S_IWOTH;
-			new_attr.sa_mask |= SMB_AT_TYPE | SMB_AT_MODE;
+			new_attr.sa_mask |=
+			    SMB_AT_DOSATTR | SMB_AT_TYPE | SMB_AT_MODE;
 
 			if (op->dsize) {
 				new_attr.sa_vattr.va_size = op->dsize;
@@ -753,8 +747,7 @@
 			}
 
 			rc = smb_fsop_create(sr, sr->user_cr, dnode,
-			    op->fqi.fq_last_comp, &new_attr,
-			    &op->fqi.fq_fnode, &op->fqi.fq_fattr);
+			    op->fqi.fq_last_comp, &new_attr, &op->fqi.fq_fnode);
 
 			if (rc != 0) {
 				smb_node_unlock(dnode);
@@ -765,9 +758,6 @@
 			}
 
 			node = op->fqi.fq_fnode;
-
-			op->fqi.fq_fattr = node->attr;
-
 			smb_node_wrlock(node);
 
 			status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
@@ -775,8 +765,7 @@
 
 			if (status == NT_STATUS_SHARING_VIOLATION) {
 				smb_node_unlock(node);
-				if (created)
-					smb_delete_new_object(sr);
+				smb_delete_new_object(sr);
 				smb_node_release(node);
 				smb_node_unlock(dnode);
 				smb_node_release(dnode);
@@ -785,13 +774,14 @@
 			}
 		} else {
 			op->dattr |= FILE_ATTRIBUTE_DIRECTORY;
+			new_attr.sa_dosattr = op->dattr;
 			new_attr.sa_vattr.va_type = VDIR;
 			new_attr.sa_vattr.va_mode = 0777;
-			new_attr.sa_mask |= SMB_AT_TYPE | SMB_AT_MODE;
+			new_attr.sa_mask |=
+			    SMB_AT_DOSATTR | SMB_AT_TYPE | SMB_AT_MODE;
 
 			rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
-			    op->fqi.fq_last_comp, &new_attr,
-			    &op->fqi.fq_fnode, &op->fqi.fq_fattr);
+			    op->fqi.fq_last_comp, &new_attr, &op->fqi.fq_fnode);
 			if (rc != 0) {
 				smb_node_unlock(dnode);
 				smb_node_release(dnode);
@@ -807,35 +797,59 @@
 		created = B_TRUE;
 		op->action_taken = SMB_OACT_CREATED;
 		node->flags |= NODE_FLAGS_CREATED;
-
-		if (op->dattr & FILE_ATTRIBUTE_READONLY) {
-			op->created_readonly = B_TRUE;
-			op->dattr &= ~FILE_ATTRIBUTE_READONLY;
-		}
 	}
 
-	op->dattr = smb_node_get_dosattr(node);
-
 	if (max_requested) {
 		smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed);
 		op->desired_access |= max_allowed;
 	}
 
-	/*
-	 * if last_write time was in request and is not 0 or -1,
-	 * use it as file's mtime
-	 */
-	if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) {
-		smb_node_set_time(node, NULL, &op->mtime, NULL, NULL,
-		    SMB_AT_MTIME);
-		(void) smb_sync_fsattr(sr, sr->user_cr, node);
-	}
+	status = NT_STATUS_SUCCESS;
 
 	of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op, SMB_FTYPE_DISK,
 	    uniq_fid, &err);
+	if (of == NULL) {
+		smbsr_error(sr, err.status, err.errcls, err.errcode);
+		status = err.status;
+	}
 
-	if (of == NULL) {
-		smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
+	if (status == NT_STATUS_SUCCESS) {
+		if (!smb_tree_is_connected(sr->tid_tree)) {
+			smbsr_error(sr, 0, ERRSRV, ERRinvnid);
+			status = NT_STATUS_UNSUCCESSFUL;
+		}
+	}
+
+	/*
+	 * This MUST be done after ofile creation, so that explicitly
+	 * set timestamps can be remembered on the ofile.
+	 */
+	if (status == NT_STATUS_SUCCESS) {
+		if ((rc = smb_set_open_timestamps(sr, of, created)) != 0) {
+			smbsr_errno(sr, rc);
+			status = sr->smb_error.status;
+		}
+	}
+
+	if (status == NT_STATUS_SUCCESS) {
+		if (smb_node_getattr(sr, node,  &op->fqi.fq_fattr) != 0) {
+			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+			    ERRDOS, ERROR_INTERNAL_ERROR);
+			status = NT_STATUS_INTERNAL_ERROR;
+		}
+	}
+
+	/*
+	 * smb_fsop_unshrlock is a no-op if node is a directory
+	 * smb_fsop_unshrlock is done in smb_ofile_close
+	 */
+	if (status != NT_STATUS_SUCCESS) {
+		if (of == NULL) {
+			smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
+		} else {
+			smb_ofile_close(of, 0);
+			smb_ofile_release(of);
+		}
 		if (created)
 			smb_delete_new_object(sr);
 		smb_node_unlock(node);
@@ -844,23 +858,7 @@
 			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 (!smb_tree_is_connected(sr->tid_tree)) {
-		smb_ofile_close(of, 0);
-		smb_ofile_release(of);
-		if (created)
-			smb_delete_new_object(sr);
-		smb_node_unlock(node);
-		smb_node_release(node);
-		if (created)
-			smb_node_unlock(dnode);
-		smb_node_release(dnode);
-		SMB_NULL_FQI_NODES(op->fqi);
-		smbsr_error(sr, 0, ERRSRV, ERRinvnid);
-		return (NT_STATUS_UNSUCCESSFUL);
+		return (status);
 	}
 
 	/*
@@ -871,7 +869,11 @@
 	    (op->create_options & FILE_WRITE_THROUGH))
 		node->flags |= NODE_FLAGS_WRITE_THROUGH;
 
+	/*
+	 * Set up the fileid and dosattr in open_param for response
+	 */
 	op->fileid = op->fqi.fq_fattr.sa_vattr.va_nodeid;
+	op->dattr = op->fqi.fq_fattr.sa_dosattr;
 
 	/*
 	 * Set up the file type in open_param for the response
@@ -900,6 +902,64 @@
 }
 
 /*
+ * smb_set_open_timestamps
+ *
+ * Last write time:
+ * - If the last_write time specified in the open params is not 0 or -1,
+ *   use it as file's mtime. This will be considered an explicitly set
+ *   timestamps, not reset by subsequent writes.
+ *
+ * Opening existing file (not directory):
+ * - If opening an existing file for overwrite set initial ATIME, MTIME
+ *   & CTIME to now. (This is achieved by setting them as pending then forcing
+ *   an smb_node_setattr() to apply pending times.)
+ *
+ * - Note  If opening an existing file NOT for overwrite, windows would
+ *   set the atime on file close, however setting the atime would cause
+ *   the ARCHIVE attribute to be set, which does not occur on windows,
+ *   so we do not do the atime update.
+ *
+ * Returns: errno
+ */
+static int
+smb_set_open_timestamps(smb_request_t *sr, smb_ofile_t *of, boolean_t created)
+{
+	int		rc = 0;
+	open_param_t	*op = &sr->arg.open;
+	smb_node_t	*node = of->f_node;
+	boolean_t	existing_file, set_times;
+	smb_attr_t	attr;
+
+	bzero(&attr, sizeof (smb_attr_t));
+	set_times = B_FALSE;
+
+	if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) {
+		attr.sa_mask = SMB_AT_MTIME;
+		attr.sa_vattr.va_mtime = op->mtime;
+		set_times = B_TRUE;
+	}
+
+	existing_file = !(created || smb_node_is_dir(node));
+	if (existing_file) {
+		switch (op->create_disposition) {
+		case FILE_SUPERSEDE:
+		case FILE_OVERWRITE_IF:
+		case FILE_OVERWRITE:
+			smb_ofile_set_write_time_pending(of);
+			set_times = B_TRUE;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (set_times)
+		rc = smb_node_setattr(sr, node, sr->user_cr, of, &attr);
+
+	return (rc);
+}
+
+/*
  * smb_validate_object_name
  *
  * Very basic file name validation.
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c	Tue Jun 30 08:31:17 2009 -0700
@@ -32,7 +32,7 @@
 static int smb_delete_single_file(smb_request_t *, smb_error_t *);
 static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
 static int smb_delete_find_fname(smb_request_t *, smb_odir_t *);
-static int smb_delete_check_attr(smb_request_t *, smb_error_t *);
+static int smb_delete_check_dosattr(smb_request_t *, smb_error_t *);
 static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
 
 static void smb_delete_error(smb_error_t *, uint32_t, uint16_t, uint16_t);
@@ -219,7 +219,6 @@
 smb_delete_single_file(smb_request_t *sr, smb_error_t *err)
 {
 	smb_fqi_t *fqi;
-	smb_attr_t ret_attr;
 	uint32_t status;
 
 	fqi = &sr->arg.dirop.fqi;
@@ -232,13 +231,13 @@
 	}
 
 	if (smb_fsop_lookup_name(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
-	    fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode, &ret_attr) != 0) {
+	    fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode) != 0) {
 		smb_delete_error(err, NT_STATUS_OBJECT_NAME_NOT_FOUND,
 		    ERRDOS, ERROR_FILE_NOT_FOUND);
 		return (-1);
 	}
 
-	if (smb_delete_check_attr(sr, err) != 0) {
+	if (smb_delete_check_dosattr(sr, err) != 0) {
 		smb_node_release(fqi->fq_fnode);
 		return (-1);
 	}
@@ -263,7 +262,7 @@
  *    - The search ends (but not an error) if a directory is
  *      matched and the request's search did not include
  *      directories.
- *    - Otherwise, if smb_delete_check_attr fails the file
+ *    - Otherwise, if smb_delete_check_dosattr fails the file
  *      is skipped and the search continues (at step 1)
  * 3. delete the file
  *
@@ -275,7 +274,6 @@
 {
 	int rc, deleted = 0;
 	smb_fqi_t *fqi;
-	smb_attr_t ret_attr;
 	uint16_t odid;
 	smb_odir_t *od;
 
@@ -283,7 +281,7 @@
 
 	/*
 	 * Specify all search attributes (SMB_SEARCH_ATTRIBUTES) so that
-	 * delete-specific checking can be done (smb_delete_check_attr).
+	 * delete-specific checking can be done (smb_delete_check_dosattr).
 	 */
 	odid = smb_odir_open(sr, fqi->fq_path.pn_path,
 	    SMB_SEARCH_ATTRIBUTES, 0);
@@ -300,11 +298,11 @@
 
 		rc = smb_fsop_lookup_name(sr, sr->user_cr, 0,
 		    sr->tid_tree->t_snode, fqi->fq_dnode,
-		    fqi->fq_od_name, &fqi->fq_fnode, &ret_attr);
+		    fqi->fq_od_name, &fqi->fq_fnode);
 		if (rc != 0)
 			break;
 
-		if (smb_delete_check_attr(sr, err) != 0) {
+		if (smb_delete_check_dosattr(sr, err) != 0) {
 			smb_node_release(fqi->fq_fnode);
 			if (err->status == NT_STATUS_CANNOT_DELETE) {
 				smb_odir_close(od);
@@ -406,7 +404,7 @@
 }
 
 /*
- * smb_delete_check_attr
+ * smb_delete_check_dosattr
  *
  * Check file's dos atributes to ensure that
  * 1. the file is not a directory - NT_STATUS_FILE_IS_A_DIRECTORY
@@ -419,18 +417,24 @@
  *         -1 - err populated with error details
  */
 static int
-smb_delete_check_attr(smb_request_t *sr, smb_error_t *err)
+smb_delete_check_dosattr(smb_request_t *sr, smb_error_t *err)
 {
 	smb_fqi_t *fqi;
 	smb_node_t *node;
-	uint16_t dosattr, sattr;
+	smb_attr_t attr;
+	uint16_t sattr;
 
 	fqi = &sr->arg.dirop.fqi;
 	sattr = fqi->fq_sattr;
 	node = fqi->fq_fnode;
-	dosattr = smb_node_get_dosattr(node);
 
-	if (dosattr & FILE_ATTRIBUTE_DIRECTORY) {
+	if (smb_node_getattr(sr, node, &attr) != 0) {
+		smb_delete_error(err, NT_STATUS_INTERNAL_ERROR,
+		    ERRDOS, ERROR_INTERNAL_ERROR);
+		return (-1);
+	}
+
+	if (attr.sa_dosattr & FILE_ATTRIBUTE_DIRECTORY) {
 		smb_delete_error(err, NT_STATUS_FILE_IS_A_DIRECTORY,
 		    ERRDOS, ERROR_ACCESS_DENIED);
 		return (-1);
@@ -442,13 +446,15 @@
 		return (-1);
 	}
 
-	if ((dosattr & FILE_ATTRIBUTE_HIDDEN) && !(SMB_SEARCH_HIDDEN(sattr))) {
+	if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
+	    !(SMB_SEARCH_HIDDEN(sattr))) {
 		smb_delete_error(err, NT_STATUS_NO_SUCH_FILE,
 		    ERRDOS, ERROR_FILE_NOT_FOUND);
 		return (-1);
 	}
 
-	if ((dosattr & FILE_ATTRIBUTE_SYSTEM) && !(SMB_SEARCH_SYSTEM(sattr))) {
+	if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
+	    !(SMB_SEARCH_SYSTEM(sattr))) {
 		smb_delete_error(err, NT_STATUS_NO_SUCH_FILE,
 		    ERRDOS, ERROR_FILE_NOT_FOUND);
 		return (-1);
--- a/usr/src/uts/common/fs/smbsrv/smb_directory.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_directory.c	Tue Jun 30 08:31:17 2009 -0700
@@ -228,14 +228,19 @@
 
 	if ((rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
 	    sr->arg.dirop.fqi.fq_last_comp, &new_attr,
-	    &sr->arg.dirop.fqi.fq_fnode,
-	    &sr->arg.dirop.fqi.fq_fattr)) != 0) {
+	    &sr->arg.dirop.fqi.fq_fnode)) != 0) {
 		smb_node_release(dnode);
 		SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
 		return (rc);
 	}
 
 	node = sr->arg.dirop.fqi.fq_fnode;
+	rc = smb_node_getattr(sr, node, &sr->arg.dirop.fqi.fq_fattr);
+	if (rc != 0) {
+		smb_node_release(dnode);
+		SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+		return (rc);
+	}
 	node->flags |= NODE_FLAGS_CREATED;
 
 	sr->arg.open.create_options = FILE_DIRECTORY_FILE;
@@ -393,7 +398,7 @@
 	rc = smb_fsop_access(sr, sr->user_cr, dnode, DELETE);
 
 	if ((rc != NT_STATUS_SUCCESS) ||
-	    (dnode->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
+	    attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) {
 		smb_node_release(dnode);
 		smb_node_release(sr->arg.dirop.fqi.fq_dnode);
 		SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Tue Jun 30 08:31:17 2009 -0700
@@ -43,13 +43,13 @@
 extern int smb_vop_other_opens(vnode_t *, int);
 
 static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *,
-    char *, char *, int, smb_attr_t *, smb_node_t **, smb_attr_t *);
+    char *, char *, int, smb_attr_t *, smb_node_t **);
 
 static int smb_fsop_create_file(smb_request_t *, cred_t *, smb_node_t *,
-    char *, int, smb_attr_t *, smb_node_t **, smb_attr_t *);
+    char *, int, smb_attr_t *, smb_node_t **);
 
 static int smb_fsop_create_with_sd(smb_request_t *, cred_t *, smb_node_t *,
-    char *, smb_attr_t *, smb_node_t **, smb_attr_t *, smb_fssd_t *);
+    char *, smb_attr_t *, smb_node_t **, smb_fssd_t *);
 
 static int smb_fsop_sdinherit(smb_request_t *, smb_node_t *, smb_fssd_t *);
 
@@ -152,8 +152,7 @@
 static int
 smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr,
     smb_node_t *dnode, char *name,
-    smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr,
-    smb_fssd_t *fs_sd)
+    smb_attr_t *attr, smb_node_t **ret_snode, smb_fssd_t *fs_sd)
 {
 	vsecattr_t *vsap;
 	vsecattr_t vsecattr;
@@ -243,7 +242,7 @@
 
 		if (rc == 0) {
 			*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
-			    name, dnode, NULL, ret_attr);
+			    name, dnode, NULL);
 
 			if (*ret_snode == NULL)
 				rc = ENOMEM;
@@ -272,7 +271,7 @@
 			return (rc);
 
 		*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
-		    name, dnode, NULL, ret_attr);
+		    name, dnode, NULL);
 
 		if (*ret_snode != NULL) {
 			if (!smb_tree_has_feature(sr->tid_tree,
@@ -308,9 +307,8 @@
  * taken if an error is returned.
  */
 int
-smb_fsop_create(smb_request_t *sr, cred_t *cr,
-    smb_node_t *dnode, char *name,
-    smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr)
+smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
+    char *name, smb_attr_t *attr, smb_node_t **ret_snode)
 {
 	int	rc = 0;
 	int	flags = 0;
@@ -349,7 +347,7 @@
 		smb_stream_parse_name(name, fname, sname);
 
 		rc = smb_fsop_create_stream(sr, cr, dnode,
-		    fname, sname, flags, attr, ret_snode, ret_attr);
+		    fname, sname, flags, attr, ret_snode);
 
 		kmem_free(fname, MAXNAMELEN);
 		kmem_free(sname, MAXNAMELEN);
@@ -370,7 +368,7 @@
 	}
 
 	rc = smb_fsop_create_file(sr, cr, dnode, name, flags,
-	    attr, ret_snode, ret_attr);
+	    attr, ret_snode);
 	return (rc);
 
 }
@@ -397,7 +395,7 @@
 static int
 smb_fsop_create_stream(smb_request_t *sr, cred_t *cr,
     smb_node_t *dnode, char *fname, char *sname, int flags,
-    smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr)
+    smb_attr_t *attr, smb_node_t **ret_snode)
 {
 	smb_node_t	*fnode;
 	smb_attr_t	fattr;
@@ -408,19 +406,23 @@
 
 	/* Look up / create the unnamed stream, fname */
 	rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
-	    sr->tid_tree->t_snode, dnode, fname,
-	    &fnode, &fattr);
+	    sr->tid_tree->t_snode, dnode, fname, &fnode);
 	if (rc == ENOENT) {
 		fcreate = B_TRUE;
 		rc = smb_fsop_create_file(sr, cr, dnode, fname, flags,
-		    attr, &fnode, &fattr);
+		    attr, &fnode);
 	}
 	if (rc != 0)
 		return (rc);
 
-	/* create the named stream, sname */
-	rc = smb_vop_stream_create(fnode->vp, sname, attr, &vp,
-	    &xattrdvp, flags, cr);
+	fattr.sa_mask = SMB_AT_UID | SMB_AT_GID;
+	rc = smb_vop_getattr(fnode->vp, NULL, &fattr, 0, kcred);
+
+	if (rc == 0) {
+		/* create the named stream, sname */
+		rc = smb_vop_stream_create(fnode->vp, sname, attr,
+		    &vp, &xattrdvp, flags, cr);
+	}
 	if (rc != 0) {
 		if (fcreate) {
 			flags &= ~SMB_IGNORE_CASE;
@@ -442,7 +444,7 @@
 	}
 
 	*ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdvp,
-	    vp, sname, ret_attr);
+	    vp, sname);
 
 	smb_node_release(fnode);
 	VN_RELE(xattrdvp);
@@ -460,7 +462,7 @@
 static int
 smb_fsop_create_file(smb_request_t *sr, cred_t *cr,
     smb_node_t *dnode, char *name, int flags,
-    smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr)
+    smb_attr_t *attr, smb_node_t **ret_snode)
 {
 	open_param_t	*op = &sr->arg.open;
 	vnode_t		*vp;
@@ -480,7 +482,7 @@
 		status = smb_sd_tofs(op->sd, &fs_sd);
 		if (status == NT_STATUS_SUCCESS) {
 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
-			    name, attr, ret_snode, ret_attr, &fs_sd);
+			    name, attr, ret_snode, &fs_sd);
 		} else {
 			rc = EINVAL;
 		}
@@ -495,7 +497,7 @@
 		rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
 		if (rc == 0) {
 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
-			    name, attr, ret_snode, ret_attr, &fs_sd);
+			    name, attr, ret_snode, &fs_sd);
 		}
 
 		smb_fssd_term(&fs_sd);
@@ -509,7 +511,7 @@
 
 		if (rc == 0) {
 			*ret_snode = smb_node_lookup(sr, op, cr, vp,
-			    name, dnode, NULL, ret_attr);
+			    name, dnode, NULL);
 
 			if (*ret_snode == NULL)
 				rc = ENOMEM;
@@ -541,8 +543,7 @@
     smb_node_t *dnode,
     char *name,
     smb_attr_t *attr,
-    smb_node_t **ret_snode,
-    smb_attr_t *ret_attr)
+    smb_node_t **ret_snode)
 {
 	struct open_param *op = &sr->arg.open;
 	char *longname;
@@ -609,7 +610,7 @@
 		status = smb_sd_tofs(op->sd, &fs_sd);
 		if (status == NT_STATUS_SUCCESS) {
 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
-			    name, attr, ret_snode, ret_attr, &fs_sd);
+			    name, attr, ret_snode, &fs_sd);
 		}
 		else
 			rc = EINVAL;
@@ -624,7 +625,7 @@
 		rc = smb_fsop_sdinherit(sr, dnode, &fs_sd);
 		if (rc == 0) {
 			rc = smb_fsop_create_with_sd(sr, cr, dnode,
-			    name, attr, ret_snode, ret_attr, &fs_sd);
+			    name, attr, ret_snode, &fs_sd);
 		}
 
 		smb_fssd_term(&fs_sd);
@@ -635,7 +636,7 @@
 
 		if (rc == 0) {
 			*ret_snode = smb_node_lookup(sr, op, cr, vp, name,
-			    dnode, NULL, ret_attr);
+			    dnode, NULL);
 
 			if (*ret_snode == NULL)
 				rc = ENOMEM;
@@ -668,7 +669,6 @@
     uint32_t		flags)
 {
 	smb_node_t	*fnode;
-	smb_attr_t	file_attr;
 	char		*longname;
 	char		*fname;
 	char		*sname;
@@ -706,8 +706,7 @@
 		 */
 
 		rc = smb_fsop_lookup(sr, cr, flags | SMB_FOLLOW_LINKS,
-		    sr->tid_tree->t_snode, dnode, fname,
-		    &fnode, &file_attr);
+		    sr->tid_tree->t_snode, dnode, fname, &fnode);
 
 		if (rc != 0) {
 			kmem_free(fname, MAXNAMELEN);
@@ -917,7 +916,8 @@
 	    SMB_TREE_HAS_ACCESS(sr, ACE_READ_ATTRIBUTES) == 0)
 		return (EACCES);
 
-	if (sr->fid_ofile) {
+	/* sr could be NULL in some cases */
+	if (sr && sr->fid_ofile) {
 		/* if uid and/or gid is requested */
 		if (attr->sa_mask & (SMB_AT_UID|SMB_AT_GID))
 			access |= READ_CONTROL;
@@ -944,9 +944,6 @@
 	}
 
 	rc = smb_vop_getattr(snode->vp, unnamed_vp, attr, flags, cr);
-	if (rc == 0)
-		snode->attr = *attr;
-
 	return (rc);
 }
 
@@ -1029,7 +1026,6 @@
     char *to_name)
 {
 	smb_node_t *from_snode;
-	smb_attr_t tmp_attr;
 	vnode_t *from_vp;
 	int flags = 0, ret_flags;
 	int rc;
@@ -1095,7 +1091,7 @@
 
 	if (rc == 0) {
 		from_snode = smb_node_lookup(sr, NULL, cr, from_vp, from_name,
-		    from_dnode, NULL, &tmp_attr);
+		    from_dnode, NULL);
 
 		if (from_snode == NULL) {
 			rc = ENOMEM;
@@ -1128,8 +1124,7 @@
     smb_request_t	*sr,
     cred_t		*cr,
     smb_node_t		*snode,
-    smb_attr_t		*set_attr,
-    smb_attr_t		*ret_attr)
+    smb_attr_t		*set_attr)
 {
 	smb_node_t *unnamed_node;
 	vnode_t *unnamed_vp = NULL;
@@ -1200,19 +1195,6 @@
 	}
 
 	rc = smb_vop_setattr(snode->vp, unnamed_vp, set_attr, flags, cr);
-
-	if ((rc == 0) && ret_attr) {
-		/*
-		 * Use kcred to update the node attr because this
-		 * call is not being made on behalf of the user.
-		 */
-		ret_attr->sa_mask = SMB_AT_ALL;
-		rc = smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, flags,
-		    kcred);
-		if (rc == 0)
-			snode->attr = *ret_attr;
-	}
-
 	return (rc);
 }
 
@@ -1227,15 +1209,8 @@
  * It is assumed that a reference exists on snode coming into this routine.
  */
 int
-smb_fsop_read(
-    struct smb_request *sr,
-    cred_t *cr,
-    smb_node_t *snode,
-    uio_t *uio,
-    smb_attr_t *ret_attr)
+smb_fsop_read(smb_request_t *sr, cred_t *cr, smb_node_t *snode, uio_t *uio)
 {
-	smb_node_t *unnamed_node;
-	vnode_t *unnamed_vp = NULL;
 	caller_context_t ct;
 	int svmand;
 	int rc;
@@ -1258,19 +1233,14 @@
 			return (EACCES);
 	}
 
-	unnamed_node = SMB_IS_STREAM(snode);
-	if (unnamed_node) {
-		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
-		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
-		unnamed_vp = unnamed_node->vp;
-		/*
-		 * Streams permission are checked against the unnamed stream,
-		 * but in FS level they have their own permissions. To avoid
-		 * rejection by FS due to lack of permission on the actual
-		 * extended attr kcred is passed for streams.
-		 */
+	/*
+	 * Streams permission are checked against the unnamed stream,
+	 * but in FS level they have their own permissions. To avoid
+	 * rejection by FS due to lack of permission on the actual
+	 * extended attr kcred is passed for streams.
+	 */
+	if (SMB_IS_STREAM(snode))
 		cr = kcred;
-	}
 
 	smb_node_start_crit(snode, RW_READER);
 	rc = nbl_svmand(snode->vp, kcred, &svmand);
@@ -1288,20 +1258,8 @@
 		smb_node_end_crit(snode);
 		return (ERANGE);
 	}
+
 	rc = smb_vop_read(snode->vp, uio, cr);
-
-	if (rc == 0 && ret_attr) {
-		/*
-		 * Use kcred to update the node attr because this
-		 * call is not being made on behalf of the user.
-		 */
-		ret_attr->sa_mask = SMB_AT_ALL;
-		if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
-		    kcred) == 0) {
-			snode->attr = *ret_attr;
-		}
-	}
-
 	smb_node_end_crit(snode);
 
 	return (rc);
@@ -1321,11 +1279,8 @@
     smb_node_t *snode,
     uio_t *uio,
     uint32_t *lcount,
-    smb_attr_t *ret_attr,
     int ioflag)
 {
-	smb_node_t *unnamed_node;
-	vnode_t *unnamed_vp = NULL;
 	caller_context_t ct;
 	int svmand;
 	int rc;
@@ -1353,20 +1308,14 @@
 			return (EACCES);
 	}
 
-	unnamed_node = SMB_IS_STREAM(snode);
-
-	if (unnamed_node) {
-		ASSERT(unnamed_node->n_magic == SMB_NODE_MAGIC);
-		ASSERT(unnamed_node->n_state != SMB_NODE_STATE_DESTROYING);
-		unnamed_vp = unnamed_node->vp;
-		/*
-		 * Streams permission are checked against the unnamed stream,
-		 * but in FS level they have their own permissions. To avoid
-		 * rejection by FS due to lack of permission on the actual
-		 * extended attr kcred is passed for streams.
-		 */
+	/*
+	 * Streams permission are checked against the unnamed stream,
+	 * but in FS level they have their own permissions. To avoid
+	 * rejection by FS due to lack of permission on the actual
+	 * extended attr kcred is passed for streams.
+	 */
+	if (SMB_IS_STREAM(snode))
 		cr = kcred;
-	}
 
 	smb_node_start_crit(snode, RW_READER);
 	rc = nbl_svmand(snode->vp, kcred, &svmand);
@@ -1384,20 +1333,8 @@
 		smb_node_end_crit(snode);
 		return (ERANGE);
 	}
+
 	rc = smb_vop_write(snode->vp, uio, ioflag, lcount, cr);
-
-	if (rc == 0 && ret_attr) {
-		/*
-		 * Use kcred to update the node attr because this
-		 * call is not being made on behalf of the user.
-		 */
-		ret_attr->sa_mask = SMB_AT_ALL;
-		if (smb_vop_getattr(snode->vp, unnamed_vp, ret_attr, 0,
-		    kcred) == 0) {
-			snode->attr = *ret_attr;
-		}
-	}
-
 	smb_node_end_crit(snode);
 
 	return (rc);
@@ -1504,7 +1441,7 @@
 
 	/* Links don't have ACL */
 	if ((!smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) ||
-	    (snode->attr.sa_vattr.va_type == VLNK))
+	    smb_node_is_link(snode))
 		acl_check = B_FALSE;
 
 	/*
@@ -1556,11 +1493,9 @@
     smb_node_t	*root_node,
     smb_node_t	*dnode,
     char	*name,
-    smb_node_t	**ret_snode,
-    smb_attr_t	*ret_attr)
+    smb_node_t	**ret_snode)
 {
 	smb_node_t	*fnode;
-	smb_attr_t	file_attr;
 	vnode_t		*xattrdirvp;
 	vnode_t		*vp;
 	char		*od_name;
@@ -1591,8 +1526,8 @@
 		 * Unmangle processing will be done on fname
 		 * as well as any link target.
 		 */
-		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, fname,
-		    &fnode, &file_attr);
+		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode,
+		    fname, &fnode);
 
 		if (rc != 0) {
 			kmem_free(fname, MAXNAMELEN);
@@ -1623,7 +1558,7 @@
 		}
 
 		*ret_snode = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
-		    vp, od_name, ret_attr);
+		    vp, od_name);
 
 		kmem_free(od_name, MAXNAMELEN);
 		smb_node_release(fnode);
@@ -1637,7 +1572,7 @@
 		}
 	} else {
 		rc = smb_fsop_lookup(sr, cr, flags, root_node, dnode, name,
-		    ret_snode, ret_attr);
+		    ret_snode);
 	}
 
 	if (rc == 0) {
@@ -1685,8 +1620,7 @@
     smb_node_t	*root_node,
     smb_node_t	*dnode,
     char	*name,
-    smb_node_t	**ret_snode,
-    smb_attr_t	*ret_attr)
+    smb_node_t	**ret_snode)
 {
 	smb_node_t *lnk_target_node;
 	smb_node_t *lnk_dnode;
@@ -1794,11 +1728,9 @@
 
 		if (lnk_target_node->vp == vp) {
 			*ret_snode = lnk_target_node;
-			*ret_attr = (*ret_snode)->attr;
 		} else {
 			*ret_snode = smb_node_lookup(sr, NULL, cr, vp,
-			    lnk_target_node->od_name, lnk_dnode, NULL,
-			    ret_attr);
+			    lnk_target_node->od_name, lnk_dnode, NULL);
 			VN_RELE(vp);
 
 			if (*ret_snode == NULL)
@@ -1818,7 +1750,7 @@
 		}
 
 		*ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
-		    dnode, NULL, ret_attr);
+		    dnode, NULL);
 		VN_RELE(vp);
 
 		if (*ret_snode == NULL)
@@ -2229,8 +2161,7 @@
 		orig_attr.sa_mask = SMB_AT_UID | SMB_AT_GID;
 		error = smb_fsop_getattr(sr, kcred, snode, &orig_attr);
 		if (error == 0) {
-			error = smb_fsop_setattr(sr, cr, snode, &set_attr,
-			    NULL);
+			error = smb_fsop_setattr(sr, cr, snode, &set_attr);
 			if (error == EPERM)
 				error = EBADE;
 		}
@@ -2254,7 +2185,7 @@
 			if (set_attr.sa_mask) {
 				orig_attr.sa_mask = set_attr.sa_mask;
 				(void) smb_fsop_setattr(sr, kcred, snode,
-				    &orig_attr, NULL);
+				    &orig_attr);
 			}
 		}
 	}
@@ -2425,7 +2356,7 @@
 {
 	int rc;
 
-	if (node->attr.sa_vattr.va_type == VDIR)
+	if (smb_node_is_dir(node))
 		return (NT_STATUS_SUCCESS);
 
 	/* Allow access if the request is just for meta data */
@@ -2447,7 +2378,7 @@
 void
 smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid)
 {
-	if (node->attr.sa_vattr.va_type == VDIR)
+	if (smb_node_is_dir(node))
 		return;
 
 	(void) smb_vop_unshrlock(node->vp, uniq_fid, cr);
--- a/usr/src/uts/common/fs/smbsrv/smb_lock.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock.c	Tue Jun 30 08:31:17 2009 -0700
@@ -352,7 +352,7 @@
 
 	ASSERT(smb_node_in_crit(node));
 
-	if (node->attr.sa_vattr.va_type == VDIR)
+	if (smb_node_is_dir(node))
 		return (NT_STATUS_SUCCESS);
 
 	rc = smb_lock_range_access(sr, node, start, length, will_write);
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c	Tue Jun 30 08:31:17 2009 -0700
@@ -140,12 +140,15 @@
 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 smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t);
 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 *);
+static void smb_node_init_cached_timestamps(smb_node_t *);
+static void smb_node_clear_cached_timestamps(smb_node_t *);
+static void smb_node_get_cached_timestamps(smb_node_t *, smb_attr_t *);
+static void smb_node_set_cached_timestamps(smb_node_t *, smb_attr_t *);
 
 #define	VALIDATE_DIR_NODE(_dir_, _node_) \
     ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
@@ -257,11 +260,11 @@
     vnode_t		*vp,
     char		*od_name,
     smb_node_t		*dir_snode,
-    smb_node_t		*unnamed_node,
-    smb_attr_t		*attr)
+    smb_node_t		*unnamed_node)
 {
 	smb_llist_t		*node_hdr;
 	smb_node_t		*node;
+	smb_attr_t		attr;
 	uint32_t		hashkey = 0;
 	fsid_t			fsid;
 	int			error;
@@ -281,8 +284,8 @@
 	 * This getattr is performed on behalf of the server
 	 * that's why kcred is used not the user's cred
 	 */
-	attr->sa_mask = SMB_AT_ALL;
-	error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred);
+	attr.sa_mask = SMB_AT_ALL;
+	error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, kcred);
 	if (error)
 		return (NULL);
 
@@ -301,7 +304,7 @@
 		fsid = vp->v_vfsp->vfs_fsid;
 	}
 
-	node_hdr = smb_node_get_hash(&fsid, attr, &hashkey);
+	node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey);
 	lock_mode = RW_READER;
 
 	smb_llist_enter(node_hdr, lock_mode);
@@ -329,8 +332,6 @@
 						node->dir_snode = dir_snode;
 						smb_node_ref(dir_snode);
 					}
-					node->attr = *attr;
-					node->n_size = attr->sa_vattr.va_size;
 
 					smb_node_audit(node);
 					mutex_exit(&node->n_mutex);
@@ -364,7 +365,7 @@
 		}
 		break;
 	}
-	node = smb_node_alloc(od_name, vp, attr, node_hdr, hashkey);
+	node = smb_node_alloc(od_name, vp, node_hdr, hashkey);
 	node->n_orig_uid = crgetuid(sr->user_cr);
 
 	if (op)
@@ -400,20 +401,19 @@
 
 smb_node_t *
 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)
+    vnode_t *xattrdirvp, vnode_t *vp, char *stream_name)
 {
 	smb_node_t	*xattrdir_node;
 	smb_node_t	*snode;
-	smb_attr_t	tmp_attr;
 
 	xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR,
-	    fnode, NULL, &tmp_attr);
+	    fnode, NULL);
 
 	if (xattrdir_node == NULL)
 		return (NULL);
 
 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
-	    fnode, ret_attr);
+	    fnode);
 
 	(void) smb_node_release(xattrdir_node);
 	return (snode);
@@ -535,7 +535,7 @@
 		flags = node->n_delete_on_close_flags;
 		ASSERT(node->od_name != NULL);
 
-		if (node->attr.sa_vattr.va_type == VDIR)
+		if (node->vp->v_type == VDIR)
 			rc = smb_fsop_rmdir(0, node->delete_on_close_cred,
 			    d_snode, node->od_name, flags);
 		else
@@ -589,22 +589,22 @@
 int
 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root)
 {
-	smb_attr_t	va;
+	smb_attr_t	attr;
 	int		error;
 	uint32_t	hashkey;
 	smb_llist_t	*node_hdr;
 	smb_node_t	*node;
 
-	va.sa_mask = SMB_AT_ALL;
-	error = smb_vop_getattr(vp, NULL, &va, 0, kcred);
+	attr.sa_mask = SMB_AT_ALL;
+	error = smb_vop_getattr(vp, NULL, &attr, 0, kcred);
 	if (error) {
 		VN_RELE(vp);
 		return (error);
 	}
 
-	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &va, &hashkey);
+	node_hdr = smb_node_get_hash(&vp->v_vfsp->vfs_fsid, &attr, &hashkey);
 
-	node = smb_node_alloc(ROOTVOL, vp, &va, node_hdr, hashkey);
+	node = smb_node_alloc(ROOTVOL, vp, node_hdr, hashkey);
 
 	sv->si_root_smb_node = node;
 	smb_node_audit(node);
@@ -616,198 +616,6 @@
 }
 
 /*
- * smb_node_get_size
- */
-u_offset_t
-smb_node_get_size(smb_node_t *node, smb_attr_t *attr)
-{
-	u_offset_t size;
-
-	if (attr->sa_vattr.va_type == VDIR)
-		return (0);
-
-	mutex_enter(&node->n_mutex);
-	if (node && (node->flags & NODE_FLAGS_SET_SIZE))
-		size = node->n_size;
-	else
-		size = attr->sa_vattr.va_size;
-	mutex_exit(&node->n_mutex);
-	return (size);
-}
-
-static int
-timeval_cmp(timestruc_t *a, timestruc_t *b)
-{
-	if (a->tv_sec < b->tv_sec)
-		return (-1);
-	if (a->tv_sec > b->tv_sec)
-		return (1);
-	/* Seconds are equal compare tv_nsec */
-	if (a->tv_nsec < b->tv_nsec)
-		return (-1);
-	return (a->tv_nsec > b->tv_nsec);
-}
-
-/*
- * smb_node_set_time
- *
- * This function will update the time stored in the node and
- * set the appropriate flags. If there is nothing to update,
- * the function will return without any updates.  The update
- * is only in the node level and the attribute in the file system
- * will be updated when client close the file.
- */
-void
-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;
-
-	if ((what & SMB_AT_CRTIME && crtime == 0) ||
-	    (what & SMB_AT_MTIME && mtime == 0) ||
-	    (what & SMB_AT_ATIME && atime == 0) ||
-	    (what & SMB_AT_CTIME && ctime == 0))
-		return;
-
-	mutex_enter(&node->n_mutex);
-
-	if ((what & SMB_AT_CRTIME) &&
-	    timeval_cmp((timestruc_t *)&node->attr.sa_crtime,
-	    crtime) != 0) {
-		node->what |= SMB_AT_CRTIME;
-		node->attr.sa_crtime = *((timestruc_t *)crtime);
-	}
-
-	if ((what & SMB_AT_MTIME) &&
-	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime,
-	    mtime) != 0) {
-		node->what |= SMB_AT_MTIME;
-		node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime);
-	}
-
-	if ((what & SMB_AT_ATIME) &&
-	    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime,
-	    atime) != 0) {
-			node->what |= SMB_AT_ATIME;
-			node->attr.sa_vattr.va_atime = *((timestruc_t *)atime);
-	}
-
-	/*
-	 * The ctime handling is trickier. It has three scenarios.
-	 * 1. Only ctime need to be set and it is the same as the ctime
-	 *    stored in the node. (update not necessary)
-	 * 2. The ctime is the same as the ctime stored in the node but
-	 *    is not the only time need to be set. (update required)
-	 * 3. The ctime need to be set and is not the same as the ctime
-	 *    stored in the node. (update required)
-	 * Unlike other time setting, the ctime needs to be set even when
-	 * it is the same as the ctime in the node if there are other time
-	 * needs to be set (#2). This will ensure the ctime not being
-	 * updated when other times are being updated in the file system.
-	 *
-	 * Retained file rules:
-	 *
-	 * 1. Don't add SMB_AT_CTIME to node->what by default because the
-	 *    request will be rejected by filesystem
-	 * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e.
-	 *    any request for changing ctime on these files should have
-	 *    been already rejected
-	 */
-	node->what |= SMB_AT_CTIME;
-	if (what & SMB_AT_CTIME) {
-		if ((what == SMB_AT_CTIME) &&
-		    timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime,
-		    ctime) == 0) {
-			node->what &= ~SMB_AT_CTIME;
-		} else {
-			gethrestime(&node->attr.sa_vattr.va_ctime);
-		}
-	} else {
-		gethrestime(&node->attr.sa_vattr.va_ctime);
-	}
-	mutex_exit(&node->n_mutex);
-}
-
-
-timestruc_t *
-smb_node_get_crtime(smb_node_t *node)
-{
-	return ((timestruc_t *)&node->attr.sa_crtime);
-}
-
-timestruc_t *
-smb_node_get_atime(smb_node_t *node)
-{
-	return ((timestruc_t *)&node->attr.sa_vattr.va_atime);
-}
-
-timestruc_t *
-smb_node_get_ctime(smb_node_t *node)
-{
-	return ((timestruc_t *)&node->attr.sa_vattr.va_ctime);
-}
-
-timestruc_t *
-smb_node_get_mtime(smb_node_t *node)
-{
-	return ((timestruc_t *)&node->attr.sa_vattr.va_mtime);
-}
-
-/*
- * smb_node_set_dosattr
- *
- * Parse the specified DOS attributes and, if they have been modified,
- * update the node cache. This call should be followed by a
- * smb_sync_fsattr() call to write the attribute changes to filesystem.
- */
-void
-smb_node_set_dosattr(smb_node_t *node, uint32_t dosattr)
-{
-	uint32_t mode = dosattr & (FILE_ATTRIBUTE_ARCHIVE |
-	    FILE_ATTRIBUTE_READONLY |
-	    FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
-
-	mutex_enter(&node->n_mutex);
-	if (node->attr.sa_dosattr != mode) {
-		node->attr.sa_dosattr = mode;
-		node->what |= SMB_AT_DOSATTR;
-	}
-	mutex_exit(&node->n_mutex);
-}
-
-/*
- * smb_node_get_dosattr()
- *
- * This function is used to provide clients with information as to whether
- * the readonly bit is set.  Hence both the node attribute cache (which
- * reflects the on-disk attributes) and node->readonly_creator (which
- * reflects whether a readonly set is pending from a readonly create) are
- * checked.  In the latter case, the readonly attribute should be visible to
- * all clients even though the readonly creator fid is immune to the readonly
- * bit until close.
- */
-
-uint32_t
-smb_node_get_dosattr(smb_node_t *node)
-{
-	uint32_t dosattr = node->attr.sa_dosattr;
-
-	if (node->readonly_creator)
-		dosattr |= FILE_ATTRIBUTE_READONLY;
-
-	if (!dosattr)
-		dosattr = FILE_ATTRIBUTE_NORMAL;
-
-	return (dosattr);
-}
-
-/*
  * When DeleteOnClose is set on an smb_node, the common open code will
  * reject subsequent open requests for the file. Observation of Windows
  * 2000 indicates that subsequent opens should be allowed (assuming
@@ -822,19 +630,31 @@
 int
 smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags)
 {
-	int	rc = -1;
+	int rc;
+	smb_attr_t attr;
 
 	mutex_enter(&node->n_mutex);
-	if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) &&
-	    !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) {
-		crhold(cr);
-		node->delete_on_close_cred = cr;
-		node->n_delete_on_close_flags = flags;
-		node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
-		rc = 0;
+
+	if ((node->flags & NODE_FLAGS_DELETE_ON_CLOSE) ||
+	    (node->readonly_creator)) {
+		mutex_exit(&node->n_mutex);
+		return (-1);
 	}
+
+	bzero(&attr, sizeof (smb_attr_t));
+	attr.sa_mask = SMB_AT_DOSATTR;
+	rc = smb_fsop_getattr(NULL, kcred, node, &attr);
+	if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
+		mutex_exit(&node->n_mutex);
+		return (-1);
+	}
+
+	crhold(cr);
+	node->delete_on_close_cred = cr;
+	node->n_delete_on_close_flags = flags;
+	node->flags |= NODE_FLAGS_DELETE_ON_CLOSE;
 	mutex_exit(&node->n_mutex);
-	return (rc);
+	return (0);
 }
 
 void
@@ -939,7 +759,7 @@
 
 	SMB_NODE_VALID(node);
 
-	if (node->attr.sa_vattr.va_type == VDIR)
+	if (node->vp->v_type == VDIR)
 		return (NT_STATUS_SUCCESS);
 
 	/*
@@ -1067,6 +887,9 @@
 	smb_llist_exit(&node->n_ofile_list);
 }
 
+/*
+ * smb_node_inc_open_ofiles
+ */
 void
 smb_node_inc_open_ofiles(smb_node_t *node)
 {
@@ -1075,8 +898,13 @@
 	mutex_enter(&node->n_mutex);
 	node->n_open_count++;
 	mutex_exit(&node->n_mutex);
+
+	smb_node_init_cached_timestamps(node);
 }
 
+/*
+ * smb_node_dec_open_ofiles
+ */
 void
 smb_node_dec_open_ofiles(smb_node_t *node)
 {
@@ -1085,6 +913,8 @@
 	mutex_enter(&node->n_mutex);
 	node->n_open_count--;
 	mutex_exit(&node->n_mutex);
+
+	smb_node_clear_cached_timestamps(node);
 }
 
 uint32_t
@@ -1107,7 +937,6 @@
 smb_node_alloc(
     char	*od_name,
     vnode_t	*vp,
-    smb_attr_t	*attr,
     smb_llist_t	*bucket,
     uint32_t	hashkey)
 {
@@ -1118,9 +947,7 @@
 	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;
+	node->flags = 0;
 	VN_HOLD(vp);
 	node->vp = vp;
 	node->n_refcnt = 1;
@@ -1266,3 +1093,288 @@
 	*phashkey = hashkey;
 	return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]);
 }
+
+boolean_t
+smb_node_is_dir(smb_node_t *node)
+{
+	SMB_NODE_VALID(node);
+	return (node->vp->v_type == VDIR);
+}
+
+boolean_t
+smb_node_is_link(smb_node_t *node)
+{
+	SMB_NODE_VALID(node);
+	return (node->vp->v_type == VLNK);
+}
+
+/*
+ * smb_node_file_is_readonly
+ *
+ * Checks if the file (which node represents) is marked readonly
+ * in the filesystem. No account is taken of any pending readonly
+ * in the node, which must be handled by the callers.
+ * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY)
+ */
+boolean_t
+smb_node_file_is_readonly(smb_node_t *node)
+{
+	smb_attr_t attr;
+
+	if (node == NULL)
+		return (B_FALSE);
+
+	bzero(&attr, sizeof (smb_attr_t));
+	attr.sa_mask = SMB_AT_DOSATTR;
+	(void) smb_fsop_getattr(NULL, kcred, node, &attr);
+	return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0);
+}
+
+/*
+ * smb_node_setattr
+ *
+ * The sr may be NULL, for example when closing an ofile.
+ * The ofile may be NULL, for example when a client request
+ * specifies the file by pathname.
+ *
+ * When attributes are set on an ofile, any pending timestamps
+ * from a write request on the ofile are implicitly set to "now".
+ * For compatibility with windows the following timestamps are
+ * also implicitly set to now:
+ * - if any attribute is being explicitly set, set ctime to now
+ * - if file size is being explicitly set, set atime & ctime to now
+ *
+ * Any attribute that is being explicitly set, or has previously
+ * been explicitly set on the ofile, is excluded from implicit
+ * (now) setting.
+ *
+ * Updates the node's cached timestamp values.
+ * Updates the ofile's explicit times flag.
+ *
+ * Returns: errno
+ */
+int
+smb_node_setattr(smb_request_t *sr, smb_node_t *node,
+    cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
+{
+	int rc;
+	uint32_t what;
+	uint32_t now_times = 0;
+	timestruc_t now;
+
+	ASSERT(attr);
+	SMB_NODE_VALID(node);
+
+	what = attr->sa_mask;
+
+	/* determine which timestamps to implicitly set to "now" */
+	if (what)
+		now_times |= SMB_AT_CTIME;
+	if (what & SMB_AT_SIZE)
+		now_times |= (SMB_AT_MTIME | SMB_AT_CTIME);
+	if (of) {
+		if (smb_ofile_write_time_pending(of))
+			now_times |=
+			    (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME);
+		now_times &= ~(smb_ofile_explicit_times(of));
+	}
+	now_times &= ~what;
+
+	if (now_times) {
+		gethrestime(&now);
+
+		if (now_times & SMB_AT_ATIME) {
+			attr->sa_vattr.va_atime = now;
+			attr->sa_mask |= SMB_AT_ATIME;
+		}
+		if (now_times & SMB_AT_MTIME) {
+			attr->sa_vattr.va_mtime = now;
+			attr->sa_mask |= SMB_AT_MTIME;
+		}
+		if (now_times & SMB_AT_CTIME) {
+			attr->sa_vattr.va_ctime = now;
+			attr->sa_mask |= SMB_AT_CTIME;
+		}
+	}
+
+	if (attr->sa_mask == 0)
+		return (0);
+
+	rc = smb_fsop_setattr(sr, cr, node, attr);
+	if (rc != 0)
+		return (rc);
+
+	smb_node_set_cached_timestamps(node, attr);
+
+	if (of)
+		smb_ofile_set_explicit_times(of, (what & SMB_AT_TIMES));
+
+	return (0);
+}
+
+/*
+ * smb_node_getattr
+ *
+ * Get attributes from the file system and apply any smb-specific
+ * overrides for size, dos attributes and timestamps
+ *
+ * node->readonly_creator reflects whether a readonly set is pending
+ * from a readonly create. The readonly attribute should be visible to
+ * all clients even though the readonly creator fid is immune to the
+ * readonly bit until close.
+ *
+ * Returns: errno
+ */
+int
+smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr)
+{
+	int rc;
+
+	SMB_NODE_VALID(node);
+
+	bzero(attr, sizeof (smb_attr_t));
+	attr->sa_mask = SMB_AT_ALL;
+	rc = smb_fsop_getattr(sr, kcred, node, attr);
+	if (rc != 0)
+		return (rc);
+
+	mutex_enter(&node->n_mutex);
+
+	if (node->vp->v_type == VDIR)
+		attr->sa_vattr.va_size = 0;
+
+	if (node->readonly_creator)
+		attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
+	if (attr->sa_dosattr == 0)
+		attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
+
+	mutex_exit(&node->n_mutex);
+
+	smb_node_get_cached_timestamps(node, attr);
+	return (0);
+}
+
+/*
+ * Timestamp caching
+ *
+ * Solaris file systems handle timestamps different from NTFS. For
+ * example when file data is written NTFS doesn't update the timestamps
+ * until the file is closed, and then only if they haven't been explicity
+ * set via a set attribute request. In order to provide a more similar
+ * view of an open file's timestamps, we cache the timestamps in the
+ * node and manipulate them in a manner more consistent with windows.
+ * (See handling of explicit times and pending timestamps from a write
+ * request in smb_node_getattr and smb_node_setattr above.)
+ * Timestamps remain cached while there are open ofiles for the node.
+ * This includes open ofiles for named streams.
+ * n_open_ofiles cannot be used as this doesn't include ofiles opened
+ * for the node's named streams. Thus n_timestamps contains a count
+ * of open ofiles (t_open_ofiles), including named streams' ofiles,
+ * to be used to control timestamp caching.
+ *
+ * If a node represents a named stream the associated unnamed streams
+ * cached timestamps are used instead.
+ */
+
+/*
+ * smb_node_init_cached_timestamps
+ *
+ * Increment count of open ofiles which are using the cached timestamps.
+ * If this is the first open ofile, init the cached timestamps from the
+ * file system values.
+ */
+static void
+smb_node_init_cached_timestamps(smb_node_t *node)
+{
+	smb_node_t *unode;
+	smb_attr_t attr;
+
+	if ((unode = SMB_IS_STREAM(node)) != NULL)
+		node = unode;
+
+	mutex_enter(&node->n_mutex);
+	++(node->n_timestamps.t_open_ofiles);
+	if (node->n_timestamps.t_open_ofiles == 1) {
+		bzero(&attr, sizeof (smb_attr_t));
+		attr.sa_mask = SMB_AT_TIMES;
+		(void) smb_fsop_getattr(NULL, kcred, node, &attr);
+		node->n_timestamps.t_mtime = attr.sa_vattr.va_mtime;
+		node->n_timestamps.t_atime = attr.sa_vattr.va_atime;
+		node->n_timestamps.t_ctime = attr.sa_vattr.va_ctime;
+		node->n_timestamps.t_crtime = attr.sa_crtime;
+		node->n_timestamps.t_cached = B_TRUE;
+	}
+	mutex_exit(&node->n_mutex);
+}
+
+/*
+ * smb_node_clear_cached_timestamps
+ *
+ * Decrement count of open ofiles using the cached timestamps.
+ * If the decremented count is zero, clear the cached timestamps.
+ */
+static void
+smb_node_clear_cached_timestamps(smb_node_t *node)
+{
+	smb_node_t *unode;
+
+	if ((unode = SMB_IS_STREAM(node)) != NULL)
+		node = unode;
+
+	mutex_enter(&node->n_mutex);
+	ASSERT(node->n_timestamps.t_open_ofiles > 0);
+	--(node->n_timestamps.t_open_ofiles);
+	if (node->n_timestamps.t_open_ofiles == 0)
+		bzero(&node->n_timestamps, sizeof (smb_times_t));
+	mutex_exit(&node->n_mutex);
+}
+
+/*
+ * smb_node_get_cached_timestamps
+ *
+ * Overwrite timestamps in attr with those cached in node.
+ */
+static void
+smb_node_get_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
+{
+	smb_node_t *unode;
+
+	if ((unode = SMB_IS_STREAM(node)) != NULL)
+		node = unode;
+
+	mutex_enter(&node->n_mutex);
+	if (node->n_timestamps.t_cached) {
+		attr->sa_vattr.va_mtime = node->n_timestamps.t_mtime;
+		attr->sa_vattr.va_atime = node->n_timestamps.t_atime;
+		attr->sa_vattr.va_ctime = node->n_timestamps.t_ctime;
+		attr->sa_crtime = node->n_timestamps.t_crtime;
+	}
+	mutex_exit(&node->n_mutex);
+}
+
+/*
+ * smb_node_set_cached_timestamps
+ *
+ * Update the node's cached timestamps with values from attr.
+ */
+static void
+smb_node_set_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
+{
+	smb_node_t *unode;
+
+	if ((unode = SMB_IS_STREAM(node)) != NULL)
+		node = unode;
+
+	mutex_enter(&node->n_mutex);
+	if (node->n_timestamps.t_cached) {
+		if (attr->sa_mask & SMB_AT_MTIME)
+			node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
+		if (attr->sa_mask & SMB_AT_ATIME)
+			node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
+		if (attr->sa_mask & SMB_AT_CTIME)
+			node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
+		if (attr->sa_mask & SMB_AT_CRTIME)
+			node->n_timestamps.t_crtime = attr->sa_crtime;
+	}
+	mutex_exit(&node->n_mutex);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c	Tue Jun 30 08:31:17 2009 -0700
@@ -228,7 +228,7 @@
 	struct open_param	*op = &sr->arg.open;
 	unsigned char		OplockLevel;
 	unsigned char		DirFlag;
-	smb_attr_t		new_attr;
+	smb_attr_t		attr;
 	smb_node_t		*node;
 	int rc;
 
@@ -295,19 +295,12 @@
 		if (op->create_options & FILE_DELETE_ON_CLOSE)
 			smb_ofile_set_delete_on_close(sr->fid_ofile);
 
-		/*
-		 * Set up the directory flag and ensure that
-		 * we don't return a stale file size.
-		 */
 		node = sr->fid_ofile->f_node;
-		if (node->attr.sa_vattr.va_type == VDIR) {
-			DirFlag = 1;
-			new_attr.sa_vattr.va_size = 0;
-		} else {
-			DirFlag = 0;
-			new_attr.sa_mask = SMB_AT_SIZE;
-			(void) smb_fsop_getattr(sr, kcred, node, &new_attr);
-			node->attr.sa_vattr.va_size = new_attr.sa_vattr.va_size;
+		DirFlag = smb_node_is_dir(node) ? 1 : 0;
+		if (smb_node_getattr(sr, node, &attr) != 0) {
+			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+			    ERRDOS, ERROR_INTERNAL_ERROR);
+			return (SDRC_ERROR);
 		}
 
 		rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
@@ -317,13 +310,13 @@
 		    OplockLevel,
 		    sr->smb_fid,
 		    op->action_taken,
-		    &node->attr.sa_crtime,
-		    &node->attr.sa_vattr.va_atime,
-		    &node->attr.sa_vattr.va_mtime,
-		    &node->attr.sa_vattr.va_ctime,
+		    &attr.sa_crtime,
+		    &attr.sa_vattr.va_atime,
+		    &attr.sa_vattr.va_mtime,
+		    &attr.sa_vattr.va_ctime,
 		    op->dattr & FILE_ATTRIBUTE_MASK,
-		    new_attr.sa_vattr.va_size,
-		    new_attr.sa_vattr.va_size,
+		    attr.sa_vattr.va_size,
+		    attr.sa_vattr.va_size,
 		    op->ftype,
 		    op->devstate,
 		    DirFlag,
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c	Tue Jun 30 08:31:17 2009 -0700
@@ -144,7 +144,7 @@
 	struct open_param *op = &sr->arg.open;
 	uint8_t			OplockLevel;
 	uint8_t			DirFlag;
-	smb_attr_t		new_attr;
+	smb_attr_t		attr;
 	smb_node_t		*node;
 	uint32_t status;
 
@@ -213,19 +213,12 @@
 		if (op->create_options & FILE_DELETE_ON_CLOSE)
 			smb_ofile_set_delete_on_close(sr->fid_ofile);
 
-		/*
-		 * Set up the directory flag and ensure that
-		 * we don't return a stale file size.
-		 */
 		node = sr->fid_ofile->f_node;
-		if (node->attr.sa_vattr.va_type == VDIR) {
-			DirFlag = 1;
-			new_attr.sa_vattr.va_size = 0;
-		} else {
-			DirFlag = 0;
-			new_attr.sa_mask = SMB_AT_SIZE;
-			(void) smb_fsop_getattr(sr, kcred, node, &new_attr);
-			node->attr.sa_vattr.va_size = new_attr.sa_vattr.va_size;
+		DirFlag = smb_node_is_dir(node) ? 1 : 0;
+		if (smb_node_getattr(sr, node, &attr) != 0) {
+			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+			    ERRDOS, ERROR_INTERNAL_ERROR);
+			return (SDRC_ERROR);
 		}
 
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
@@ -233,28 +226,28 @@
 		    sr->smb_fid,
 		    op->action_taken,
 		    0,	/* EaErrorOffset */
-		    &node->attr.sa_crtime,
-		    &node->attr.sa_vattr.va_atime,
-		    &node->attr.sa_vattr.va_mtime,
-		    &node->attr.sa_vattr.va_ctime,
+		    &attr.sa_crtime,
+		    &attr.sa_vattr.va_atime,
+		    &attr.sa_vattr.va_mtime,
+		    &attr.sa_vattr.va_ctime,
 		    op->dattr & FILE_ATTRIBUTE_MASK,
-		    new_attr.sa_vattr.va_size,
-		    new_attr.sa_vattr.va_size,
+		    attr.sa_vattr.va_size,
+		    attr.sa_vattr.va_size,
 		    op->ftype,
 		    op->devstate,
 		    DirFlag);
 	} else {
 		/* Named PIPE */
-		bzero(&new_attr, sizeof (smb_attr_t));
+		bzero(&attr, sizeof (smb_attr_t));
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb",
 		    0,
 		    sr->smb_fid,
 		    op->action_taken,
 		    0,	/* EaErrorOffset */
-		    &new_attr.sa_crtime,
-		    &new_attr.sa_vattr.va_atime,
-		    &new_attr.sa_vattr.va_mtime,
-		    &new_attr.sa_vattr.va_ctime,
+		    &attr.sa_crtime,
+		    &attr.sa_vattr.va_atime,
+		    &attr.sa_vattr.va_mtime,
+		    &attr.sa_vattr.va_ctime,
 		    op->dattr,
 		    0x1000LL,
 		    0LL,
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c	Tue Jun 30 08:31:17 2009 -0700
@@ -203,7 +203,7 @@
 
 	node = sr->fid_ofile->f_node;
 
-	if (node->attr.sa_vattr.va_type != VDIR) {
+	if (!smb_node_is_dir(node)) {
 		/*
 		 * Notify change requests are only valid on directories.
 		 */
--- a/usr/src/uts/common/fs/smbsrv/smb_odir.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c	Tue Jun 30 08:31:17 2009 -0700
@@ -164,7 +164,7 @@
  *	Find the next directory entry in the odir. Return the details of
  *	the directory entry in smb_fileinfo_t. (See odir internals below)
  *
- * smb_odir_read_stream_info(..., smb_streaminfo_t *)
+ * smb_odir_read_streaminfo(..., smb_streaminfo_t *)
  *	Find the next named stream entry in the odir. Return the details of
  *	the named stream in smb_streaminfo_t.
  *
@@ -214,7 +214,7 @@
  * of the file that is the target of the link. If the link target cannot
  * be found the attributes returned are the attributes of the link itself.
  *
- * smb_odir_read_stream_info
+ * smb_odir_read_streaminfo
  * In order for an odir to provide information about stream files it
  * must be opened with smb_odir_openat(). smb_odir_read_streaminfo() can
  * then be used to obtain the name and size of named stream files.
@@ -257,8 +257,8 @@
 static int smb_odir_wildcard_fileinfo(smb_request_t *, smb_odir_t *,
     smb_odirent_t *, smb_fileinfo_t *);
 static int smb_odir_next_odirent(smb_odir_t *, smb_odirent_t *);
-static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *, char *,
-    smb_node_t **, smb_attr_t *);
+static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *,
+    char *, smb_node_t **);
 
 
 /*
@@ -338,7 +338,6 @@
 	char		pattern[SMB_STREAM_PREFIX_LEN + 2];
 
 	smb_node_t	*xattr_dnode;
-	smb_attr_t	tmp_attr;
 
 	ASSERT(sr);
 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
@@ -362,7 +361,7 @@
 
 	/* lookup the xattrdir's smb_node */
 	xattr_dnode = smb_node_lookup(sr, NULL, cr, xattr_dvp, XATTR_DIR,
-	    unode, NULL, &tmp_attr);
+	    unode, NULL);
 	VN_RELE(xattr_dvp);
 	if (xattr_dnode == NULL) {
 		smbsr_error(sr, NT_STATUS_NO_MEMORY,
@@ -704,8 +703,8 @@
 		}
 
 		/*
-		 * since we only care about the size attribute we don't need to
-		 * pass the vp of the unnamed stream file to smb_vop_getattr
+		 * since we only care about the size attributes we don't need
+		 * to pass the vp of the unnamed stream file to smb_vop_getattr
 		 */
 		rc = smb_vop_lookup(od->d_dnode->vp, odirent->od_name, &vp,
 		    NULL, 0, &tmpflg, od->d_tree->t_snode->vp, od->d_cred);
@@ -719,6 +718,8 @@
 			    odirent->od_name + SMB_STREAM_PREFIX_LEN,
 			    sizeof (sinfo->si_name));
 			sinfo->si_size = attr.sa_vattr.va_size;
+			sinfo->si_alloc_size =
+			    attr.sa_vattr.va_nblocks * DEV_BSIZE;
 			break;
 		}
 	}
@@ -1037,10 +1038,9 @@
 {
 	int		rc;
 	smb_node_t	*fnode, *tgt_node;
-	smb_attr_t	attr, tgt_attr, *fattr;
+	smb_attr_t	attr;
 	ino64_t		ino;
 	char		*name;
-	uint32_t	dosattr;
 	boolean_t	case_conflict = B_FALSE;
 	int		lookup_flags, flags = 0;
 	vnode_t		*vp;
@@ -1054,7 +1054,7 @@
 	bzero(fileinfo, sizeof (smb_fileinfo_t));
 
 	rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode,
-	    od->d_dnode, od->d_pattern, &fnode, &attr);
+	    od->d_dnode, od->d_pattern, &fnode);
 	if (rc != 0)
 		return (rc);
 
@@ -1078,6 +1078,11 @@
 			case_conflict = B_TRUE;
 	}
 
+	if ((rc = smb_node_getattr(sr, fnode, &attr)) != 0) {
+		smb_node_release(fnode);
+		return (rc);
+	}
+
 	ino = attr.sa_vattr.va_nodeid;
 	(void) smb_mangle_name(ino, fnode->od_name,
 	    fileinfo->fi_shortname, fileinfo->fi_name83, case_conflict);
@@ -1086,33 +1091,32 @@
 
 	/* follow link to get target node & attr */
 	if ((fnode->vp->v_type == VLNK) &&
-	    (smb_odir_lookup_link(sr, od, fnode->od_name,
-	    &tgt_node, &tgt_attr))) {
+	    (smb_odir_lookup_link(sr, od, fnode->od_name, &tgt_node))) {
 		smb_node_release(fnode);
 		fnode = tgt_node;
-		fattr = &tgt_attr;
-	} else {
-		fattr = &attr;
+		if ((rc = smb_node_getattr(sr, fnode, &attr)) != 0) {
+			smb_node_release(fnode);
+			return (rc);
+		}
 	}
 
 	/* check search attributes */
-	dosattr = smb_node_get_dosattr(fnode);
-	if (!smb_sattr_check(dosattr, od->d_sattr)) {
+	if (!smb_sattr_check(attr.sa_dosattr, od->d_sattr)) {
 		smb_node_release(fnode);
 		return (ENOENT);
 	}
 
-	fileinfo->fi_dosattr = dosattr;
-	fileinfo->fi_nodeid = fattr->sa_vattr.va_nodeid;
-	fileinfo->fi_size = smb_node_get_size(fnode, fattr);
-	fileinfo->fi_alloc_size = fattr->sa_vattr.va_nblocks * DEV_BSIZE;
-	fileinfo->fi_atime = fattr->sa_vattr.va_atime;
-	fileinfo->fi_mtime = fattr->sa_vattr.va_mtime;
-	fileinfo->fi_ctime = fattr->sa_vattr.va_ctime;
-	if (fattr->sa_crtime.tv_sec)
-		fileinfo->fi_crtime = fattr->sa_crtime;
+	fileinfo->fi_dosattr = attr.sa_dosattr;
+	fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
+	fileinfo->fi_size = attr.sa_vattr.va_size;
+	fileinfo->fi_alloc_size = attr.sa_vattr.va_nblocks * DEV_BSIZE;
+	fileinfo->fi_atime = attr.sa_vattr.va_atime;
+	fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
+	fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
+	if (attr.sa_crtime.tv_sec)
+		fileinfo->fi_crtime = attr.sa_crtime;
 	else
-		fileinfo->fi_crtime = fattr->sa_vattr.va_mtime;
+		fileinfo->fi_crtime = attr.sa_vattr.va_mtime;
 
 	smb_node_release(fnode);
 	return (0);
@@ -1150,9 +1154,8 @@
 {
 	int		rc;
 	smb_node_t	*fnode, *tgt_node;
-	smb_attr_t	attr, tgt_attr, *fattr;
+	smb_attr_t	attr;
 	char		*name;
-	uint32_t	dosattr;
 	boolean_t	case_conflict;
 
 	ASSERT(sr);
@@ -1171,39 +1174,40 @@
 	(void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name));
 
 	rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode,
-	    od->d_dnode, name, &fnode, &attr);
+	    od->d_dnode, name, &fnode);
 	if (rc != 0)
 		return (rc);
 
 	/* follow link to get target node & attr */
 	if ((fnode->vp->v_type == VLNK) &&
-	    (smb_odir_lookup_link(sr, od, name, &tgt_node, &tgt_attr))) {
+	    (smb_odir_lookup_link(sr, od, name, &tgt_node))) {
 		smb_node_release(fnode);
 		fnode = tgt_node;
-		fattr = &tgt_attr;
-	} else {
-		fattr = &attr;
+	}
+
+	if ((rc = smb_node_getattr(sr, fnode, &attr)) != 0) {
+		smb_node_release(fnode);
+		return (rc);
 	}
 
 	/* check search attributes */
-	dosattr = smb_node_get_dosattr(fnode);
-	if (!smb_sattr_check(dosattr, od->d_sattr)) {
+	if (!smb_sattr_check(attr.sa_dosattr, od->d_sattr)) {
 		smb_node_release(fnode);
 		return (ENOENT);
 	}
 
 	fileinfo->fi_cookie = (uint32_t)od->d_offset;
-	fileinfo->fi_dosattr = dosattr;
-	fileinfo->fi_nodeid = fattr->sa_vattr.va_nodeid;
-	fileinfo->fi_size = smb_node_get_size(fnode, fattr);
-	fileinfo->fi_alloc_size = fattr->sa_vattr.va_nblocks * DEV_BSIZE;
-	fileinfo->fi_atime = fattr->sa_vattr.va_atime;
-	fileinfo->fi_mtime = fattr->sa_vattr.va_mtime;
-	fileinfo->fi_ctime = fattr->sa_vattr.va_ctime;
-	if (fattr->sa_crtime.tv_sec)
-		fileinfo->fi_crtime = fattr->sa_crtime;
+	fileinfo->fi_dosattr = attr.sa_dosattr;
+	fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
+	fileinfo->fi_size = attr.sa_vattr.va_size;
+	fileinfo->fi_alloc_size = attr.sa_vattr.va_nblocks * DEV_BSIZE;
+	fileinfo->fi_atime = attr.sa_vattr.va_atime;
+	fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
+	fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
+	if (attr.sa_crtime.tv_sec)
+		fileinfo->fi_crtime = attr.sa_crtime;
 	else
-		fileinfo->fi_crtime = fattr->sa_vattr.va_mtime;
+		fileinfo->fi_crtime = attr.sa_vattr.va_mtime;
 
 	smb_node_release(fnode);
 	return (0);
@@ -1229,18 +1233,18 @@
  */
 static boolean_t
 smb_odir_lookup_link(smb_request_t *sr, smb_odir_t *od,
-    char *fname, smb_node_t **tgt_node, smb_attr_t *tgt_attr)
+    char *fname, smb_node_t **tgt_node)
 {
 	int rc;
 
 	rc = smb_fsop_lookup(sr, od->d_cred, SMB_FOLLOW_LINKS,
-	    od->d_tree->t_snode, od->d_dnode, fname, tgt_node, tgt_attr);
+	    od->d_tree->t_snode, od->d_dnode, fname, tgt_node);
 	if (rc != 0) {
 		*tgt_node = NULL;
 		return (B_FALSE);
 	}
 
-	if ((tgt_attr->sa_vattr.va_type == VDIR) && (!smb_dirsymlink_enable)) {
+	if (smb_node_is_dir(*tgt_node) && (!smb_dirsymlink_enable)) {
 		smb_node_release(*tgt_node);
 		*tgt_node = NULL;
 		return (B_FALSE);
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c	Tue Jun 30 08:31:17 2009 -0700
@@ -165,13 +165,12 @@
 #include <smbsrv/smb_fsops.h>
 
 /* Static functions defined further down this file. */
-static void		smb_ofile_delete(smb_ofile_t *of);
-static smb_ofile_t	*smb_ofile_close_and_next(smb_ofile_t *of);
+static void smb_ofile_delete(smb_ofile_t *of);
+static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *of);
+static void smb_ofile_set_close_attrs(smb_ofile_t *, uint32_t);
 
 /*
  * smb_ofile_open
- *
- *
  */
 smb_ofile_t *
 smb_ofile_open(
@@ -185,6 +184,7 @@
 {
 	smb_ofile_t	*of;
 	uint16_t	fid;
+	smb_attr_t	attr;
 
 	if (smb_idpool_alloc(&tree->t_fid_pool, &fid)) {
 		err->status = NT_STATUS_TOO_MANY_OPENED_FILES;
@@ -212,9 +212,11 @@
 	of->f_user = tree->t_user;
 	of->f_tree = tree;
 	of->f_node = node;
+	of->f_explicit_times = 0;
 	mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL);
 	of->f_state = SMB_OFILE_STATE_OPEN;
 
+
 	if (ftype == SMB_FTYPE_MESG_PIPE) {
 		of->f_pipe = kmem_zalloc(sizeof (smb_opipe_t), KM_SLEEP);
 	} else {
@@ -224,7 +226,20 @@
 		if (of->f_granted_access == FILE_EXECUTE)
 			of->f_flags |= SMB_OFLAGS_EXECONLY;
 
-		if (crgetuid(of->f_cr) == node->attr.sa_vattr.va_uid) {
+		bzero(&attr, sizeof (smb_attr_t));
+		attr.sa_mask |= SMB_AT_UID;
+		if (smb_fsop_getattr(NULL, kcred, node, &attr) != 0) {
+			of->f_magic = 0;
+			mutex_destroy(&of->f_mutex);
+			crfree(of->f_cr);
+			smb_idpool_free(&tree->t_fid_pool, of->f_fid);
+			kmem_cache_free(tree->t_server->si_cache_ofile, of);
+			err->status = NT_STATUS_INTERNAL_ERROR;
+			err->errcls = ERRDOS;
+			err->errcode = ERROR_INTERNAL_ERROR;
+			return (NULL);
+		}
+		if (crgetuid(of->f_cr) == attr.sa_vattr.va_uid) {
 			/*
 			 * Add this bit for the file's owner even if it's not
 			 * specified in the request (Windows behavior).
@@ -270,13 +285,9 @@
 
 /*
  * smb_ofile_close
- *
- *
  */
 void
-smb_ofile_close(
-    smb_ofile_t		*of,
-    uint32_t		last_wtime)
+smb_ofile_close(smb_ofile_t *of, uint32_t last_wtime)
 {
 	ASSERT(of);
 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
@@ -293,19 +304,8 @@
 		if (of->f_ftype == SMB_FTYPE_MESG_PIPE) {
 			smb_opipe_close(of);
 		} else {
-			/*
-			 * 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;
-				of->f_node->what |= SMB_AT_DOSATTR;
-				of->f_node->readonly_creator = NULL;
-			}
+			smb_ofile_set_close_attrs(of, last_wtime);
 
-			smb_ofile_close_timestamp_update(of, last_wtime);
-			(void) smb_sync_fsattr(NULL, of->f_cr, of->f_node);
 			if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) {
 				if (smb_tree_has_feature(of->f_tree,
 				    SMB_TREE_CATIA)) {
@@ -526,6 +526,7 @@
 {
 	u_offset_t	newoff = 0;
 	int		rc = 0;
+	smb_attr_t	attr;
 
 	ASSERT(of);
 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
@@ -548,11 +549,17 @@
 		break;
 
 	case SMB_SEEK_END:
-		if (off < 0 && (-off) > of->f_node->attr.sa_vattr.va_size)
+		bzero(&attr, sizeof (smb_attr_t));
+		attr.sa_mask |= SMB_AT_SIZE;
+		rc = smb_fsop_getattr(NULL, kcred, of->f_node, &attr);
+		if (rc != 0) {
+			mutex_exit(&of->f_mutex);
+			return (rc);
+		}
+		if (off < 0 && (-off) > attr.sa_vattr.va_size)
 			newoff = 0;
 		else
-			newoff = of->f_node->attr.sa_vattr.va_size +
-			    (u_offset_t)off;
+			newoff = attr.sa_vattr.va_size + (u_offset_t)off;
 		break;
 
 	default:
@@ -576,47 +583,7 @@
 }
 
 /*
- * smb_ofile_close_timestamp_update
- *
- * The last_wtime is specified in the request received
- * from the client. If it is neither 0 nor -1, this time
- * should be used as the file's mtime. It must first be
- * converted from the server's localtime (as received in
- * the client's request) to GMT.
- */
-void
-smb_ofile_close_timestamp_update(
-    smb_ofile_t		*of,
-    uint32_t		last_wtime)
-{
-	smb_node_t	*node;
-	timestruc_t	mtime, atime;
-	unsigned int	what = 0;
-
-	mtime.tv_sec = 0;
-	mtime.tv_nsec = 0;
-
-	if (last_wtime != 0 && last_wtime != 0xFFFFFFFF) {
-		mtime.tv_sec = last_wtime + of->f_server->si_gmtoff;
-		what |= SMB_AT_MTIME;
-	}
-
-	/*
-	 * NODE_FLAGS_SYNCATIME is set whenever something is
-	 * written to a file.
-	 */
-	node = of->f_node;
-	if (node->flags & NODE_FLAGS_SYNCATIME) {
-		what |= SMB_AT_ATIME;
-		(void) microtime(&atime);
-	}
-
-	smb_node_set_time(node, 0, &mtime, &atime, 0, what);
-}
-
-/*
  * smb_ofile_is_open
- *
  */
 boolean_t
 smb_ofile_is_open(smb_ofile_t *of)
@@ -644,9 +611,113 @@
 	mutex_exit(&of->f_mutex);
 }
 
+/*
+ * smb_ofile_pending_write_time
+ *
+ * Flag write times as pending - to be set on close, setattr
+ * or delayed write timer.
+ */
+void
+smb_ofile_set_write_time_pending(smb_ofile_t *of)
+{
+	SMB_OFILE_VALID(of);
+	mutex_enter(&of->f_mutex);
+	of->f_flags |= SMB_OFLAGS_TIMESTAMPS_PENDING;
+	mutex_exit(&of->f_mutex);
+}
+
+boolean_t
+smb_ofile_write_time_pending(smb_ofile_t *of)
+{
+	boolean_t rc = B_FALSE;
+
+	SMB_OFILE_VALID(of);
+	mutex_enter(&of->f_mutex);
+	if (of->f_flags & SMB_OFLAGS_TIMESTAMPS_PENDING)
+		rc = B_TRUE;
+	mutex_exit(&of->f_mutex);
+
+	return (rc);
+}
+
+/*
+ * smb_ofile_set_explicit_time_flag
+ *
+ * Note the timestamps specified in "what", as having been
+ * explicity set for the ofile. Also clear the flag for pending
+ * timestamps as the pending timestamps will have been applied
+ * by the explicit set.
+ */
+void
+smb_ofile_set_explicit_times(smb_ofile_t *of, uint32_t what)
+{
+	SMB_OFILE_VALID(of);
+	mutex_enter(&of->f_mutex);
+	of->f_flags &= ~SMB_OFLAGS_TIMESTAMPS_PENDING;
+	of->f_explicit_times |= (what & SMB_AT_TIMES);
+	mutex_exit(&of->f_mutex);
+}
+
+uint32_t
+smb_ofile_explicit_times(smb_ofile_t *of)
+{
+	uint32_t rc;
+
+	SMB_OFILE_VALID(of);
+	mutex_enter(&of->f_mutex);
+	rc = of->f_explicit_times;
+	mutex_exit(&of->f_mutex);
+
+	return (rc);
+}
+
 /* *************************** Static Functions ***************************** */
 
 /*
+ * smb_ofile_set_close_attrs
+ *
+ * Updates timestamps, size and readonly bit.
+ * The last_wtime is specified in the request received
+ * from the client. If it is neither 0 nor -1, this time
+ * should be used as the file's mtime. It must first be
+ * converted from the server's localtime (as received in
+ * the client's request) to GMT.
+ *
+ * Call smb_node_setattr even if no attributes are being
+ * explicitly set, to set any pending attributes.
+ */
+static void
+smb_ofile_set_close_attrs(smb_ofile_t *of, uint32_t last_wtime)
+{
+	smb_node_t *node = of->f_node;
+	smb_attr_t attr;
+
+	bzero(&attr, sizeof (smb_attr_t));
+
+	/* For files created readonly, propagate readonly bit */
+	if (node->readonly_creator == of) {
+		attr.sa_mask |= SMB_AT_DOSATTR;
+		if (smb_fsop_getattr(NULL, kcred, node, &attr) &&
+		    (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) {
+			attr.sa_mask = 0;
+		} else {
+			attr.sa_dosattr |= FILE_ATTRIBUTE_READONLY;
+		}
+
+		node->readonly_creator = NULL;
+	}
+
+	/* apply last_wtime if specified */
+	if (last_wtime != 0 && last_wtime != 0xFFFFFFFF) {
+		attr.sa_vattr.va_mtime.tv_sec =
+		    last_wtime + of->f_server->si_gmtoff;
+		attr.sa_mask |= SMB_AT_MTIME;
+	}
+
+	(void) smb_node_setattr(NULL, node, of->f_cr, of, &attr);
+}
+
+/*
  * smb_ofile_close_and_next
  *
  * This function closes the file passed in (if appropriate) and returns the
@@ -655,8 +726,7 @@
  * RW_READER mode before being called.
  */
 static smb_ofile_t *
-smb_ofile_close_and_next(
-    smb_ofile_t		*of)
+smb_ofile_close_and_next(smb_ofile_t *of)
 {
 	smb_ofile_t	*next_of;
 	smb_tree_t	*tree;
@@ -702,8 +772,7 @@
  *
  */
 static void
-smb_ofile_delete(
-    smb_ofile_t		*of)
+smb_ofile_delete(smb_ofile_t *of)
 {
 	ASSERT(of);
 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
@@ -800,7 +869,7 @@
 	 * directories, but this check will remain as it is not
 	 * clear whether it was originally put here for a reason.
 	 */
-	if (node->attr.sa_vattr.va_type == VDIR) {
+	if (smb_node_is_dir(node)) {
 		if (SMB_DENY_RW(of->f_share_access) &&
 		    (node->n_orig_uid != crgetuid(cr))) {
 			mutex_exit(&of->f_mutex);
--- a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c	Tue Jun 30 08:31:17 2009 -0700
@@ -243,6 +243,7 @@
 {
 	struct open_param *op = &sr->arg.open;
 	smb_node_t *node;
+	smb_attr_t attr;
 	uint16_t file_attr;
 	int rc;
 
@@ -279,12 +280,17 @@
 
 	file_attr = op->dattr  & FILE_ATTRIBUTE_MASK;
 	node = sr->fid_ofile->f_node;
+	if (smb_node_getattr(sr, node, &attr) != 0) {
+		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+		    ERRDOS, ERROR_INTERNAL_ERROR);
+		return (SDRC_ERROR);
+	}
 
 	rc = smbsr_encode_result(sr, 7, 0, "bwwllww",
 	    7,
 	    sr->smb_fid,
 	    file_attr,
-	    smb_gmt2local(sr, node->attr.sa_vattr.va_mtime.tv_sec),
+	    smb_gmt2local(sr, attr.sa_vattr.va_mtime.tv_sec),
 	    (uint32_t)op->dsize,
 	    op->omode,
 	    (uint16_t)0);	/* bcc */
@@ -348,6 +354,7 @@
 {
 	struct open_param	*op = &sr->arg.open;
 	uint16_t		file_attr;
+	smb_attr_t		attr;
 	int rc;
 
 	op->desired_access = smb_omode_to_amask(op->omode);
@@ -378,14 +385,21 @@
 
 	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
 	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+
 		smb_node_t *node = sr->fid_ofile->f_node;
+		if (smb_node_getattr(sr, node, &attr) != 0) {
+			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+			    ERRDOS, ERROR_INTERNAL_ERROR);
+			return (SDRC_ERROR);
+		}
+
 		rc = smbsr_encode_result(sr, 15, 0,
 		    "bb.wwwllwwwwl2.w",
 		    15,
 		    sr->andx_com, VAR_BCC,
 		    sr->smb_fid,
 		    file_attr,
-		    smb_gmt2local(sr, node->attr.sa_vattr.va_mtime.tv_sec),
+		    smb_gmt2local(sr, attr.sa_vattr.va_mtime.tv_sec),
 		    (uint32_t)op->dsize,
 		    op->omode, op->ftype,
 		    op->devstate,
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c	Tue Jun 30 08:31:17 2009 -0700
@@ -88,11 +88,22 @@
 
 	rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
 	    sr->tid_tree->t_snode, fqi->fq_dnode, fqi->fq_last_comp,
-	    &fqi->fq_fnode, &fqi->fq_fattr);
+	    &fqi->fq_fnode);
 
 	if (rc == 0) {
-		(void) strcpy(fqi->fq_od_name,
-		    fqi->fq_fnode->od_name);
+		(void) strcpy(fqi->fq_od_name, fqi->fq_fnode->od_name);
+
+		/*
+		 * fqi->fq_fattr MUST be set even if returning EEXIST, as it
+		 * is used by some callers to determine how to handle EEXIST
+		 */
+		rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
+		if (rc != 0) {
+			smb_node_release(fqi->fq_dnode);
+			smb_node_release(fqi->fq_fnode);
+			SMB_NULL_FQI_NODES(*fqi);
+			return (rc);
+		}
 
 		if (fqm == FQM_PATH_MUST_NOT_EXIST) {
 			smb_node_release(fqi->fq_dnode);
@@ -383,7 +394,6 @@
 	pathname_t	pn, rpn, upn, link_pn;
 	smb_node_t	*dnode, *fnode;
 	vnode_t		*rootvp, *vp;
-	smb_attr_t	attr;
 	size_t		pathleft;
 	int		err = 0;
 	int		nlink = 0;
@@ -517,7 +527,7 @@
 			    namebuf, sizeof (namebuf));
 
 			fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
-			    dnode, NULL, &attr);
+			    dnode, NULL);
 			VN_RELE(vp);
 
 			if (fnode == NULL) {
@@ -640,7 +650,7 @@
 	(void) pn_alloc(&pn);
 
 	if (pn_set(&pn, path) == 0) {
-		VN_HOLD(rootvp);
+		VN_HOLD(startvp);
 		if (rootvp != rootdir)
 			VN_HOLD(rootvp);
 
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information.c	Tue Jun 30 08:31:17 2009 -0700
@@ -114,24 +114,30 @@
 		return (SDRC_ERROR);
 	}
 
-	if ((rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
-	    sr->tid_tree->t_snode, dir_node, name, &node, &attr)) != 0) {
+	if ((rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+	    sr->tid_tree->t_snode, dir_node, name, &node)) != 0) {
 		smb_node_release(dir_node);
 		smbsr_errno(sr, rc);
 		return (SDRC_ERROR);
 	}
 
 	smb_node_release(dir_node);
+	rc = smb_node_getattr(sr, node, &attr);
+	smb_node_release(node);
 
-	dattr = smb_node_get_dosattr(node);
-	mtime = smb_node_get_mtime(node);
+	if (rc != 0) {
+		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+		    ERRDOS, ERROR_INTERNAL_ERROR);
+		return (SDRC_ERROR);
+	}
+
+	dattr = attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
+	mtime = &attr.sa_vattr.va_mtime;
 	write_time = smb_gmt2local(sr, mtime->tv_sec);
-	datasz = smb_node_get_size(node, &node->attr);
+	datasz = attr.sa_vattr.va_size;
 	if (datasz > UINT_MAX)
 		datasz = UINT_MAX;
 
-	smb_node_release(node);
-
 	rc = smbsr_encode_result(sr, 10, 0, "bwll10.w",
 	    10, dattr, write_time, (uint32_t)datasz, 0);
 
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c	Tue Jun 30 08:31:17 2009 -0700
@@ -81,10 +81,9 @@
 smb_com_query_information2(smb_request_t *sr)
 {
 	smb_node_t *node;
-	smb_attr_t *attr;
+	smb_attr_t attr;
 	u_offset_t size64;
 	uint32_t datasz, allocsz;
-	uint16_t dattr;
 	int rc;
 
 	smbsr_lookup_file(sr);
@@ -99,26 +98,29 @@
 	}
 
 	node = sr->fid_ofile->f_node;
-	attr = &node->attr;
+	if (smb_node_getattr(sr, node, &attr) != 0) {
+		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+		    ERRDOS, ERROR_INTERNAL_ERROR);
+		return (SDRC_ERROR);
+	}
 
-	dattr = smb_node_get_dosattr(node);
-	size64 = smb_node_get_size(node, attr);
+	size64 =  attr.sa_vattr.va_size;
 	datasz = (size64 > UINT_MAX) ? UINT_MAX : (uint32_t)size64;
 
-	size64 = attr->sa_vattr.va_nblocks * DEV_BSIZE;
+	size64 = attr.sa_vattr.va_nblocks * DEV_BSIZE;
 	allocsz = (size64 > UINT_MAX) ? UINT_MAX : (uint32_t)size64;
 
 	rc = smbsr_encode_result(sr, 11, 0, "byyyllww",
-	    11,						/* wct */
-	    smb_gmt2local(sr, attr->sa_crtime.tv_sec),
+	    11,				/* wct */
+	    smb_gmt2local(sr, attr.sa_crtime.tv_sec),
 	    /* LastAccessTime */
-	    smb_gmt2local(sr, attr->sa_vattr.va_atime.tv_sec),
+	    smb_gmt2local(sr, attr.sa_vattr.va_atime.tv_sec),
 	    /* LastWriteTime */
-	    smb_gmt2local(sr, attr->sa_vattr.va_mtime.tv_sec),
+	    smb_gmt2local(sr, attr.sa_vattr.va_mtime.tv_sec),
 	    datasz,
 	    allocsz,
-	    dattr,					/* FileAttributes */
-	    0);						/* bcc */
+	    attr.sa_dosattr & FILE_ATTRIBUTE_MASK,
+	    0);				/* bcc */
 
 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_read.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_read.c	Tue Jun 30 08:31:17 2009 -0700
@@ -514,7 +514,7 @@
 	case STYPE_DISKTREE:
 		node = ofile->f_node;
 
-		if (node->attr.sa_vattr.va_type != VDIR) {
+		if (!smb_node_is_dir(node)) {
 			rc = smb_lock_range_access(sr, node, param->rw_offset,
 			    param->rw_count, B_FALSE);
 			if (rc != NT_STATUS_SUCCESS) {
@@ -535,13 +535,10 @@
 			break;
 		}
 
-		(void) smb_sync_fsattr(sr, sr->user_cr, node);
-
 		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->vdb_uio,
-		    &node->attr);
+		rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio);
 
 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
--- a/usr/src/uts/common/fs/smbsrv/smb_rename.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c	Tue Jun 30 08:31:17 2009 -0700
@@ -44,7 +44,7 @@
 
 static int smb_do_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
 static int smb_make_link(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
-static int smb_rename_check_attr(smb_node_t *, uint16_t);
+static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t);
 static void smb_rename_set_error(smb_request_t *, int);
 
 /*
@@ -141,7 +141,7 @@
 
 	src_node = src_fqi->fq_fnode;
 
-	if ((rc = smb_rename_check_attr(src_node, src_fqi->fq_sattr)) != 0)
+	if ((rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr)) != 0)
 		goto rename_cleanup_nodes;
 
 	/*
@@ -387,7 +387,7 @@
 
 	src_fnode = src_fqi->fq_fnode;
 
-	if ((rc = smb_rename_check_attr(src_fnode, src_fqi->fq_sattr)) != 0)
+	if ((rc = smb_rename_check_attr(sr, src_fnode, src_fqi->fq_sattr)) != 0)
 		goto link_cleanup_nodes;
 
 	/*
@@ -462,14 +462,19 @@
 }
 
 static int
-smb_rename_check_attr(smb_node_t *node, uint16_t sattr)
+smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
 {
-	uint16_t dosattr = smb_node_get_dosattr(node);
+	smb_attr_t attr;
 
-	if ((dosattr & FILE_ATTRIBUTE_HIDDEN) && !(SMB_SEARCH_HIDDEN(sattr)))
+	if (smb_node_getattr(sr, node, &attr) != 0)
+		return (EIO);
+
+	if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
+	    !(SMB_SEARCH_HIDDEN(sattr)))
 		return (ESRCH);
 
-	if ((dosattr & FILE_ATTRIBUTE_SYSTEM) && !(SMB_SEARCH_SYSTEM(sattr)))
+	if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
+	    !(SMB_SEARCH_SYSTEM(sattr)))
 		return (ESRCH);
 
 	return (0);
@@ -497,7 +502,8 @@
 	{ ENOENT, ERROR_FILE_NOT_FOUND,	NT_STATUS_OBJECT_NAME_NOT_FOUND },
 	{ ESRCH,  ERROR_FILE_NOT_FOUND,	NT_STATUS_NO_SUCH_FILE },
 	{ EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER },
-	{ EACCES, ERROR_ACCESS_DENIED,	NT_STATUS_ACCESS_DENIED }
+	{ EACCES, ERROR_ACCESS_DENIED,	NT_STATUS_ACCESS_DENIED },
+	{ EIO,    ERROR_INTERNAL_ERROR,	NT_STATUS_INTERNAL_ERROR }
 	};
 
 	int i;
--- a/usr/src/uts/common/fs/smbsrv/smb_seek.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_seek.c	Tue Jun 30 08:31:17 2009 -0700
@@ -109,9 +109,6 @@
 
 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
 
-	if (mode == SMB_SEEK_END)
-		(void) smb_set_file_size(sr, sr->fid_ofile->f_node);
-
 	if ((rc = smb_ofile_seek(sr->fid_ofile, mode, off, &off_ret)) != 0) {
 		if (rc == EINVAL) {
 			smbsr_error(sr, 0, ERRDOS, ERRbadfunc);
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c	Tue Jun 30 08:31:17 2009 -0700
@@ -882,7 +882,6 @@
 	int		error = 0;
 	smb_node_t	*fnode = NULL;
 	smb_node_t	*dnode;
-	smb_attr_t	ret_attr;
 	char		last_comp[MAXNAMELEN];
 	smb_request_t	*sr;
 
@@ -917,7 +916,7 @@
 	}
 
 	error = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
-	    sv->si_root_smb_node, dnode, last_comp, &fnode, &ret_attr);
+	    sv->si_root_smb_node, dnode, last_comp, &fnode);
 
 	smb_node_release(dnode);
 
@@ -980,7 +979,6 @@
 	smb_unexport_t	*ux;
 	smb_node_t	*fnode = NULL;
 	smb_node_t	*dnode;
-	smb_attr_t	ret_attr;
 	char		last_comp[MAXNAMELEN];
 	int		rc;
 
@@ -1016,7 +1014,7 @@
 	}
 
 	rc = smb_fsop_lookup(sr, kcred, SMB_FOLLOW_LINKS, sv->si_root_smb_node,
-	    dnode, last_comp, &fnode, &ret_attr);
+	    dnode, last_comp, &fnode);
 
 	smb_node_release(dnode);
 	smb_request_free(sr);
--- a/usr/src/uts/common/fs/smbsrv/smb_set_information.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_information.c	Tue Jun 30 08:31:17 2009 -0700
@@ -74,11 +74,10 @@
 {
 	int			rc;
 	unsigned short		dattr;
-	timestruc_t		utime;
 	char			*path;
-	struct smb_node		*dir_node;
+	smb_node_t		*dir_node;
+	smb_node_t		*node;
 	smb_attr_t		attr;
-	struct smb_node		*node;
 	char			*name;
 	uint32_t		last_wtime;
 
@@ -106,8 +105,8 @@
 		return (SDRC_ERROR);
 	}
 
-	rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
-	    sr->tid_tree->t_snode, dir_node, name, &node, &attr);
+	rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+	    sr->tid_tree->t_snode, dir_node, name, &node);
 	if (rc != 0) {
 		smb_node_release(dir_node);
 		kmem_free(name, MAXNAMELEN);
@@ -122,7 +121,7 @@
 	 * target is not a directory.
 	 */
 	if ((dattr & FILE_ATTRIBUTE_DIRECTORY) &&
-	    (node->attr.sa_vattr.va_type != VDIR)) {
+	    (!smb_node_is_dir(node))) {
 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
 		    ERRDOS, ERROR_INVALID_PARAMETER);
 		return (SDRC_ERROR);
@@ -135,14 +134,18 @@
 		(void) smb_oplock_break(node, sr->session, B_FALSE);
 	}
 
+	bzero(&attr, sizeof (smb_attr_t));
+
 	/*
 	 * For compatibility with Windows Servers, if the specified
 	 * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change
 	 * the file's attributes.
 	 * Note - this is different from TRANS2_SET_PATH/FILE_INFORMATION
 	 */
-	if (dattr != FILE_ATTRIBUTE_NORMAL)
-		smb_node_set_dosattr(node, dattr);
+	if (dattr != FILE_ATTRIBUTE_NORMAL) {
+		attr.sa_dosattr = dattr;
+		attr.sa_mask |= SMB_AT_DOSATTR;
+	}
 
 	/*
 	 * The behaviour when the time field is set to -1
@@ -151,12 +154,11 @@
 	 * need not be changed.
 	 */
 	if (last_wtime != 0 && last_wtime != 0xFFFFFFFF) {
-		utime.tv_sec = smb_local2gmt(sr, last_wtime);
-		utime.tv_nsec = 0;
-		smb_node_set_time(node, 0, &utime, 0, 0, SMB_AT_MTIME);
+		attr.sa_vattr.va_mtime.tv_sec = smb_local2gmt(sr, last_wtime);
+		attr.sa_mask |= SMB_AT_MTIME;
 	}
 
-	rc = smb_sync_fsattr(sr, sr->user_cr, node);
+	rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
 	smb_node_release(node);
 	kmem_free(name, MAXNAMELEN);
 
--- a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c	Tue Jun 30 08:31:17 2009 -0700
@@ -72,9 +72,8 @@
 smb_com_set_information2(smb_request_t *sr)
 {
 	uint32_t creation, last_access, last_write;  /* times */
-	timestruc_t		crtime, mtime, atime;
-	unsigned int 		what = 0;
-	struct smb_node		*node;
+	smb_attr_t		attr;
+	smb_node_t		*node;
 	int			rc;
 
 	rc = smbsr_decode_vwv(sr, "wyyy", &sr->smb_fid,
@@ -97,30 +96,30 @@
 		return (SDRC_ERROR);
 	}
 
+	bzero(&attr, sizeof (smb_attr_t));
+
 	/*
 	 * The behaviour when the time field is set to -1
 	 * is not documented but is generally treated like 0,
 	 * meaning that that server file system assigned value
 	 * need not be changed.
 	 */
-	crtime.tv_nsec = mtime.tv_nsec = atime.tv_nsec = 0;
 	if (last_write != 0 && last_write != UINT_MAX) {
-		mtime.tv_sec = smb_local2gmt(sr, last_write);
-		what |= SMB_AT_MTIME;
+		attr.sa_vattr.va_mtime.tv_sec = smb_local2gmt(sr, last_write);
+		attr.sa_mask |= SMB_AT_MTIME;
 	}
 
 	if (creation != 0 && creation != UINT_MAX) {
-		crtime.tv_sec = smb_local2gmt(sr, creation);
-		what |= SMB_AT_CRTIME;
+		attr.sa_crtime.tv_sec = smb_local2gmt(sr, creation);
+		attr.sa_mask |= SMB_AT_CRTIME;
 	}
 
 	if (last_access != 0 && last_access != UINT_MAX) {
-		atime.tv_sec = smb_local2gmt(sr, last_access);
-		what |= SMB_AT_ATIME;
+		attr.sa_vattr.va_atime.tv_sec = smb_local2gmt(sr, last_access);
+		attr.sa_mask |= SMB_AT_ATIME;
 	}
 
-	smb_node_set_time(node, &crtime, &mtime, &atime, 0, what);
-	rc = smb_sync_fsattr(sr, sr->user_cr, node);
+	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
 	if (rc) {
 		smbsr_errno(sr, rc);
 		return (SDRC_ERROR);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c	Tue Jun 30 08:31:17 2009 -0700
@@ -52,6 +52,8 @@
 #include <smbsrv/smb_fsops.h>
 
 uint32_t smb_pad_align(uint32_t offset, uint32_t align);
+extern int smb_query_all_info_filename(smb_tree_t *, smb_node_t *,
+    char *, size_t);
 
 
 /*
@@ -69,30 +71,26 @@
  * delete-on-close status returned by Trans2QueryFileInfo will be set
  * immediately.
  */
-
 smb_sdrc_t
 smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
 {
 	static smb_attr_t pipe_attr;
+	smb_attr_t file_attr;
 	unsigned short	infolev, dattr = 0;
 	u_offset_t	datasz = 0, allocsz = 0;
 	smb_attr_t	*ap = NULL;
 	char		*namep = NULL;
 	char		*filename = NULL, *alt_nm_ptr = NULL;
 	int		filename_len = 0;
-	struct smb_node	*dir_snode = NULL;
+	smb_node_t	*node = NULL; /* only set for SMB_FTYPE_DISK files */
+	smb_node_t	*dir_snode = NULL;
 	timestruc_t	*creation_time = NULL;
 	unsigned char	delete_on_close = 0;
 	unsigned char	is_dir = 0;
 	char		*filebuf = NULL;
-
-	/*
-	 *  buffer for mangled name and shortname are allocated
-	 *  much higher than required space. Optimization
-	 *  here should be performed along with mangled_name & shortname
-	 *  of query path information.
-	 */
-	char *mangled_name = 0;
+	char		short_name[SMB_SHORTNAMELEN];
+	char		name83[SMB_SHORTNAMELEN];
+	int		rc;
 
 	if (smb_mbc_decodef(&xa->req_param_mb, "ww", &sr->smb_fid,
 	    &infolev) != 0) {
@@ -108,10 +106,8 @@
 	switch (sr->fid_ofile->f_ftype) {
 	case SMB_FTYPE_DISK:
 		{
-		/*
-		 * The node is only valid for SMB_FTYPE_DISK files.
-		 */
-		struct smb_node *node = sr->fid_ofile->f_node;
+		/* The node is only valid for SMB_FTYPE_DISK files. */
+		node = sr->fid_ofile->f_node;
 
 		/*
 		 * For some reason NT will not show the security tab in the root
@@ -129,11 +125,17 @@
 		if (strcmp(namep, ".") == 0 && filename_len == 1)
 			filename_len = 2;
 
-		creation_time = smb_node_get_crtime(node);
-		dattr = smb_node_get_dosattr(node);
+		ap = &file_attr;
+		if (smb_node_getattr(sr, node, ap) != 0) {
+			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+			    ERRDOS, ERROR_INTERNAL_ERROR);
+			return (SDRC_ERROR);
+		}
 
-		ap = &node->attr;
-		if (ap->sa_vattr.va_type == VDIR) {
+		dattr = ap->sa_dosattr;
+		creation_time = &ap->sa_crtime;
+
+		if (smb_node_is_dir(node)) {
 			is_dir = 1;
 			datasz = allocsz = 0;
 		} else {
@@ -172,8 +174,7 @@
 		return (SDRC_ERROR);
 	}
 
-	filebuf = kmem_alloc(MAXNAMELEN+1, KM_SLEEP);
-	mangled_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+	filebuf = kmem_alloc(MAXPATHLEN+1, KM_SLEEP);
 
 	switch (infolev) {
 	case SMB_FILE_ACCESS_INFORMATION:
@@ -219,6 +220,7 @@
 
 	case SMB_INFO_QUERY_EAS_FROM_LIST:
 	case SMB_INFO_QUERY_ALL_EAS:
+	case SMB_FILE_EA_INFORMATION:
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
 		break;
@@ -263,6 +265,7 @@
 		break;
 
 	case SMB_QUERY_FILE_NAME_INFO:
+	case SMB_FILE_NAME_INFORMATION:
 		/*
 		 * It looks like NT doesn't know what to do with the name "."
 		 * so we convert it to "\\" to indicate the root directory.
@@ -290,6 +293,7 @@
 		break;
 
 	case SMB_QUERY_FILE_ALL_INFO:
+	case SMB_FILE_ALL_INFORMATION:
 		/*
 		 * The reply of this information level on the
 		 * wire doesn't match with protocol specification.
@@ -304,6 +308,19 @@
 		 * AlignmentRequirement in spec. that aren't sent
 		 * on the wire.
 		 */
+		if (node) {
+			rc = smb_query_all_info_filename(sr->tid_tree, node,
+			    filebuf, MAXPATHLEN);
+			if (rc != 0) {
+				smbsr_errno(sr, rc);
+				kmem_free(filebuf, MAXPATHLEN+1);
+				return (SDRC_ERROR);
+			}
+			filename = filebuf;
+			filename_len = smb_ascii_or_unicode_strlen(sr,
+			    filename);
+		}
+
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
 		    creation_time,
@@ -317,37 +334,38 @@
 		    delete_on_close,
 		    is_dir,
 		    0);
+
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
 		    sr, filename_len, filename);
 		break;
 
 	case SMB_QUERY_FILE_ALT_NAME_INFO:
+	case SMB_FILE_ALT_NAME_INFORMATION:
 		/*
 		 * Conform to the rule used by Windows NT/2003 servers.
-		 * Shortname is created only if either the
-		 * filename or extension portion of a file is made up of
-		 * mixed case. This is handled in os/libnt/nt_mangle_name.c.
+		 * Shortname is created only if either the filename or
+		 * extension portion of a file is made up of mixed case.
 		 *
 		 * If the shortname is generated, it will be returned as
-		 * the alternative name.  Otherwise, converts the original
-		 * name to all upper-case and returns it as the alternative
-		 * name.  This is how Windows NT/2003 servers behave.  However,
-		 * Windows 2000 seems to preserve the case of the original
-		 * name, and returns it as the alternative name.
+		 * the alternative name.  Otherwise, convert the original
+		 * name to all upper-case and return it as the alternative
+		 * name.
 		 */
-		alt_nm_ptr = (*mangled_name == 0) ?
-		    utf8_strupr(filename) : mangled_name;
+		(void) smb_mangle_name(ap->sa_vattr.va_nodeid,
+		    filename, short_name, name83, 0);
+		alt_nm_ptr = (*short_name == 0) ?
+		    utf8_strupr(filename) : short_name;
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
 		    mts_wcequiv_strlen(alt_nm_ptr), alt_nm_ptr);
 		break;
 
 	case SMB_QUERY_FILE_STREAM_INFO:
+	case SMB_FILE_STREAM_INFORMATION:
 		{
 		struct smb_node *node = sr->fid_ofile->f_node;
 		if (dir_snode == NULL) {
-			kmem_free(filebuf, MAXNAMELEN+1);
-			kmem_free(mangled_name, MAXNAMELEN);
+			kmem_free(filebuf, MAXPATHLEN+1);
 			smbsr_error(sr, 0, ERRDOS, ERRbadfile);
 			return (SDRC_ERROR);
 		}
@@ -367,11 +385,18 @@
 		break;
 		}
 	case SMB_QUERY_FILE_COMPRESSION_INFO:
+	case SMB_FILE_COMPRESSION_INFORMATION:
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
 		    datasz, 0, 0, 0, 0);
 		break;
 
+	case SMB_FILE_INTERNAL_INFORMATION:
+		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "q",
+		    ap->sa_vattr.va_nodeid);
+		break;
+
 	case SMB_FILE_ATTR_TAG_INFORMATION:
 		/*
 		 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
@@ -386,14 +411,12 @@
 		break;
 
 	default:
-		kmem_free(filebuf, MAXNAMELEN+1);
-		kmem_free(mangled_name, MAXNAMELEN);
+		kmem_free(filebuf, MAXPATHLEN+1);
 		smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
 		return (SDRC_ERROR);
 	}
 
-	kmem_free(filebuf, MAXNAMELEN+1);
-	kmem_free(mangled_name, MAXNAMELEN);
+	kmem_free(filebuf, MAXPATHLEN+1);
 	return (SDRC_SUCCESS);
 }
 
@@ -457,7 +480,7 @@
 	uint32_t next_offset;
 	uint32_t stream_nlen;
 	uint32_t pad;
-	u_offset_t datasz;
+	u_offset_t datasz, allocsz;
 	boolean_t is_dir;
 	smb_streaminfo_t *sinfo, *sinfo_next;
 	int rc = 0;
@@ -470,6 +493,7 @@
 	sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
 	is_dir = (attr->sa_vattr.va_type == VDIR);
 	datasz = attr->sa_vattr.va_size;
+	allocsz = attr->sa_vattr.va_nblocks * DEV_BSIZE;
 
 	odid = smb_odir_openat(sr, fnode);
 	if (odid != 0)
@@ -494,7 +518,7 @@
 			    smb_ascii_or_unicode_null_len(sr);
 
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr,
-		    next_offset, stream_nlen, datasz, datasz, stream_name);
+		    next_offset, stream_nlen, datasz, allocsz, stream_name);
 	}
 
 	/*
@@ -518,7 +542,7 @@
 		}
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.",
 		    sr, next_offset, stream_nlen,
-		    sinfo->si_size, sinfo->si_size,
+		    sinfo->si_size, sinfo->si_alloc_size,
 		    sinfo->si_name, pad);
 
 		(void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c	Tue Jun 30 08:31:17 2009 -0700
@@ -321,6 +321,8 @@
 #include <smbsrv/smb_vops.h>
 #include <smbsrv/smb_fsops.h>
 
+int smb_query_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t);
+
 /*
  * Function: int smb_com_trans2_query_path_information(struct smb_request *)
  */
@@ -334,7 +336,7 @@
 	smb_attr_t		*ap, ret_attr;
 	struct smb_node		*dir_node;
 	struct smb_node		*node;
-	char			*name;
+	char			*name, *namep;
 	char			short_name[SMB_SHORTNAMELEN];
 	char			name83[SMB_SHORTNAMELEN];
 	unsigned char		is_dir;
@@ -369,12 +371,12 @@
 	}
 
 	ap = &ret_attr;
-	name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
+	name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
 
 	if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
 	    sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
 	    != 0) {
-		kmem_free(name, MAXNAMELEN);
+		kmem_free(name, MAXPATHLEN);
 		if (rc == ENOENT)
 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
 			    ERRDOS, ERROR_FILE_NOT_FOUND);
@@ -383,10 +385,10 @@
 		return (SDRC_ERROR);
 	}
 
-	if ((rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
-	    sr->tid_tree->t_snode, dir_node, name, &node, ap)) != 0) {
+	if ((rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+	    sr->tid_tree->t_snode, dir_node, name, &node)) != 0) {
 		smb_node_release(dir_node);
-		kmem_free(name, MAXNAMELEN);
+		kmem_free(name, MAXPATHLEN);
 
 		if (rc == ENOENT)
 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
@@ -397,14 +399,22 @@
 	}
 
 	smb_node_release(dir_node);
-	(void) strcpy(name, node->od_name);
 
-	dattr = smb_node_get_dosattr(node);
-	if (ap->sa_vattr.va_type == VDIR) {
+	if (smb_node_getattr(sr, node, ap) != 0) {
+		smb_node_release(node);
+		kmem_free(name, MAXPATHLEN);
+		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+		    ERRDOS, ERROR_INTERNAL_ERROR);
+		return (SDRC_ERROR);
+	}
+
+	(void) strcpy(name, node->od_name);
+	namep = node->od_name;
+	dattr = ap->sa_dosattr;
+
+	if (smb_node_is_dir(node)) {
 		is_dir = 1;
-		/*
-		 * Win2K and NT reply with the size of directory file.
-		 */
+		/* Win2K and NT reply with the size of directory file */
 		datasz = allocsz = 0;
 	} else {
 		is_dir = 0;
@@ -491,21 +501,25 @@
 		break;
 
 	case SMB_QUERY_FILE_EA_INFO:
+	case SMB_FILE_EA_INFORMATION:
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
 		break;
 
 	case SMB_QUERY_FILE_NAME_INFO:
-		/*
-		 * If you have problems here, see the changes
-		 * in smb_trans2_query_file_information.c.
-		 */
+	case SMB_FILE_NAME_INFORMATION:
+		/* If the leading \ is missing, add it.  */
+		if (*namep != '\\') {
+			(void) snprintf(name, MAXNAMELEN, "\\%s", namep);
+			namep = name;
+		}
+		len = smb_ascii_or_unicode_strlen(sr, namep);
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
-		    smb_ascii_or_unicode_strlen(sr, name), name);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr, len, namep);
 		break;
 
 	case SMB_QUERY_FILE_ALL_INFO:
+	case SMB_FILE_ALL_INFORMATION:
 		/*
 		 * The reply of this information level on the
 		 * wire doesn't match with protocol specification.
@@ -520,6 +534,15 @@
 		 * AlignmentRequirement in spec. that aren't sent
 		 * on the wire.
 		 */
+		rc = smb_query_all_info_filename(sr->tid_tree, node,
+		    name, MAXPATHLEN);
+		if (rc != 0) {
+			smbsr_errno(sr, rc);
+			smb_node_release(node);
+			kmem_free(name, MAXPATHLEN);
+			return (SDRC_ERROR);
+		}
+
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
 		    &ap->sa_crtime,
@@ -533,11 +556,13 @@
 		    0,
 		    is_dir,
 		    0);
+
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
 		    smb_ascii_or_unicode_strlen(sr, name), name);
 		break;
 
 	case SMB_QUERY_FILE_ALT_NAME_INFO:
+	case SMB_FILE_ALT_NAME_INFORMATION:
 		/*
 		 * Conform to the rule used by Windows NT/2003 servers.
 		 * Shortname is created only if either the filename or
@@ -558,11 +583,13 @@
 		break;
 
 	case SMB_QUERY_FILE_STREAM_INFO:
+	case SMB_FILE_STREAM_INFORMATION:
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		smb_encode_stream_info(sr, xa, node, ap);
 		break;
 
 	case SMB_QUERY_FILE_COMPRESSION_INFO:
+	case SMB_FILE_COMPRESSION_INFORMATION:
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
 		(void) smb_mbc_encodef(&xa->rep_data_mb,
 		    "qwbbb3.", datasz, 0, 0, 0, 0);
@@ -589,12 +616,57 @@
 
 	default:
 		smb_node_release(node);
-		kmem_free(name, MAXNAMELEN);
+		kmem_free(name, MAXPATHLEN);
 		smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
 		return (SDRC_ERROR);
 	}
 
 	smb_node_release(node);
-	kmem_free(name, MAXNAMELEN);
+	kmem_free(name, MAXPATHLEN);
 	return (SDRC_SUCCESS);
 }
+
+
+/*
+ * smb_query_all_info_filename
+ *
+ * This format of filename is only used by the ALL_INFO level.
+ *
+ * Determine the absolute pathname of 'node' within the share.
+ * For example if the node represents file "test1.txt" in directory
+ * "dir1" on share "share1", the path would be: \share1\dir1\test1.txt
+ *
+ * If node represents a named stream, construct the pathname for the
+ * associated unnamed stream then append the stream name.
+ */
+int
+smb_query_all_info_filename(smb_tree_t *tree, smb_node_t *node,
+    char *buf, size_t buflen)
+{
+	char *sharename = tree->t_sharename;
+	int rc;
+	size_t len;
+	vnode_t *vp;
+
+	len = snprintf(buf, buflen, "\\%s", sharename);
+	if (len == (buflen - 1))
+		return (ENAMETOOLONG);
+
+	buf += len;
+	buflen -= len;
+
+	if (SMB_IS_STREAM(node))
+		vp = node->unnamed_stream_node->vp;
+	else
+		vp = node->vp;
+
+	rc = vnodetopath(tree->t_snode->vp, vp, buf, buflen, kcred);
+	if (rc == 0) {
+		(void) strsubst(buf, '/', '\\');
+
+		if (SMB_IS_STREAM(node))
+			(void) strlcat(buf, node->od_name, buflen);
+	}
+
+	return (rc);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c	Tue Jun 30 08:31:17 2009 -0700
@@ -104,7 +104,7 @@
 {
 	smb_trans2_setinfo_t *info;
 	smb_error_t smberr;
-	DWORD status;
+	uint32_t status;
 	int rc;
 
 	info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c	Tue Jun 30 08:31:17 2009 -0700
@@ -31,33 +31,33 @@
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/smb_fsops.h>
 
-static DWORD smb_set_standard_info(struct smb_request *sr,
-    smb_trans2_setinfo_t *info, smb_error_t *smberr);
+static uint32_t smb_set_standard_info(smb_request_t *,
+    smb_trans2_setinfo_t *, smb_error_t *);
 
-static DWORD smb_set_basic_info(struct smb_request *sr,
-    smb_trans2_setinfo_t *info, smb_error_t *smberr);
+static uint32_t smb_set_basic_info(smb_request_t *,
+    smb_trans2_setinfo_t *, smb_error_t *);
 
-static DWORD smb_set_disposition_info(struct smb_request *sr,
-    smb_trans2_setinfo_t *info, smb_error_t *smberr);
+static uint32_t smb_set_disposition_info(smb_request_t *,
+    smb_trans2_setinfo_t *, smb_error_t *);
 
-static DWORD smb_set_alloc_info(struct smb_request *sr,
-    smb_trans2_setinfo_t *info, smb_error_t *smberr);
+static uint32_t smb_set_alloc_info(smb_request_t *sr,
+    smb_trans2_setinfo_t *, smb_error_t *);
 
 /*LINTED E_STATIC_UNUSED*/
-static DWORD smb_set_mac_info(struct smb_request *sr,
-    smb_trans2_setinfo_t *info, smb_error_t *smberr);
+static uint32_t smb_set_mac_info(smb_request_t *,
+    smb_trans2_setinfo_t *, smb_error_t *);
 
 /*LINTED E_STATIC_UNUSED*/
-static DWORD smb_set_mac_addappl(struct smb_request *sr,
-    smb_trans2_setinfo_t *info, smb_error_t *smberr);
+static uint32_t smb_set_mac_addappl(smb_request_t *,
+    smb_trans2_setinfo_t *, smb_error_t *);
 
 /*LINTED E_STATIC_UNUSED*/
-static DWORD smb_set_mac_rmvappl(struct smb_request *sr,
-    smb_trans2_setinfo_t *info, smb_error_t *smberr);
+static uint32_t smb_set_mac_rmvappl(smb_request_t *,
+    smb_trans2_setinfo_t *, smb_error_t *);
 
 /*LINTED E_STATIC_UNUSED*/
-static DWORD smb_set_mac_addicon(struct smb_request *sr,
-    smb_trans2_setinfo_t *info, smb_error_t *smberr);
+static uint32_t smb_set_mac_addicon(smb_request_t *,
+    smb_trans2_setinfo_t *, smb_error_t *);
 
 static unsigned short smb_info_passthru(unsigned short infolevel);
 
@@ -67,10 +67,8 @@
  * This is a common function called by both Trans2SetFileInfo
  * and Trans2SetPathInfo.
  */
-DWORD
-smb_trans2_set_information(
-    struct smb_request *sr,
-    smb_trans2_setinfo_t *info,
+uint32_t
+smb_trans2_set_information(smb_request_t *sr, smb_trans2_setinfo_t *info,
     smb_error_t *smberr)
 {
 	info->level = smb_info_passthru(info->level);
@@ -153,75 +151,49 @@
 /*
  * smb_set_standard_info
  *
- * SMB_INFO_STANDARD
- *
- *  Data Block Encoding                Description
- *  ================================== =================================
- *
- *  SMB_DATE CreationDate;             Date when file was created
- *  SMB_TIME CreationTime;             Time when file was created
- *  SMB_DATE LastAccessDate;           Date of last file access
- *  SMB_TIME LastAccessTime;           Time of last file access
- *  SMB_DATE LastWriteDate;            Date of last write to the file
- *  SMB_TIME LastWriteTime;            Time of last write to the file
- *  ULONG  DataSize;                   File Size
- *  ULONG AllocationSize;              Size of filesystem allocation unit
- *  USHORT Attributes;                 File Attributes
- *
- * For exact compatibility with Windows (NT and later), the whole
- * request is decoded (to ensure that all 22 bytes are present),
- * and the DataSize, AllocationSize and Attributes values are
- * ignored.
+ * Sets standard file/path information.
  */
-static DWORD
-smb_set_standard_info(
-    struct smb_request *sr,
-    smb_trans2_setinfo_t *info,
+static uint32_t
+smb_set_standard_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
     smb_error_t *smberr)
 {
+	smb_attr_t attr;
 	uint32_t Creation, LastAccess, LastWrite;  /* times */
-	uint32_t DataSize, AllocationSize;
-	unsigned short Attributes;
-	unsigned int what = 0;
-	timestruc_t crtime, mtime, atime;
-	DWORD status = NT_STATUS_SUCCESS;
-	struct smb_node *node = info->node;
+	uint32_t status = NT_STATUS_SUCCESS;
+	smb_node_t *node = info->node;
 	int rc;
 
-	if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "yyyllw",
-	    &Creation,			/* CreationDate/Time */
-	    &LastAccess,		/* LastAccessDate/Time */
-	    &LastWrite,			/* LastWriteDate/Time */
-	    &DataSize,			/* File Size */
-	    &AllocationSize,		/* Block Size */
-	    &Attributes) != 0) {	/* File Attributes */
+	if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "yyy",
+	    &Creation,		/* CreationDate/Time */
+	    &LastAccess,	/* LastAccessDate/Time */
+	    &LastWrite) != 0) {	/* LastWriteDate/Time */
 		return (NT_STATUS_DATA_ERROR);
 	}
 
+	bzero(&attr, sizeof (smb_attr_t));
+
 	/*
 	 * The behaviour when the time field is set to -1
 	 * is not documented but is generally treated like 0,
 	 * meaning that that server file system assigned value
 	 * need not be changed.
 	 */
-	crtime.tv_nsec = mtime.tv_nsec = atime.tv_nsec = 0;
 	if (LastWrite != 0 && LastWrite != (uint32_t)-1) {
-		mtime.tv_sec = smb_local2gmt(sr, LastWrite);
-		what |= SMB_AT_MTIME;
+		attr.sa_vattr.va_mtime.tv_sec = smb_local2gmt(sr, LastWrite);
+		attr.sa_mask |= SMB_AT_MTIME;
 	}
 
 	if (Creation != 0 && Creation != (uint32_t)-1) {
-		crtime.tv_sec = smb_local2gmt(sr, Creation);
-		what |= SMB_AT_CRTIME;
+		attr.sa_crtime.tv_sec = smb_local2gmt(sr, Creation);
+		attr.sa_mask |= SMB_AT_CRTIME;
 	}
 
 	if (LastAccess != 0 && LastAccess != (uint32_t)-1) {
-		atime.tv_sec = smb_local2gmt(sr, LastAccess);
-		what |= SMB_AT_ATIME;
+		attr.sa_vattr.va_atime.tv_sec = smb_local2gmt(sr, LastAccess);
+		attr.sa_mask |= SMB_AT_ATIME;
 	}
 
-	smb_node_set_time(node, &crtime, &mtime, &atime, 0, what);
-	rc = smb_sync_fsattr(sr, sr->user_cr, node);
+	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
 	if (rc) {
 		smbsr_map_errno(rc, smberr);
 		status = NT_STATUS_UNSUCCESSFUL;
@@ -235,18 +207,15 @@
  *
  * Sets basic file/path information.
  */
-static DWORD
-smb_set_basic_info(
-    struct smb_request *sr,
-    smb_trans2_setinfo_t *info,
+static uint32_t
+smb_set_basic_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
     smb_error_t *smberr)
 {
+	smb_attr_t attr;
 	uint64_t NT_Creation, NT_LastAccess, NT_LastWrite, NT_Change;
 	unsigned short Attributes;
-	unsigned int what = 0;
-	timestruc_t crtime, mtime, atime, ctime;
-	struct smb_node *node = info->node;
-	DWORD status = NT_STATUS_SUCCESS;
+	smb_node_t *node = info->node;
+	uint32_t status = NT_STATUS_SUCCESS;
 	int rc;
 
 	if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "qqqqw",
@@ -258,6 +227,8 @@
 		return (NT_STATUS_DATA_ERROR);
 	}
 
+	bzero(&attr, sizeof (smb_attr_t));
+
 	/*
 	 * The behaviour when the time field is set to -1
 	 * is not documented but is generally treated like 0,
@@ -265,23 +236,23 @@
 	 * need not be changed.
 	 */
 	if (NT_Change != 0 && NT_Change != (uint64_t)-1) {
-		(void) nt_to_unix_time(NT_Change, &ctime);
-		what |= SMB_AT_CTIME;
+		(void) nt_to_unix_time(NT_Change, &attr.sa_vattr.va_ctime);
+		attr.sa_mask |= SMB_AT_CTIME;
 	}
 
 	if (NT_Creation != 0 && NT_Creation != (uint64_t)-1) {
-		(void) nt_to_unix_time(NT_Creation, &crtime);
-		what |= SMB_AT_CRTIME;
+		(void) nt_to_unix_time(NT_Creation, &attr.sa_crtime);
+		attr.sa_mask |= SMB_AT_CRTIME;
 	}
 
 	if (NT_LastWrite != 0 && NT_LastWrite != (uint64_t)-1) {
-		(void) nt_to_unix_time(NT_LastWrite, &mtime);
-		what |= SMB_AT_MTIME;
+		(void) nt_to_unix_time(NT_LastWrite, &attr.sa_vattr.va_mtime);
+		attr.sa_mask |= SMB_AT_MTIME;
 	}
 
 	if (NT_LastAccess != 0 && NT_LastAccess != (uint64_t)-1) {
-		(void) nt_to_unix_time(NT_LastAccess, &atime);
-		what |= SMB_AT_ATIME;
+		(void) nt_to_unix_time(NT_LastAccess, &attr.sa_vattr.va_atime);
+		attr.sa_mask |= SMB_AT_ATIME;
 	}
 
 	/*
@@ -295,17 +266,18 @@
 	 */
 	if (Attributes != 0) {
 		if ((Attributes & FILE_ATTRIBUTE_DIRECTORY) &&
-		    (node->attr.sa_vattr.va_type != VDIR)) {
+		    (!smb_node_is_dir(node))) {
 			smberr->status = NT_STATUS_INVALID_PARAMETER;
 			smberr->errcls = ERRDOS;
 			smberr->errcode = ERROR_INVALID_PARAMETER;
 			return (NT_STATUS_UNSUCCESSFUL);
 		}
-		smb_node_set_dosattr(node, Attributes);
+
+		attr.sa_dosattr = Attributes;
+		attr.sa_mask |= SMB_AT_DOSATTR;
 	}
 
-	smb_node_set_time(node, &crtime, &mtime, &atime, &ctime, what);
-	rc = smb_sync_fsattr(sr, sr->user_cr, node);
+	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
 	if (rc) {
 		smbsr_map_errno(rc, smberr);
 		status = NT_STATUS_UNSUCCESSFUL;
@@ -320,33 +292,26 @@
  *
  * Sets file allocation/end_of_file info
  */
-static DWORD
-smb_set_alloc_info(
-    struct smb_request *sr,
-    smb_trans2_setinfo_t *info,
+static uint32_t
+smb_set_alloc_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
     smb_error_t *smberr)
 {
+	smb_attr_t attr;
 	uint64_t DataSize;
-	DWORD status = NT_STATUS_SUCCESS;
-	struct smb_node *node = info->node;
+	uint32_t status = NT_STATUS_SUCCESS;
+	smb_node_t *node = info->node;
 	int rc;
 
 	if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "q", &DataSize) != 0)
 		return (NT_STATUS_DATA_ERROR);
 
-	if (node->attr.sa_vattr.va_size != DataSize) {
-		node->flags |= NODE_FLAGS_SET_SIZE;
-		node->n_size = (u_offset_t)DataSize;
-
-		/*
-		 * Ensure that the FS is consistent with the node cache
-		 * because the size flag can get cleared by subsequent
-		 * write requests without the inode ever being updated.
-		 */
-		if ((rc = smb_set_file_size(sr, node)) != 0) {
-			smbsr_map_errno(rc, smberr);
-			status = NT_STATUS_UNSUCCESSFUL;
-		}
+	bzero(&attr, sizeof (smb_attr_t));
+	attr.sa_mask = SMB_AT_SIZE;
+	attr.sa_vattr.va_size = (u_offset_t)DataSize;
+	rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
+	if (rc) {
+		smbsr_map_errno(rc, smberr);
+		status = NT_STATUS_UNSUCCESSFUL;
 	}
 
 	return (status);
@@ -385,11 +350,9 @@
  * node delete-on-close flag, which will result in the file not being
  * removed even after the last file handle is closed.
  */
-static DWORD
-smb_set_disposition_info(
-    smb_request_t		*sr,
-    smb_trans2_setinfo_t	*info,
-    smb_error_t			*smberr)
+static uint32_t
+smb_set_disposition_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
+    smb_error_t *smberr)
 {
 	unsigned char	mark_delete;
 	uint32_t	flags = 0;
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c	Tue Jun 30 08:31:17 2009 -0700
@@ -111,11 +111,10 @@
 smb_com_trans2_set_path_information(struct smb_request *sr, struct smb_xa *xa)
 {
 	smb_trans2_setinfo_t *info;
-	smb_attr_t ret_attr;
 	struct smb_node *dir_node;
 	struct smb_node *ret_snode;
 	smb_error_t smberr;
-	DWORD status;
+	uint32_t status;
 	int rc = 0;
 
 	info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
@@ -145,8 +144,8 @@
 		return (SDRC_ERROR);
 	}
 
-	rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
-	    sr->tid_tree->t_snode, dir_node, info->name, &ret_snode, &ret_attr);
+	rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+	    sr->tid_tree->t_snode, dir_node, info->name, &ret_snode);
 
 	smb_node_release(dir_node);
 
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c	Tue Jun 30 08:31:17 2009 -0700
@@ -420,9 +420,10 @@
 	 * values.
 	 */
 
-	if (rc == 0)
+	if (rc == 0) {
 		smb_vop_eaccess(sharevp, (int *)access, V_ACE_MASK, NULL, cred);
-
+		VN_RELE(sharevp);
+	}
 }
 
 /*
@@ -438,7 +439,6 @@
 	char			last_component[MAXNAMELEN];
 	smb_tree_t		*tree;
 	smb_share_t 		*si;
-	smb_attr_t		attr;
 	cred_t			*u_cred;
 	int			rc;
 	uint32_t		access = 0; /* read/write is assumed */
@@ -535,7 +535,7 @@
 	if (rc == 0) {
 		rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS,
 		    sr->sr_server->si_root_smb_node, dir_snode, last_component,
-		    &snode, &attr);
+		    &snode);
 
 		smb_node_release(dir_snode);
 	}
@@ -556,19 +556,12 @@
 	 * before the tree is allocated.
 	 */
 	smb_tree_acl_access(u_cred, sharename, snode->vp, &aclaccess);
-	/* if an error, then no share file -- default to no ACL */
-	if (rc == 0) {
-		/*
-		 * There need to be some permissions in order to have
-		 * any access.
-		 */
-		if ((aclaccess & ACE_ALL_PERMS) == 0) {
-			smb_tree_log(sr, sharename, "access denied: share ACL");
-			smbsr_error(sr, 0, ERRSRV, ERRaccess);
-			kmem_free(si, sizeof (smb_share_t));
-			smb_node_release(snode);
-			return (NULL);
-		}
+	if ((aclaccess & ACE_ALL_PERMS) == 0) {
+		smb_tree_log(sr, sharename, "access denied: share ACL");
+		smbsr_error(sr, 0, ERRSRV, ERRaccess);
+		kmem_free(si, sizeof (smb_share_t));
+		smb_node_release(snode);
+		return (NULL);
 	}
 
 	/*
--- a/usr/src/uts/common/fs/smbsrv/smb_util.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_util.c	Tue Jun 30 08:31:17 2009 -0700
@@ -2016,49 +2016,6 @@
 }
 
 /*
- * smb_sync_fsattr
- *
- * Sync file's attributes with file system.
- * The sync takes place based on node->what and node->flags
- * values.
- */
-int
-smb_sync_fsattr(struct smb_request *sr, cred_t *cr, smb_node_t *node)
-{
-	uint32_t what;
-	int rc = 0;
-
-	if (node->flags & NODE_FLAGS_SET_SIZE) {
-		node->flags &= ~NODE_FLAGS_SET_SIZE;
-		node->what |= SMB_AT_SIZE;
-		node->attr.sa_vattr.va_size = node->n_size;
-	}
-
-	if (node->what) {
-		/*
-		 * This is to prevent another thread from starting
-		 * a setattr should this one go to sleep
-		 */
-		what = node->what;
-		node->what = 0;
-
-		node->attr.sa_mask = what;
-
-		rc = smb_fsop_setattr(sr, cr, node, &node->attr, &node->attr);
-
-		if (rc) {
-			/* setattr failed, restore the dirty state? */
-			node->what = what;
-		} else {
-			if (what & SMB_AT_ATIME)
-				node->flags &= ~NODE_FLAGS_SYNCATIME;
-		}
-	}
-
-	return (rc);
-}
-
-/*
  * smb_cred_create_privs
  *
  * Creates a duplicate credential that contains system privileges for
--- a/usr/src/uts/common/fs/smbsrv/smb_vops.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c	Tue Jun 30 08:31:17 2009 -0700
@@ -385,8 +385,8 @@
 	if (unnamed_vp) {
 		ret_attr->sa_vattr.va_type = VREG;
 
-		if (ret_attr->sa_mask & SMB_AT_SIZE) {
-			tmp_attr.sa_vattr.va_mask = AT_SIZE;
+		if (ret_attr->sa_mask & (SMB_AT_SIZE | SMB_AT_NBLOCKS)) {
+			tmp_attr.sa_vattr.va_mask = AT_SIZE | AT_NBLOCKS;
 
 			error = VOP_GETATTR(vp, &tmp_attr.sa_vattr,
 			    flags, cr, &smb_ct);
@@ -394,6 +394,8 @@
 				return (error);
 
 			ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size;
+			ret_attr->sa_vattr.va_nblocks =
+			    tmp_attr.sa_vattr.va_nblocks;
 		}
 	}
 
@@ -423,7 +425,7 @@
  * with the (unnamed stream) file.
  */
 int
-smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
+smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *attr,
     int flags, cred_t *cr)
 {
 	int error = 0;
@@ -432,11 +434,17 @@
 	xvattr_t xvattr;
 	vattr_t *vap;
 
+	if (attr->sa_mask & SMB_AT_DOSATTR) {
+		attr->sa_dosattr &=
+		    (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY |
+		    FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+	}
+
 	if (unnamed_vp) {
 		use_vp = unnamed_vp;
-		if (set_attr->sa_mask & SMB_AT_SIZE) {
+		if (attr->sa_mask & SMB_AT_SIZE) {
 			at_size = 1;
-			set_attr->sa_mask &= ~SMB_AT_SIZE;
+			attr->sa_mask &= ~SMB_AT_SIZE;
 		}
 	} else {
 		use_vp = vp;
@@ -447,24 +455,23 @@
 	 * but rather sa_mask.
 	 */
 
-	set_attr->sa_vattr.va_mask = 0;
+	attr->sa_vattr.va_mask = 0;
 
 	if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
-		smb_vop_setup_xvattr(set_attr, &xvattr);
+		smb_vop_setup_xvattr(attr, &xvattr);
 		vap = &xvattr.xva_vattr;
 	} else {
-		smb_sa_to_va_mask(set_attr->sa_mask,
-		    &set_attr->sa_vattr.va_mask);
-		vap = &set_attr->sa_vattr;
+		smb_sa_to_va_mask(attr->sa_mask,
+		    &attr->sa_vattr.va_mask);
+		vap = &attr->sa_vattr;
 	}
 
 	if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0)
 		return (error);
 
 	if (at_size) {
-		set_attr->sa_vattr.va_mask = AT_SIZE;
-		error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr,
-		    &smb_ct);
+		attr->sa_vattr.va_mask = AT_SIZE;
+		error = VOP_SETATTR(vp, &attr->sa_vattr, flags, kcred, &smb_ct);
 	}
 
 	return (error);
--- a/usr/src/uts/common/fs/smbsrv/smb_vss.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_vss.c	Tue Jun 30 08:31:17 2009 -0700
@@ -135,7 +135,6 @@
 	char *snapname;
 	char *nodepath;
 	char gmttoken[SMB_VSS_GMT_SIZE];
-	smb_attr_t attr;
 	vnode_t *fsrootvp;
 	vnode_t *vp = NULL;
 	int err = 0;
@@ -196,7 +195,7 @@
 		}
 
 		*vss_root_node = smb_node_lookup(sr, NULL, kcred, vp,
-		    gmttoken, cur_node, NULL, &attr);
+		    gmttoken, cur_node, NULL);
 		VN_RELE(vp);
 
 		if (*vss_root_node == NULL) {
@@ -212,7 +211,7 @@
 
 		if (vp) {
 			*vss_cur_node = smb_node_lookup(sr, NULL, kcred, vp,
-			    gmttoken, cur_node, NULL, &attr);
+			    gmttoken, cur_node, NULL);
 			VN_RELE(vp);
 
 			if (*vss_cur_node != NULL) {
--- a/usr/src/uts/common/fs/smbsrv/smb_write.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_write.c	Tue Jun 30 08:31:17 2009 -0700
@@ -461,7 +461,7 @@
 static int
 smb_write_common(smb_request_t *sr, smb_rw_param_t *param)
 {
-	struct smb_ofile *ofile = sr->fid_ofile;
+	smb_ofile_t *ofile = sr->fid_ofile;
 	smb_node_t *node;
 	int stability = 0;
 	uint32_t lcount;
@@ -471,7 +471,7 @@
 	case STYPE_DISKTREE:
 		node = ofile->f_node;
 
-		if (node->attr.sa_vattr.va_type != VDIR) {
+		if (!smb_node_is_dir(node)) {
 			rc = smb_lock_range_access(sr, node, param->rw_offset,
 			    param->rw_count, B_TRUE);
 			if (rc != NT_STATUS_SUCCESS) {
@@ -487,19 +487,12 @@
 		}
 
 		rc = smb_fsop_write(sr, sr->user_cr, node,
-		    &param->rw_vdb.vdb_uio, &lcount, &node->attr, stability);
+		    &param->rw_vdb.vdb_uio, &lcount, stability);
 
 		if (rc)
 			return (rc);
 
-		node->flags |= NODE_FLAGS_SYNCATIME;
-
-		if (node->flags & NODE_FLAGS_SET_SIZE) {
-			if ((param->rw_offset + lcount) >= node->n_size) {
-				node->flags &= ~NODE_FLAGS_SET_SIZE;
-				node->n_size = param->rw_offset + lcount;
-			}
-		}
+		smb_ofile_set_write_time_pending(ofile);
 
 		param->rw_count = lcount;
 		break;
@@ -529,38 +522,27 @@
  * Truncate a disk file to the specified offset.
  * Typically, w_count will be zero here.
  *
+ * Note that smb_write_andx cannot be used to reduce the file size so,
+ * if this is required, smb_write is called with a count of zero and
+ * the appropriate file length in offset. The file should be resized
+ * to the length specified by the offset.
+ *
  * Returns errno values.
  */
 static int
 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param)
 {
-	struct smb_ofile *ofile = sr->fid_ofile;
+	smb_ofile_t *ofile = sr->fid_ofile;
 	smb_node_t *node = ofile->f_node;
-	boolean_t append_only = B_FALSE;
+	smb_attr_t attr;
 	uint32_t status;
 	int rc;
 
 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0)
 		return (0);
 
-	status = smb_ofile_access(sr->fid_ofile, sr->user_cr, FILE_WRITE_DATA);
-	if (status != NT_STATUS_SUCCESS) {
-		status = smb_ofile_access(sr->fid_ofile, sr->user_cr,
-		    FILE_APPEND_DATA);
-		if (status != NT_STATUS_SUCCESS)
-			return (EACCES);
-		else
-			append_only = B_TRUE;
-	}
-
 	mutex_enter(&node->n_mutex);
-
-	if (append_only && (param->rw_offset < node->n_size)) {
-		mutex_exit(&node->n_mutex);
-		return (EACCES);
-	}
-
-	if (node->attr.sa_vattr.va_type != VDIR) {
+	if (!smb_node_is_dir(node)) {
 		status = smb_lock_range_access(sr, node, param->rw_offset,
 		    param->rw_count, B_TRUE);
 		if (status != NT_STATUS_SUCCESS) {
@@ -570,13 +552,13 @@
 			return (EACCES);
 		}
 	}
-
-	node->flags |= NODE_FLAGS_SET_SIZE;
-	node->n_size = param->rw_offset;
-
 	mutex_exit(&node->n_mutex);
 
-	if ((rc = smb_set_file_size(sr, node)) != 0)
+	bzero(&attr, sizeof (smb_attr_t));
+	attr.sa_mask = SMB_AT_SIZE;
+	attr.sa_vattr.va_size = param->rw_offset;
+	rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr);
+	if (rc != 0)
 		return (rc);
 
 	mutex_enter(&ofile->f_mutex);
@@ -584,38 +566,3 @@
 	mutex_exit(&ofile->f_mutex);
 	return (0);
 }
-
-/*
- * Set the file size using the value in the node. The file will only be
- * updated if NODE_FLAGS_SET_SIZE is set.  It is safe to pass a null node
- * pointer, we just return success.
- *
- * The node attributes are refreshed here from the file system. So any
- * attributes that are affected by file size changes, i.e. the mtime,
- * will be current.
- *
- * Note that smb_write_andx cannot be used to reduce the file size so,
- * if this is required, smb_write is called with a count of zero and
- * the appropriate file length in offset. The file should be resized
- * to the length specified by the offset.
- */
-int
-smb_set_file_size(smb_request_t *sr, smb_node_t *node)
-{
-	smb_attr_t new_attr;
-
-	if (node == NULL)
-		return (0);
-
-	if ((node->flags & NODE_FLAGS_SET_SIZE) == 0)
-		return (0);
-
-	node->flags &= ~NODE_FLAGS_SET_SIZE;
-
-	bzero(&new_attr, sizeof (new_attr));
-	new_attr.sa_vattr.va_size = node->n_size;
-	new_attr.sa_mask = SMB_AT_SIZE;
-
-	return (smb_fsop_setattr(sr, sr->user_cr, node, &new_attr,
-	    &node->attr));
-}
--- a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c	Tue Jun 30 08:31:17 2009 -0700
@@ -274,7 +274,7 @@
 		/*
 		 * See comments in smb_write.c
 		 */
-		if (fnode->attr.sa_vattr.va_type != VDIR) {
+		if (!smb_node_is_dir(fnode)) {
 			rc = smb_lock_range_access(sr, fnode, off,
 			    count, B_TRUE);
 			if (rc != NT_STATUS_SUCCESS) {
@@ -498,19 +498,10 @@
 	} else {
 		fnode = sr->fid_ofile->f_node;
 		rc = smb_fsop_write(sr, sr->user_cr, fnode,
-		    uiop, lcountp, &fnode->attr, stability);
-
-		if (rc == 0) {
-
-			fnode->flags |= NODE_FLAGS_SYNCATIME;
+		    uiop, lcountp, stability);
 
-			if (fnode->flags & NODE_FLAGS_SET_SIZE) {
-				if ((*offp + *lcountp) >= fnode->n_size) {
-					fnode->flags &= ~NODE_FLAGS_SET_SIZE;
-					fnode->n_size = *offp + *lcountp;
-				}
-			}
-		}
+		if (rc == 0)
+			smb_ofile_set_write_time_pending(sr->fid_ofile);
 	}
 
 	*offp += *lcountp;
--- a/usr/src/uts/common/smbsrv/cifs.h	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/smbsrv/cifs.h	Tue Jun 30 08:31:17 2009 -0700
@@ -601,12 +601,18 @@
 
 
 /* NT passthrough levels */
-#define	SMB_INFO_PASSTHROUGH		1000
-#define	SMB_FILE_BASIC_INFORMATION	(SMB_INFO_PASSTHROUGH + 4)
-#define	SMB_FILE_STANDARD_INFORMATION	(SMB_INFO_PASSTHROUGH + 5)
-#define	SMB_FILE_INTERNAL_INFORMATION	(SMB_INFO_PASSTHROUGH + 6)
-#define	SMB_FILE_ACCESS_INFORMATION	(SMB_INFO_PASSTHROUGH + 8)
-#define	SMB_FILE_ATTR_TAG_INFORMATION	(SMB_INFO_PASSTHROUGH + 35)
+#define	SMB_INFO_PASSTHROUGH			1000
+#define	SMB_FILE_BASIC_INFORMATION		(SMB_INFO_PASSTHROUGH + 4)
+#define	SMB_FILE_STANDARD_INFORMATION		(SMB_INFO_PASSTHROUGH + 5)
+#define	SMB_FILE_INTERNAL_INFORMATION		(SMB_INFO_PASSTHROUGH + 6)
+#define	SMB_FILE_EA_INFORMATION			(SMB_INFO_PASSTHROUGH + 7)
+#define	SMB_FILE_ACCESS_INFORMATION		(SMB_INFO_PASSTHROUGH + 8)
+#define	SMB_FILE_NAME_INFORMATION		(SMB_INFO_PASSTHROUGH + 9)
+#define	SMB_FILE_ALL_INFORMATION		(SMB_INFO_PASSTHROUGH + 18)
+#define	SMB_FILE_ALT_NAME_INFORMATION		(SMB_INFO_PASSTHROUGH + 21)
+#define	SMB_FILE_STREAM_INFORMATION		(SMB_INFO_PASSTHROUGH + 22)
+#define	SMB_FILE_COMPRESSION_INFORMATION	(SMB_INFO_PASSTHROUGH + 28)
+#define	SMB_FILE_ATTR_TAG_INFORMATION		(SMB_INFO_PASSTHROUGH + 35)
 
 /*
  * The following bits may be set in the SecurityMode field of the
--- a/usr/src/uts/common/smbsrv/ndl/svcctl.ndl	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/smbsrv/ndl/svcctl.ndl	Tue Jun 30 08:31:17 2009 -0700
@@ -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.
  */
 
@@ -61,7 +61,7 @@
 #define	SVCCTL_OPNUM_ChangeServiceConfigA	0x17
 #define	SVCCTL_OPNUM_CreateServiceA		0x18
 #define	SVCCTL_OPNUM_EnumDependentServicesA	0x19
-#define	SVCCTL_OPNUM_EnumServiceStatusA		0x1a
+#define	SVCCTL_OPNUM_EnumServicesStatusA	0x1a
 #define	SVCCTL_OPNUM_OpenSCManagerA		0x1b
 #define	SVCCTL_OPNUM_OpenServiceA		0x1c
 #define	SVCCTL_OPNUM_QueryServiceConfigA	0x1d
@@ -78,8 +78,8 @@
 /* Windows 2000 */
 #define	SVCCTL_OPNUM_QueryServiceConfig2W	0x27
 #define	SVCCTL_OPNUM_QueryServiceStatusEx	0x28
-#define	SVCCTL_OPNUM_EnumServiceStatusExA	0x29
-#define	SVCCTL_OPNUM_EnumServiceStatusExW	0x2a
+#define	SVCCTL_OPNUM_EnumServicesStatusExA	0x29
+#define	SVCCTL_OPNUM_EnumServicesStatusExW	0x2a
 
 /* Windows XP and Windows Server 2003 */
 #define	SVCCTL_OPNUM_SendTSMessage		0x2b
@@ -100,6 +100,16 @@
 CONTEXT_HANDLE(svcctl_handle) svcctl_handle_t;
 
 /*
+ * String definition for the ASCII interface.
+ */
+struct svcctl_value {
+	DWORD	vc_first_is;	/* 0 */
+	DWORD	vc_length_is;
+    SIZE_IS(vc_length_is)
+	BYTE	value[ANY_SIZE_ARRAY];
+};
+
+/*
  * The svc_status (SERVICE_STATUS) structure contains information about a
  * service. The ControlService, EnumDependentServices, EnumServicesStatus,
  * and QueryServiceStatus functions use this structure to return information
@@ -238,6 +248,60 @@
 	OUT		DWORD status;
 };
 
+/*
+ ***********************************************************************
+ * ControlService
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_ControlService)
+struct svcctl_ControlService {
+	IN		svcctl_handle_t service_handle;
+	IN		DWORD control;
+	OUT		svc_status_t service_status;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * DeleteService
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_DeleteService)
+struct svcctl_DeleteService {
+	IN		svcctl_handle_t service_handle;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * QueryServiceSecurity
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_QueryServiceSecurity)
+struct svcctl_QueryServiceSecurity {
+	IN		svcctl_handle_t service_handle;
+	IN		DWORD security_info;
+	IN		DWORD buf_size;
+    SIZE_IS(buf_size)
+	OUT REFERENCE	LPBYTE buffer;
+	OUT		DWORD bytes_needed;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * SetServiceSecurity
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_SetServiceSecurity)
+struct svcctl_SetServiceSecurity {
+	IN		svcctl_handle_t service_handle;
+	IN		DWORD security_info;
+    SIZE_IS(buf_size)
+	IN REFERENCE	LPBYTE buffer;
+	IN		DWORD buf_size;
+	OUT		DWORD status;
+};
 
 /*
  ***********************************************************************
@@ -283,6 +347,23 @@
 
 /*
  ***********************************************************************
+ * EnumDependentServices
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_EnumDependentServices)
+struct svcctl_EnumDependentServices {
+	IN		svcctl_handle_t service_handle;
+	IN		DWORD svc_state;
+	IN		DWORD buf_size;
+    SIZE_IS(buf_size)
+	OUT REFERENCE	LPBYTE services;
+	OUT		DWORD bytes_needed;
+	OUT		DWORD svc_num;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
  * EnumServicesStatus
  ***********************************************************************
  */
@@ -316,6 +397,29 @@
 
 /*
  ***********************************************************************
+ * StartService
+ *
+ * argc:	The number of strings in argv.  If argv is NULL,
+ *		argc may be 0.
+ * argv:	A pointer to a buffer containing an array of
+ *		null-terminated Unicode strings.
+ *
+ * For service management support, this should probably be:
+ *	IN		DWORD argc;
+ *    SIZE_IS(buf_size)
+ *	IN REFERENCE	LPBYTE argv;
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_StartService)
+struct svcctl_StartService {
+	IN		svcctl_handle_t service_handle;
+	IN		DWORD argc;
+	IN		DWORD argv;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
  * GetServiceDisplayNameW       
  ***********************************************************************
  */
@@ -344,6 +448,53 @@
 
 /*
  ***********************************************************************
+ * OpenSCManagerA
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_OpenSCManagerA)
+struct svcctl_OpenSCManagerA {
+	IN		struct svcctl_value *machine_name;
+	IN		struct svcctl_value *database_name;
+	IN		DWORD desired_access;
+	OUT		svcctl_handle_t handle;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * OpenServiceA
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_OpenServiceA)
+struct svcctl_OpenServiceA {
+	IN		svcctl_handle_t manager_handle;
+	IN REFERENCE	struct svcctl_value *service_name;
+	IN		DWORD desired_access;
+	OUT		svcctl_handle_t service_handle;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * EnumServicesStatusA
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_EnumServicesStatusA)
+struct svcctl_EnumServicesStatusA {
+	IN		svcctl_handle_t manager_handle;
+	IN		DWORD svc_type;
+	IN		DWORD svc_state;
+	IN		DWORD buf_size;
+    SIZE_IS(buf_size)
+	OUT REFERENCE	LPBYTE services;
+	OUT		DWORD bytes_needed;
+	OUT		DWORD svc_num;
+	INOUT		DWORD *resume_handle;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
  * QueryServiceConfig2W  
  ***********************************************************************
  */
@@ -360,6 +511,35 @@
 
 /*
  ***********************************************************************
+ * QueryServiceStatusEx  
+ ***********************************************************************
+ */
+struct svc_status_ex {
+	DWORD service_type;
+	DWORD cur_state;
+	DWORD ctrl_accepted;
+	DWORD w32_exitcode;
+	DWORD svc_specified_exitcode;
+	DWORD check_point;
+	DWORD wait_hint;
+	DWORD process_id;
+	DWORD service_flags;
+}; 
+typedef struct svc_status_ex svc_status_ex_t;
+
+OPERATION(SVCCTL_OPNUM_QueryServiceStatusEx)
+struct svcctl_QueryServiceStatusEx {
+	IN		svcctl_handle_t service_handle;
+	IN		DWORD info_level;
+	IN		DWORD buf_size;
+    SIZE_IS(buf_size)
+	OUT REFERENCE	LPBYTE buffer;
+	OUT		DWORD bytes_needed;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
  * The SVCCTL interface definition.
  ***********************************************************************
  */
@@ -367,22 +547,42 @@
 union svcctl_interface {
 	CASE(SVCCTL_OPNUM_Close)
 		struct svcctl_Close			SvcClose;
+	CASE(SVCCTL_OPNUM_ControlService)
+		struct svcctl_ControlService		SvcControlService;
+	CASE(SVCCTL_OPNUM_DeleteService)
+		struct svcctl_DeleteService		SvcDeleteService;
+	CASE(SVCCTL_OPNUM_QueryServiceSecurity)
+		struct svcctl_QueryServiceSecurity	SvcQueryServiceSecurity;
+	CASE(SVCCTL_OPNUM_SetServiceSecurity)
+		struct svcctl_SetServiceSecurity	SvcSetServiceSecurity;
 	CASE(SVCCTL_OPNUM_OpenManager)
 		struct svcctl_OpenManager		SvcOpenManager;
 	CASE(SVCCTL_OPNUM_OpenService)
 		struct svcctl_OpenService		SvcOpenService;
 	CASE(SVCCTL_OPNUM_QueryServiceStatus)
 		struct svcctl_QueryServiceStatus	SvcQueryServiceStatus;
+	CASE(SVCCTL_OPNUM_EnumDependentServices)
+		struct svcctl_EnumDependentServices Svc_EnumDependentServices;
 	CASE(SVCCTL_OPNUM_EnumServicesStatus)
 		struct svcctl_EnumServicesStatus	SvcEnumServicesStatus;
 	CASE(SVCCTL_OPNUM_QueryServiceConfig)
 		struct svcctl_QueryServiceConfig	SvcQueryServiceConfig;
+	CASE(SVCCTL_OPNUM_StartService)
+		struct svcctl_StartService		SvcStartService;
 	CASE(SVCCTL_OPNUM_GetServiceDisplayNameW)
 		struct svcctl_GetServiceDisplayNameW SvcGetServiceDisplayNameW;
 	CASE(SVCCTL_OPNUM_GetServiceKeyNameW)
 		struct svcctl_GetServiceKeyNameW	SvcGetServiceKeyNameW;
+	CASE(SVCCTL_OPNUM_OpenSCManagerA)
+		struct svcctl_OpenSCManagerA		SvcOpenSCManagerA;
+	CASE(SVCCTL_OPNUM_OpenServiceA)
+		struct svcctl_OpenServiceA		SvcOpenServiceA;
+	CASE(SVCCTL_OPNUM_EnumServicesStatusA)
+		struct svcctl_EnumServicesStatusA	SvcEnumServicesStatusA;
 	CASE(SVCCTL_OPNUM_QueryServiceConfig2W)
 		struct svcctl_QueryServiceConfig2W	SvcQueryServiceConfig2W;
+	CASE(SVCCTL_OPNUM_QueryServiceStatusEx)
+		struct svcctl_QueryServiceStatusEx	SvcQueryServiceStatusEx;
 };
 
 typedef union svcctl_interface	svcctl_interface_t;
--- a/usr/src/uts/common/smbsrv/ntifs.h	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/smbsrv/ntifs.h	Tue Jun 30 08:31:17 2009 -0700
@@ -198,41 +198,60 @@
  * Define the file information class values used by the NT DDK and HAL.
  */
 typedef enum _FILE_INFORMATION_CLASS {
-	FileDirectoryInformation	= 1,
-	FileFullDirectoryInformation,	/* 2 */
-	FileBothDirectoryInformation,	/* 3 */
-	FileBasicInformation,		/* 4 */
-	FileStandardInformation,	/* 5 */
-	FileInternalInformation,	/* 6 */
-	FileEaInformation,		/* 7 */
-	FileAccessInformation,		/* 8 */
-	FileNameInformation,		/* 9 */
-	FileRenameInformation,		/* 10 */
-	FileLinkInformation,		/* 11 */
-	FileNamesInformation,		/* 12 */
-	FileDispositionInformation,	/* 13 */
-	FilePositionInformation,	/* 14 */
-	FileFullEaInformation,		/* 15 */
-	FileModeInformation,		/* 16 */
-	FileAlignmentInformation,	/* 17 */
-	FileAllInformation,		/* 18 */
-	FileAllocationInformation,	/* 19 */
-	FileEndOfFileInformation,	/* 20 */
-	FileAlternateNameInformation,	/* 21 */
-	FileStreamInformation,		/* 22 */
-	FilePipeInformation,		/* 23 */
-	FilePipeLocalInformation,	/* 24 */
-	FilePipeRemoteInformation,	/* 25 */
-	FileMailslotQueryInformation,	/* 26 */
-	FileMailslotSetInformation,	/* 27 */
-	FileCompressionInformation,	/* 28 */
-	FileObjectIdInformation,	/* 29 */
-	FileCompletionInformation,	/* 30 */
-	FileMoveClusterInformation,	/* 31 */
-	FileInformationReserved32,	/* 32 */
-	FileInformationReserved33,	/* 33 */
-	FileNetworkOpenInformation,	/* 34 */
-	FileAttributeTagInformation,	/* 35 */
+	FileDirectoryInformation		= 1,
+	FileFullDirectoryInformation,		/* 2 */
+	FileBothDirectoryInformation,		/* 3 */
+	FileBasicInformation,			/* 4 */
+	FileStandardInformation,		/* 5 */
+	FileInternalInformation,		/* 6 */
+	FileEaInformation,			/* 7 */
+	FileAccessInformation,			/* 8 */
+	FileNameInformation,			/* 9 */
+	FileRenameInformation,			/* 10 */
+	FileLinkInformation,			/* 11 */
+	FileNamesInformation,			/* 12 */
+	FileDispositionInformation,		/* 13 */
+	FilePositionInformation,		/* 14 */
+	FileFullEaInformation,			/* 15 */
+	FileModeInformation,			/* 16 */
+	FileAlignmentInformation,		/* 17 */
+	FileAllInformation,			/* 18 */
+	FileAllocationInformation,		/* 19 */
+	FileEndOfFileInformation,		/* 20 */
+	FileAlternateNameInformation,		/* 21 */
+	FileStreamInformation,			/* 22 */
+	FilePipeInformation,			/* 23 */
+	FilePipeLocalInformation,		/* 24 */
+	FilePipeRemoteInformation,		/* 25 */
+	FileMailslotQueryInformation,		/* 26 */
+	FileMailslotSetInformation,		/* 27 */
+	FileCompressionInformation,		/* 28 */
+	FileObjectIdInformation,		/* 29 */
+	FileCompletionInformation,		/* 30 */
+	FileMoveClusterInformation,		/* 31 */
+	FileQuotaInformation,			/* 32 */
+	FileReparsePointInformation,		/* 33 */
+	FileNetworkOpenInformation,		/* 34 */
+	FileAttributeTagInformation,		/* 35 */
+	FileTrackingInformation,		/* 36 */
+	FileIdBothDirectoryInformation,		/* 37 */
+	FileIdFullDirectoryInformation,		/* 38 */
+	FileValidDataLengthInformation,		/* 39 */
+	FileShortNameInformation,		/* 40 */
+	FileInformationReserved41,		/* 41 */
+	FileInformationReserved42,		/* 42 */
+	FileInformationReserved43,		/* 43 */
+	FileSfioReserveInformation,		/* 44 */
+	FileSfioVolumeInformation,		/* 45 */
+	FileHardLinkInformation,		/* 46 */
+	FileInformationReserved47,		/* 47 */
+	FileNormalizedNameInformation,		/* 48 */
+	FileInformationReserved49,		/* 49 */
+	FileIdGlobalTxDirectoryInformation,	/* 50 */
+	FileInformationReserved51,		/* 51 */
+	FileInformationReserved52,		/* 52 */
+	FileInformationReserved53,		/* 53 */
+	FileStandardLinkInformation,		/* 54 */
 	FileMaximumInformation
 } FILE_INFORMATION_CLASS;
 
--- a/usr/src/uts/common/smbsrv/smb_fsops.h	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_fsops.h	Tue Jun 30 08:31:17 2009 -0700
@@ -44,67 +44,55 @@
 int smb_fsop_amask_to_omode(uint32_t);
 
 int smb_fsop_open(smb_node_t *, int, cred_t *);
-
 void smb_fsop_close(smb_node_t *, int, cred_t *);
 
 int smb_fsop_oplock_install(smb_node_t *, int);
-
 void smb_fsop_oplock_uninstall(smb_node_t *);
 
 int smb_fsop_create(smb_request_t *, cred_t *, smb_node_t *,
-    char *name, smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr);
+    char *, smb_attr_t *, smb_node_t **);
 
-int smb_fsop_mkdir(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
-    char *name, smb_attr_t *attr, smb_node_t **ret_snode, smb_attr_t *ret_attr);
-
-int smb_fsop_remove(struct smb_request *sr, cred_t *cr, smb_node_t *dir_snode,
-    char *name, uint32_t flags);
+int smb_fsop_mkdir(smb_request_t *, cred_t *, smb_node_t *,
+    char *, smb_attr_t *, smb_node_t **);
 
-int smb_fsop_rmdir(struct smb_request *sr, cred_t *cr, smb_node_t *dir_snode,
-    char *name, uint32_t flags);
+int smb_fsop_remove(smb_request_t *sr, cred_t *cr, smb_node_t *,
+    char *, uint32_t);
 
-int smb_fsop_getattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
-    smb_attr_t *attr);
+int smb_fsop_rmdir(smb_request_t *, cred_t *, smb_node_t *, char *, uint32_t);
 
-int smb_maybe_mangled_name(char *name);
+int smb_fsop_getattr(smb_request_t *, cred_t *, smb_node_t *, smb_attr_t *);
+
+int smb_maybe_mangled_name(char *);
 
 int smb_fsop_link(smb_request_t *, cred_t *, smb_node_t *, smb_node_t *,
     char *);
 
-int smb_fsop_rename(struct smb_request *sr, cred_t *cr,
-    smb_node_t *from_snode, char *from_name, smb_node_t *to_snode,
-    char *to_name);
+int smb_fsop_rename(smb_request_t *, cred_t *,
+    smb_node_t *, char *, smb_node_t *,
+    char *);
 
-int smb_fsop_setattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
-    smb_attr_t *set_attr, smb_attr_t *ret_attr);
+int smb_fsop_setattr(smb_request_t *, cred_t *, smb_node_t *, smb_attr_t *);
 
-int smb_fsop_read(struct smb_request *sr, cred_t *cr,
-    smb_node_t *snode, uio_t *uio, smb_attr_t *ret_attr);
+int smb_fsop_read(smb_request_t *, cred_t *, smb_node_t *, uio_t *);
 
 int smb_fsop_write(smb_request_t *, cred_t *, smb_node_t *, uio_t *,
-    uint32_t *, smb_attr_t *, int);
+    uint32_t *, int);
 
-int smb_fsop_statfs(cred_t *cr, struct smb_node *snode,
-    struct statvfs64 *statp);
+int smb_fsop_statfs(cred_t *, smb_node_t *, struct statvfs64 *);
 
-int smb_fsop_remove_streams(struct smb_request *sr, cred_t *cr,
-    smb_node_t *fnode);
+int smb_fsop_remove_streams(smb_request_t *, cred_t *, smb_node_t *);
 
-int smb_fsop_access(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
-    uint32_t faccess);
+int smb_fsop_access(smb_request_t *, cred_t *, smb_node_t *, uint32_t);
 
-void smb_fsop_eaccess(smb_request_t *sr, cred_t *cr, smb_node_t *snode,
-    uint32_t *faccess);
+void smb_fsop_eaccess(smb_request_t *, cred_t *, smb_node_t *, uint32_t *);
+
+int smb_fsop_lookup_name(smb_request_t *, cred_t *, int,
+    smb_node_t *, smb_node_t *, char *, smb_node_t **);
 
-int smb_fsop_lookup_name(struct smb_request *sr, cred_t *cr, int flags,
-    smb_node_t *root_node, smb_node_t *dir_snode, char *name,
-    smb_node_t **ret_snode, smb_attr_t *ret_attr);
+int smb_fsop_lookup(smb_request_t *, cred_t *, int,
+    smb_node_t *, smb_node_t *, char *, smb_node_t **);
 
-int smb_fsop_lookup(struct smb_request *sr, cred_t *cr, int flags,
-    smb_node_t *root_node, smb_node_t *dir_snode, char *name,
-    smb_node_t **ret_snode, smb_attr_t *ret_attr);
-
-int smb_fsop_commit(smb_request_t *sr, cred_t *cr, struct smb_node *snode);
+int smb_fsop_commit(smb_request_t *, cred_t *, smb_node_t *);
 
 int smb_fsop_aclread(smb_request_t *, cred_t *, smb_node_t *, smb_fssd_t *);
 int smb_fsop_aclwrite(smb_request_t *, cred_t *, smb_node_t *, smb_fssd_t *);
@@ -114,8 +102,7 @@
     int);
 
 uint32_t smb_fsop_shrlock(cred_t *, smb_node_t *, uint32_t, uint32_t, uint32_t);
-void smb_fsop_unshrlock(cred_t *cr, smb_node_t *node, uint32_t uniq_fid);
-
+void smb_fsop_unshrlock(cred_t *, smb_node_t *, uint32_t);
 int smb_fsop_frlock(smb_node_t *, smb_lock_t *, boolean_t, cred_t *);
 
 /*
--- a/usr/src/uts/common/smbsrv/smb_kproto.h	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h	Tue Jun 30 08:31:17 2009 -0700
@@ -148,28 +148,20 @@
 int smb_notify_init(void);
 void smb_notify_fini(void);
 
-smb_sdrc_t smb_nt_transact_notify_change(struct smb_request *, struct smb_xa *);
-smb_sdrc_t smb_nt_transact_query_security_info(struct smb_request *,
-    struct smb_xa *);
-smb_sdrc_t smb_nt_transact_set_security_info(struct smb_request *,
-    struct smb_xa *);
-smb_sdrc_t smb_nt_transact_ioctl(struct smb_request *, struct smb_xa *);
+smb_sdrc_t smb_nt_transact_notify_change(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_nt_transact_query_security_info(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_nt_transact_set_security_info(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_nt_transact_ioctl(smb_request_t *, smb_xa_t *);
 
 smb_sdrc_t smb_com_trans2_open2(smb_request_t *, smb_xa_t *);
-smb_sdrc_t smb_com_trans2_create_directory(struct smb_request *,
-    struct smb_xa *);
-smb_sdrc_t smb_com_trans2_find_first2(struct smb_request *, struct smb_xa *);
-smb_sdrc_t smb_com_trans2_find_next2(struct smb_request *, struct smb_xa *);
-smb_sdrc_t smb_com_trans2_query_fs_information(struct smb_request *,
-    struct smb_xa *);
-smb_sdrc_t smb_com_trans2_query_path_information(struct smb_request *,
-    struct smb_xa *);
-smb_sdrc_t smb_com_trans2_query_file_information(struct smb_request *,
-    struct smb_xa *);
-smb_sdrc_t smb_com_trans2_set_path_information(struct smb_request *,
-    struct smb_xa *);
-smb_sdrc_t smb_com_trans2_set_file_information(struct smb_request *,
-    struct smb_xa *);
+smb_sdrc_t smb_com_trans2_create_directory(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_com_trans2_find_first2(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_com_trans2_find_next2(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_com_trans2_query_fs_information(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_com_trans2_query_path_information(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_com_trans2_query_file_information(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_com_trans2_set_path_information(smb_request_t *, smb_xa_t *);
+smb_sdrc_t smb_com_trans2_set_file_information(smb_request_t *, smb_xa_t *);
 
 /*
  * Logging functions
@@ -177,11 +169,10 @@
 void smb_log_flush(void);
 void smb_correct_keep_alive_values(uint32_t new_keep_alive);
 void smb_close_all_connections(void);
-int smb_set_file_size(smb_request_t *, smb_node_t *);
 
 int smb_net_id(uint32_t);
 
-void smb_process_file_notify_change_queue(struct smb_ofile *of);
+void smb_process_file_notify_change_queue(smb_ofile_t *of);
 
 void smb_oplock_acquire(smb_node_t *, smb_ofile_t *, open_param_t	*);
 boolean_t smb_oplock_break(smb_node_t *, smb_session_t *, boolean_t);
@@ -207,7 +198,7 @@
 	((op)->create_disposition != FILE_SUPERSEDE) &&		\
 	((op)->create_disposition != FILE_OVERWRITE))		\
 
-uint32_t smb_unlock_range(struct smb_request *, struct smb_node *,
+uint32_t smb_unlock_range(smb_request_t *, smb_node_t *,
     uint64_t, uint64_t);
 uint32_t smb_lock_range(smb_request_t *, uint64_t, uint64_t, uint32_t,
     uint32_t locktype);
@@ -223,18 +214,18 @@
 int smb_needs_mangle(char *, char **);
 boolean_t smb_is_invalid_filename(const char *);
 
-void smbsr_cleanup(struct smb_request *sr);
+void smbsr_cleanup(smb_request_t *sr);
 
-int smbsr_connect_tree(struct smb_request *);
+int smbsr_connect_tree(smb_request_t *);
 
-int smb_common_create_directory(struct smb_request *);
+int smb_common_create_directory(smb_request_t *);
 
 int	smb_convert_wildcards(char *);
-int	smb_ascii_or_unicode_strlen(struct smb_request *, char *);
-int	smb_ascii_or_unicode_strlen_null(struct smb_request *, char *);
-int	smb_ascii_or_unicode_null_len(struct smb_request *);
+int	smb_ascii_or_unicode_strlen(smb_request_t *, char *);
+int	smb_ascii_or_unicode_strlen_null(smb_request_t *, char *);
+int	smb_ascii_or_unicode_null_len(smb_request_t *);
 
-int	smb_search(struct smb_request *);
+int	smb_search(smb_request_t *);
 
 uint32_t smb_common_open(smb_request_t *);
 
@@ -253,20 +244,20 @@
 boolean_t smb_dispatch_request(smb_request_t *);
 void	smbsr_disconnect_file(smb_request_t *);
 void	smbsr_disconnect_dir(smb_request_t *);
-int	smbsr_encode_empty_result(struct smb_request *);
+int	smbsr_encode_empty_result(smb_request_t *);
 void	smbsr_lookup_file(smb_request_t *);
 
-int	smbsr_decode_vwv(struct smb_request *sr, char *fmt, ...);
-int	smbsr_decode_data(struct smb_request *sr, char *fmt, ...);
-int	smbsr_encode_result(struct smb_request *, int, int, char *, ...);
+int	smbsr_decode_vwv(smb_request_t *sr, char *fmt, ...);
+int	smbsr_decode_data(smb_request_t *sr, char *fmt, ...);
+int	smbsr_encode_result(smb_request_t *, int, int, char *, ...);
 smb_xa_t *smbsr_lookup_xa(smb_request_t *sr);
-void	smbsr_send_reply(struct smb_request *);
+void	smbsr_send_reply(smb_request_t *);
 
 void	smbsr_map_errno(int, smb_error_t *);
 void	smbsr_set_error(smb_request_t *, smb_error_t *);
-void	smbsr_errno(struct smb_request *, int);
-void	smbsr_warn(struct smb_request *, DWORD, uint16_t, uint16_t);
-void	smbsr_error(struct smb_request *, DWORD, uint16_t, uint16_t);
+void	smbsr_errno(smb_request_t *, int);
+void	smbsr_warn(smb_request_t *, DWORD, uint16_t, uint16_t);
+void	smbsr_error(smb_request_t *, DWORD, uint16_t, uint16_t);
 
 int	clock_get_milli_uptime(void);
 int32_t	smb_dos_to_ux_time(int16_t, int16_t);
@@ -279,7 +270,7 @@
 int	smb_mbc_peek(mbuf_chain_t *, int, char *, ...);
 int	smb_mbc_poke(mbuf_chain_t *, int, char *, ...);
 
-void	smbsr_encode_header(struct smb_request *sr, int wct,
+void	smbsr_encode_header(smb_request_t *sr, int wct,
 		    int bcc, char *fmt, ...);
 
 int	smb_xlate_dialect_str_to_cd(char *);
@@ -288,11 +279,11 @@
 
 int	smbd_fs_query(smb_request_t *, smb_fqi_t *, int);
 
-int smb_lock_range_access(struct smb_request *, struct smb_node *,
+int smb_lock_range_access(smb_request_t *, smb_node_t *,
     uint64_t, uint64_t, boolean_t);
 
-void	smb_encode_sid(struct smb_xa *, smb_sid_t *);
-uint32_t smb_decode_sd(struct smb_xa *, smb_sd_t *);
+void smb_encode_sid(smb_xa_t *, smb_sid_t *);
+uint32_t smb_decode_sd(smb_xa_t *, smb_sd_t *);
 
 /*
  * Socket functions
@@ -355,21 +346,18 @@
  */
 int smb_node_init(void);
 void smb_node_fini(void);
-struct smb_node *smb_node_lookup(struct smb_request *sr, struct open_param *op,
-    cred_t *cr, vnode_t *vp, char *od_name, smb_node_t *dir_snode,
-    smb_node_t *unnamed_node, smb_attr_t *attr);
-struct smb_node *smb_stream_node_lookup(struct smb_request *sr, cred_t *cr,
-    smb_node_t *fnode, vnode_t *xattrdirvp, vnode_t *vp, char *stream_name,
-    smb_attr_t *ret_attr);
-void smb_node_ref(smb_node_t *node);
-void smb_node_release(smb_node_t *node);
-int smb_node_assert(smb_node_t *node, const char *file, int line);
-void smb_node_rename(smb_node_t *from_dir_snode, smb_node_t *ret_snode,
-    smb_node_t *to_dir_snode, char *to_name);
+smb_node_t *smb_node_lookup(smb_request_t *, open_param_t *,
+    cred_t *, vnode_t *, char *, smb_node_t *, smb_node_t *);
+smb_node_t *smb_stream_node_lookup(smb_request_t *, cred_t *,
+    smb_node_t *, vnode_t *, vnode_t *, char *);
+
+void smb_node_ref(smb_node_t *);
+void smb_node_release(smb_node_t *);
+void smb_node_rename(smb_node_t *, smb_node_t *, smb_node_t *, char *);
 int smb_node_root_init(vnode_t *, smb_server_t *, smb_node_t **);
-void smb_node_add_lock(smb_node_t *node, smb_lock_t *lock);
-void smb_node_destroy_lock(smb_node_t *node, smb_lock_t *lock);
-void smb_node_destroy_lock_by_ofile(smb_node_t *node, smb_ofile_t *file);
+void smb_node_add_lock(smb_node_t *, smb_lock_t *);
+void smb_node_destroy_lock(smb_node_t *, smb_lock_t *);
+void smb_node_destroy_lock_by_ofile(smb_node_t *, smb_ofile_t *);
 void smb_node_start_crit(smb_node_t *, krw_t);
 void smb_node_end_crit(smb_node_t *);
 int smb_node_in_crit(smb_node_t *);
@@ -381,6 +369,8 @@
 void smb_node_rem_ofile(smb_node_t *, smb_ofile_t *);
 void smb_node_inc_open_ofiles(smb_node_t *);
 void smb_node_dec_open_ofiles(smb_node_t *);
+boolean_t smb_node_is_dir(smb_node_t *);
+boolean_t smb_node_is_link(smb_node_t *);
 
 uint32_t smb_node_open_check(smb_node_t *, cred_t *,
     uint32_t, uint32_t);
@@ -388,27 +378,23 @@
 DWORD smb_node_delete_check(smb_node_t *);
 void smb_node_notify_change(smb_node_t *);
 
-u_offset_t smb_node_get_size(smb_node_t *, smb_attr_t *);
-void smb_node_set_time(struct smb_node *node, timestruc_t *crtime,
-    timestruc_t *mtime, timestruc_t *atime,
-    timestruc_t *ctime, unsigned int what);
-timestruc_t *smb_node_get_crtime(struct smb_node *node);
-timestruc_t *smb_node_get_atime(struct smb_node *node);
-timestruc_t *smb_node_get_ctime(struct smb_node *node);
-timestruc_t *smb_node_get_mtime(struct smb_node *node);
-void smb_node_set_dosattr(struct smb_node *, uint32_t);
-uint32_t smb_node_get_dosattr(struct smb_node *node);
+int smb_node_getattr(smb_request_t *, smb_node_t *, smb_attr_t *);
+int smb_node_setattr(smb_request_t *, smb_node_t *, cred_t *,
+    smb_ofile_t *, smb_attr_t *);
+
 int smb_node_set_delete_on_close(smb_node_t *, cred_t *, uint32_t);
 void smb_node_reset_delete_on_close(smb_node_t *);
 
+boolean_t smb_node_file_is_readonly(smb_node_t *);
+
 /*
  * Pathname functions
  */
 
-int smb_pathname_reduce(struct smb_request *, cred_t *,
+int smb_pathname_reduce(smb_request_t *, cred_t *,
     const char *, smb_node_t *, smb_node_t *, smb_node_t **, char *);
 
-int smb_pathname(struct smb_request *, char *, int, smb_node_t *,
+int smb_pathname(smb_request_t *, char *, int, smb_node_t *,
     smb_node_t *, smb_node_t **, smb_node_t **, cred_t *);
 
 /*
@@ -427,17 +413,14 @@
  */
 char *smb_kstrdup(const char *s, size_t n);
 
-int smb_sync_fsattr(struct smb_request *sr, cred_t *cr,
-    struct smb_node *node);
 
-
-void smb_encode_stream_info(struct smb_request *sr, struct smb_xa *xa,
+void smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa,
     smb_node_t *snode, smb_attr_t *attr);
 
 /* NOTIFY CHANGE */
 void smb_process_session_notify_change_queue(smb_session_t *, smb_tree_t *);
-void smb_process_node_notify_change_queue(struct smb_node *);
-void smb_reply_specific_cancel_request(struct smb_request *);
+void smb_process_node_notify_change_queue(smb_node_t *);
+void smb_reply_specific_cancel_request(smb_request_t *);
 
 void smb_fem_fcn_install(smb_node_t *);
 void smb_fem_fcn_uninstall(smb_node_t *);
@@ -447,29 +430,24 @@
 int smb_fem_init(void);
 void smb_fem_fini(void);
 
-int smb_try_grow(struct smb_request *sr, int64_t new_size);
+int smb_try_grow(smb_request_t *sr, int64_t new_size);
 
 /* functions from smb_memory_manager.c */
 
-void	*smbsr_malloc(smb_malloc_list *, size_t);
-void	*smbsr_realloc(void *, size_t);
-void	smbsr_free_malloc_list(smb_malloc_list *);
+void *smbsr_malloc(smb_malloc_list *, size_t);
+void *smbsr_realloc(void *, size_t);
+void smbsr_free_malloc_list(smb_malloc_list *);
 
 unsigned short smb_worker_getnum();
 
-DWORD smb_trans2_set_information(struct smb_request *sr,
-    smb_trans2_setinfo_t *info,
-    smb_error_t *smberr);
+uint32_t smb_trans2_set_information(smb_request_t *,
+    smb_trans2_setinfo_t *, smb_error_t *);
 
 /* SMB signing routines smb_signing.c */
-void smb_sign_init(struct smb_request *req,
-	smb_session_key_t *session_key, char *resp, int resp_len);
-
-int smb_sign_check_request(struct smb_request *req);
-
-int smb_sign_check_secondary(struct smb_request *req, unsigned int seqnum);
-
-void smb_sign_reply(struct smb_request *req, struct mbuf_chain *reply);
+void smb_sign_init(smb_request_t *, smb_session_key_t *, char *, int);
+int smb_sign_check_request(smb_request_t *);
+int smb_sign_check_secondary(smb_request_t *, unsigned int);
+void smb_sign_reply(smb_request_t *, mbuf_chain_t *);
 
 boolean_t smb_sattr_check(uint16_t, uint16_t);
 
@@ -512,7 +490,7 @@
  */
 smb_ofile_t *smb_ofile_lookup_by_fid(smb_tree_t *, uint16_t);
 smb_ofile_t *smb_ofile_open(smb_tree_t *, smb_node_t *, uint16_t,
-    struct open_param *, uint16_t, uint32_t, smb_error_t *);
+    open_param_t *, uint16_t, uint32_t, smb_error_t *);
 void smb_ofile_close(smb_ofile_t *, uint32_t);
 uint32_t smb_ofile_access(smb_ofile_t *, cred_t *, uint32_t);
 int smb_ofile_seek(smb_ofile_t *, ushort_t, int32_t, uint32_t *);
@@ -520,16 +498,20 @@
 void smb_ofile_close_all(smb_tree_t *);
 void smb_ofile_close_all_by_pid(smb_tree_t *, uint16_t);
 void smb_ofile_set_flags(smb_ofile_t *, uint32_t);
-void smb_ofile_close_timestamp_update(smb_ofile_t *, uint32_t);
 boolean_t smb_ofile_is_open(smb_ofile_t *);
-uint32_t smb_ofile_open_check(smb_ofile_t *, cred_t *,
-    uint32_t, uint32_t);
+uint32_t smb_ofile_open_check(smb_ofile_t *, cred_t *, uint32_t, uint32_t);
 uint32_t smb_ofile_rename_check(smb_ofile_t *);
 uint32_t smb_ofile_delete_check(smb_ofile_t *);
 cred_t *smb_ofile_getcred(smb_ofile_t *);
 void smb_ofile_set_oplock_granted(smb_ofile_t *);
 void smb_ofile_set_delete_on_close(smb_ofile_t *);
 
+void smb_ofile_set_write_time_pending(smb_ofile_t *);
+boolean_t smb_ofile_write_time_pending(smb_ofile_t *);
+void smb_ofile_set_explicit_times(smb_ofile_t *, uint32_t);
+uint32_t smb_ofile_explicit_times(smb_ofile_t *);
+void smb_delayed_write_timer(smb_llist_t *);
+
 #define	SMB_OFILE_GET_SESSION(of)	((of)->f_session)
 #define	SMB_OFILE_GET_TREE(of)		((of)->f_tree)
 #define	SMB_OFILE_GET_FID(of)		((of)->f_fid)
@@ -619,7 +601,7 @@
 void smb_check_status(void);
 int smb_handle_write_raw(smb_session_t *session, smb_request_t *sr);
 
-void smb_reconnection_check(struct smb_session *session);
+void smb_reconnection_check(smb_session_t *);
 
 uint32_t nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time);
 uint64_t unix_to_nt_time(timestruc_t *);
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h	Tue Jun 30 08:31:17 2009 -0700
@@ -459,6 +459,27 @@
 	char		ux_sharename[MAXNAMELEN];
 } smb_unexport_t;
 
+/*
+ * Solaris file systems handle timestamps differently from NTFS.
+ * In order to provide a more similar view of an open file's
+ * timestamps, we cache the timestamps in the node and manipulate
+ * them in a manner more consistent with windows.
+ * t_cached is B_TRUE when timestamps are cached.
+ * Timestamps remain cached while there are open ofiles for the node.
+ * This includes open ofiles for named streams.  t_open_ofiles is a
+ * count of open ofiles on the node, including named streams' ofiles,
+ * n_open_ofiles cannot be used as it doesn't include ofiles opened
+ * for the node's named streams.
+ */
+typedef struct smb_times {
+	uint32_t		t_open_ofiles;
+	boolean_t		t_cached;
+	timestruc_t		t_atime;
+	timestruc_t		t_mtime;
+	timestruc_t		t_ctime;
+	timestruc_t		t_crtime;
+} smb_times_t;
+
 #define	SMB_NODE_MAGIC		0x4E4F4445	/* 'NODE' */
 #define	SMB_NODE_VALID(p)	ASSERT((p)->n_magic == SMB_NODE_MAGIC)
 
@@ -485,9 +506,8 @@
 	struct smb_ofile	*readonly_creator;
 	volatile int		flags;	/* FILE_NOTIFY_CHANGE_* */
 	volatile int		waiting_event; /* # of clients requesting FCN */
-	smb_attr_t		attr;
+	smb_times_t		n_timestamps; /* cached timestamps */
 	unsigned int		what;
-	u_offset_t		n_size;
 	smb_oplock_t		n_oplock;
 	struct smb_node		*dir_snode; /* Directory of node */
 	struct smb_node		*unnamed_stream_node; /* set in stream nodes */
@@ -510,7 +530,6 @@
 #define	NODE_FLAGS_WRITE_THROUGH	0x00100000
 #define	NODE_FLAGS_SYNCATIME		0x00200000
 #define	NODE_FLAGS_LOCKED		0x00400000
-#define	NODE_FLAGS_ATTR_VALID		0x00800000
 #define	NODE_XATTR_DIR			0x01000000
 #define	NODE_FLAGS_CREATED		0x04000000
 #define	NODE_FLAGS_CHANGED		0x08000000
@@ -885,16 +904,6 @@
 	(SMB_TREE_VFS((sr)->tid_tree) == SMB_NODE_VFS(node)) : 1)
 
 /*
- * SMB_NODE_IS_READONLY(node)
- *
- * This macro indicates whether the DOS readonly bit is set in the node's
- * attribute cache.  The cache reflects what is on-disk.
- */
-
-#define	SMB_NODE_IS_READONLY(node) \
-	((node) && (node)->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)
-
-/*
  * SMB_OFILE_IS_READONLY reflects whether an ofile is readonly or not.
  * The macro takes into account
  *      - the tree readonly state
@@ -905,7 +914,7 @@
 
 #define	SMB_OFILE_IS_READONLY(of)                               \
 	(((of)->f_flags & SMB_OFLAGS_READONLY) ||               \
-	SMB_NODE_IS_READONLY((of)->f_node) ||                   \
+	smb_node_file_is_readonly((of)->f_node) ||                   \
 	(((of)->f_node->readonly_creator) &&                    \
 	((of)->f_node->readonly_creator != (of))))
 
@@ -918,7 +927,7 @@
 
 #define	SMB_PATHFILE_IS_READONLY(sr, node)                       \
 	(SMB_TREE_IS_READONLY((sr)) ||                           \
-	SMB_NODE_IS_READONLY((node)) ||                          \
+	smb_node_file_is_readonly((node)) ||                          \
 	((node)->readonly_creator))
 
 #define	PIPE_STATE_AUTH_VERIFY	0x00000001
@@ -960,12 +969,18 @@
  *   DELETE_ON_CLOSE bit of the CreateOptions is set. If any
  *   open file instance has this bit set, the NODE_FLAGS_DELETE_ON_CLOSE
  *   will be set for the file node upon close.
+ *
+ *	SMB_OFLAGS_TIMESTAMPS_PENDING
+ *   This flag gets set when a write operation is performed on the
+ *   ofile. The timestamps will be updated, and the flags cleared,
+ *   when the ofile gets closed or a setattr is performed on the ofile.
  */
 
 #define	SMB_OFLAGS_READONLY		0x0001
 #define	SMB_OFLAGS_EXECONLY		0x0002
 #define	SMB_OFLAGS_SET_DELETE_ON_CLOSE	0x0004
 #define	SMB_OFLAGS_LLF_POS_VALID	0x0008
+#define	SMB_OFLAGS_TIMESTAMPS_PENDING	0x0010
 
 #define	SMB_OFILE_MAGIC 	0x4F464C45	/* 'OFLE' */
 #define	SMB_OFILE_VALID(p)	ASSERT((p)->f_magic == SMB_OFILE_MAGIC)
@@ -1007,6 +1022,8 @@
 	pid_t			f_pid;
 	boolean_t		f_oplock_granted;
 	boolean_t		f_oplock_exit;
+	uint32_t		f_explicit_times;
+
 } smb_ofile_t;
 
 #define	SMB_ODIR_MAGIC 		0x4F444952	/* 'ODIR' */
@@ -1097,6 +1114,7 @@
 
 typedef struct smb_streaminfo {
 	uint64_t	si_size;
+	uint64_t	si_alloc_size;
 	char		si_name[MAXPATHLEN];
 } smb_streaminfo_t;
 
--- a/usr/src/uts/common/smbsrv/smb_vops.h	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_vops.h	Tue Jun 30 08:31:17 2009 -0700
@@ -97,6 +97,8 @@
 			SMB_AT_FSID|SMB_AT_NODEID|SMB_AT_NLINK|SMB_AT_SIZE|\
 			SMB_AT_ATIME|SMB_AT_MTIME|SMB_AT_CTIME|SMB_AT_RDEV|\
 			SMB_AT_BLKSIZE|SMB_AT_NBLOCKS|SMB_AT_SEQ|SMB_AT_SMB)
+#define	SMB_AT_TIMES	(SMB_AT_ATIME | SMB_AT_MTIME |\
+			SMB_AT_CTIME | SMB_AT_CRTIME)
 
 int fhopen(const struct smb_node *, int);
 
--- a/usr/src/uts/common/smbsrv/winsvc.h	Tue Jun 30 04:09:23 2009 -0700
+++ b/usr/src/uts/common/smbsrv/winsvc.h	Tue Jun 30 08:31:17 2009 -0700
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SMBSRV_WINSVC_H
 #define	_SMBSRV_WINSVC_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * NT Service Control interface definition for the Service Control
  * Manager (SCM).
@@ -210,6 +208,11 @@
 #define	SC_ACTION_REBOOT		2
 #define	SC_ACTION_RUN_COMMAND		3
 
+/*
+ * Information level for QueryServiceStatusEx
+ */
+#define	SC_STATUS_PROCESS_INFO		0
+
 #ifdef __cplusplus
 }
 #endif