# HG changeset patch # User joyce mcintosh # Date 1246375877 25200 # Node ID d540bbbe2461cfcd47d3901a265846fcea87b6f0 # Parent 241a51d8720cdc9e0639021176959419a6f837ce 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) diff -r 241a51d8720c -r d540bbbe2461 usr/src/cmd/krb5/kadmin/kclient/kclient.sh --- 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 diff -r 241a51d8720c -r d540bbbe2461 usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c --- 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; diff -r 241a51d8720c -r d540bbbe2461 usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c --- 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]); diff -r 241a51d8720c -r d540bbbe2461 usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h --- 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 *); diff -r 241a51d8720c -r d540bbbe2461 usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c --- 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 #include #include +#include #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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 *)¶m->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(¶m->handle, sizeof (svcctl_handle_t)); + param->status = ERROR_ACCESS_DENIED; + return (NDR_DRC_OK); + } + + id = svcctl_mgr_hdalloc(mxa); + if (id) { + bcopy(id, ¶m->handle, sizeof (svcctl_handle_t)); + param->status = ERROR_SUCCESS; + } else { + bzero(¶m->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 *)¶m->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(¶m->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(¶m->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(¶m->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, ¶m->service_handle, sizeof (svcctl_handle_t)); + param->status = ERROR_SUCCESS; + } else { + bzero(¶m->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 *)¶m->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 *)¶m->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); +} diff -r 241a51d8720c -r d540bbbe2461 usr/src/lib/smbsrv/libsmb/common/libsmb.h --- 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 *); diff -r 241a51d8720c -r d540bbbe2461 usr/src/lib/smbsrv/libsmb/common/smb_kmod.c --- 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)); diff -r 241a51d8720c -r d540bbbe2461 usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c --- 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 | diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_common_open.c --- 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. diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_delete.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_directory.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_fsops.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_lock.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_node.c --- 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); +} diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c --- 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, diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c --- 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, diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c --- 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. */ diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_odir.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_ofile.c --- 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 /* 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_open_andx.c --- 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, diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_query_information.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_query_information2.c --- 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); } diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_read.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_rename.c --- 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; diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_seek.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_server.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_set_information.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_set_information2.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c --- 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 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)); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c --- 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 #include +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); +} diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c --- 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 #include -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; diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_tree.c --- 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); } /* diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_util.c --- 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 diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_vops.c --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_vss.c --- 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) { diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_write.c --- 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, - ¶m->rw_vdb.vdb_uio, &lcount, &node->attr, stability); + ¶m->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)); -} diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/fs/smbsrv/smb_write_raw.c --- 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; diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/smbsrv/cifs.h --- 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 diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/smbsrv/ndl/svcctl.ndl --- 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; diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/smbsrv/ntifs.h --- 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; diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/smbsrv/smb_fsops.h --- 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 *); /* diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/smbsrv/smb_kproto.h --- 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 *); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/smbsrv/smb_ktypes.h --- 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; diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/smbsrv/smb_vops.h --- 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); diff -r 241a51d8720c -r d540bbbe2461 usr/src/uts/common/smbsrv/winsvc.h --- 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