Windows FindACLCache must hold scp write locked
[openafs.git] / src / WINNT / afsd / smb3.c
index fa40cae..e2eae0d 100644 (file)
@@ -1,13 +1,17 @@
+
 /*
  * Copyright 2000, International Business Machines Corporation and others.
  * All Rights Reserved.
- * 
+ *
  * This software has been released under the terms of the IBM Public
  * License.  For details, see the LICENSE file in the top-level source
  * directory or online at http://www.openafs.org/dl/license10.html
  */
 
+#include <afsconfig.h>
 #include <afs/param.h>
+#include <roken.h>
+
 #include <afs/stds.h>
 
 #include <windows.h>
@@ -16,6 +20,7 @@
 #include <ntstatus.h>
 #define SECURITY_WIN32
 #include <security.h>
+#include <sddl.h>
 #include <lmaccess.h>
 #pragma warning(pop)
 #include <stdlib.h>
@@ -29,6 +34,8 @@
 #include <WINNT\afsreg.h>
 
 #include "smb.h"
+#include "msrpc.h"
+#include <strsafe.h>
 
 extern osi_hyper_t hzero;
 
@@ -42,7 +49,7 @@ smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
 /* protected by the smb_globalLock */
 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
 
-const char **smb_ExecutableExtensions = NULL;
+const clientchar_t **smb_ExecutableExtensions = NULL;
 
 /* retrieve a held reference to a user structure corresponding to an incoming
  * request */
@@ -50,11 +57,11 @@ cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
 {
     smb_user_t *uidp;
     cm_user_t *up = NULL;
-        
+
     uidp = smb_FindUID(vcp, inp->uid, 0);
-    if (!uidp) 
+    if (!uidp)
        return NULL;
-        
+
     up = smb_GetUserFromUID(uidp);
 
     smb_ReleaseUID(uidp);
@@ -62,22 +69,22 @@ cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
     return up;
 }
 
-/* 
- * Return boolean specifying if the path name is thought to be an 
+/*
+ * Return boolean specifying if the path name is thought to be an
  * executable file.  For now .exe or .dll.
  */
-afs_uint32 smb_IsExecutableFileName(const char *name)
+afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
 {
     int i, j, len;
-        
+
     if ( smb_ExecutableExtensions == NULL || name == NULL)
         return 0;
 
-    len = (int)strlen(name);
+    len = (int)cm_ClientStrLen(name);
 
     for ( i=0; smb_ExecutableExtensions[i]; i++) {
-        j = len - (int)strlen(smb_ExecutableExtensions[i]);
-        if (_stricmp(smb_ExecutableExtensions[i], &name[j]) == 0)
+        j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
+        if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
             return 1;
     }
 
@@ -103,17 +110,20 @@ unsigned long smb_ExtAttributes(cm_scache_t *scp)
 #endif /* SPECIAL_FOLDERS */
     } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
         attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
-    } else
+    } else if (scp->fid.vnode & 0x1)
+        attrs = SMB_ATTR_DIRECTORY;
+    else
         attrs = 0;
+
     /*
      * We used to mark a file RO if it was in an RO volume, but that
      * turns out to be impolitic in NT.  See defect 10007.
      */
 #ifdef notdef
-    if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
+    if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
         attrs |= SMB_ATTR_READONLY;            /* Read-only */
 #else
-    if ((scp->unixModeBits & 0222) == 0)
+    if ((scp->unixModeBits & 0200) == 0)
         attrs |= SMB_ATTR_READONLY;            /* Read-only */
 #endif
 
@@ -123,30 +133,23 @@ unsigned long smb_ExtAttributes(cm_scache_t *scp)
     return attrs;
 }
 
-int smb_V3IsStarMask(char *maskp)
+int smb_V3IsStarMask(clientchar_t *maskp)
 {
-    char tc;
+    clientchar_t tc;
 
     while (tc = *maskp++)
-        if (tc == '?' || tc == '*' || tc == '<' || tc == '>') 
+        if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
             return 1;
     return 0;
 }
 
-void OutputDebugF(char * format, ...) {
+void OutputDebugF(clientchar_t * format, ...) {
     va_list args;
-    int len;
-    char * buffer;
+    clientchar_t vbuffer[1024];
 
     va_start( args, format );
-    len = _vscprintf( format, args ) // _vscprintf doesn't count
-                               + 3; // terminating '\0' + '\n'
-    buffer = malloc( len * sizeof(char) );
-    vsprintf( buffer, format, args );
-    osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
-    strcat(buffer, "\n");
-    OutputDebugString(buffer);
-    free( buffer );
+    cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
+    osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
 }
 
 void OutputDebugHexDump(unsigned char * buffer, int len) {
@@ -154,16 +157,14 @@ void OutputDebugHexDump(unsigned char * buffer, int len) {
     char buf[256];
     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
 
-    OutputDebugF("Hexdump length [%d]",len);
+    OutputDebugF(_C("Hexdump length [%d]"),len);
 
     for (i=0;i<len;i++) {
         if(!(i%16)) {
             if(i) {
                 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
-                strcat(buf,"\r\n");
-                OutputDebugString(buf);
             }
-            sprintf(buf,"%5x",i);
+            StringCchPrintfA(buf, lengthof(buf), "%5x", i);
             memset(buf+5,' ',80);
             buf[85] = 0;
         }
@@ -178,12 +179,10 @@ void OutputDebugHexDump(unsigned char * buffer, int len) {
         j = j + 56 + ((j>7)?1:0);
 
         buf[j] = (k>32 && k<127)?k:'.';
-    }    
+    }
     if(i) {
         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
-        strcat(buf,"\r\n");
-        OutputDebugString(buf);
-    }   
+    }
 }
 
 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
@@ -200,7 +199,7 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
     *secBlob = NULL;
     *secBlobLength = 0;
 
-    OutputDebugF("Negotiating Extended Security");
+    OutputDebugF(_C("Negotiating Extended Security"));
 
     status = AcquireCredentialsHandle( NULL,
                                        SMB_EXT_SEC_PACKAGE_NAME,
@@ -214,7 +213,7 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
 
     if (status != SEC_E_OK) {
         /* Really bad. We return an empty security blob */
-        OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
+        OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
         goto nes_0;
     }
 
@@ -240,10 +239,10 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
                                     );
 
     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
-        OutputDebugF("Completing token...");
+        OutputDebugF(_C("Completing token..."));
         istatus = CompleteAuthToken(&ctx, &secOut);
         if ( istatus != SEC_E_OK )
-            OutputDebugF("Token completion failed: %x", istatus);
+            OutputDebugF(_C("Token completion failed: %x"), istatus);
     }
 
     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
@@ -254,7 +253,7 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
         }
     } else {
         if ( status != SEC_E_OK )
-            OutputDebugF("AcceptSecurityContext status != CONTINUE  %lX", status);
+            OutputDebugF(_C("AcceptSecurityContext status != CONTINUE  %lX"), status);
     }
 
     /* Discard partial security context */
@@ -269,14 +268,160 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
     return;
 }
 
+afs_uint32
+smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
+{
+    BOOL bSuccess = FALSE;
+    DWORD dwIndex;
+    DWORD dwLength = 0;
+    PTOKEN_GROUPS ptg = NULL;
+
+    // Verify the parameter passed in is not NULL.
+    if (NULL == ppsid)
+        goto Cleanup;
+
+    // Get required buffer size and allocate the TOKEN_GROUPS buffer.
+
+    if (!GetTokenInformation( hToken,         // handle to the access token
+                              TokenGroups,    // get information about the token's groups
+                              (LPVOID) ptg,   // pointer to TOKEN_GROUPS buffer
+                              0,              // size of buffer
+                              &dwLength       // receives required buffer size
+                              ))
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+            goto Cleanup;
+
+        ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
+                                        HEAP_ZERO_MEMORY, dwLength);
+
+        if (ptg == NULL)
+            goto Cleanup;
+    }
+
+    // Get the token group information from the access token.
+
+    if (!GetTokenInformation( hToken,         // handle to the access token
+                              TokenGroups,    // get information about the token's groups
+                              (LPVOID) ptg,   // pointer to TOKEN_GROUPS buffer
+                              dwLength,       // size of buffer
+                              &dwLength       // receives required buffer size
+                              ))
+    {
+        goto Cleanup;
+    }
+
+    // Loop through the groups to find the logon SID.
+    for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
+        if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) ==  SE_GROUP_LOGON_ID)
+        {
+            // Found the logon SID; make a copy of it.
+
+            dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
+            *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
+                                       HEAP_ZERO_MEMORY, dwLength);
+            if (*ppsid == NULL)
+                goto Cleanup;
+            if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
+            {
+                HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
+                goto Cleanup;
+            }
+            bSuccess = TRUE;
+            break;
+        }
+    }
+
+  Cleanup:
+
+    // Free the buffer for the token groups.
+    if (ptg != NULL)
+        HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
+
+    return bSuccess;
+}
+
+afs_uint32
+smb_GetUserSID(HANDLE hToken, PSID *ppsid)
+{
+    BOOL bSuccess = FALSE;
+    DWORD dwLength = 0;
+    PTOKEN_USER ptu = NULL;
+
+    // Verify the parameter passed in is not NULL.
+    if (NULL == ppsid)
+        goto Cleanup;
+
+    // Get required buffer size and allocate the TOKEN_USER buffer.
+
+    if (!GetTokenInformation( hToken,         // handle to the access token
+                              TokenUser,      // get information about the token's user
+                              (LPVOID) ptu,   // pointer to TOKEN_USER buffer
+                              0,              // size of buffer
+                              &dwLength       // receives required buffer size
+                              ))
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+            goto Cleanup;
+
+        ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
+                                        HEAP_ZERO_MEMORY, dwLength);
+
+        if (ptu == NULL)
+            goto Cleanup;
+    }
+
+    // Get the token group information from the access token.
+
+    if (!GetTokenInformation( hToken,         // handle to the access token
+                              TokenUser,      // get information about the token's user
+                              (LPVOID) ptu,   // pointer to TOKEN_USER buffer
+                              dwLength,       // size of buffer
+                              &dwLength       // receives required buffer size
+                              ))
+    {
+        goto Cleanup;
+    }
+
+    // Found the user SID; make a copy of it.
+    dwLength = GetLengthSid(ptu->User.Sid);
+    *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
+    if (*ppsid == NULL)
+        goto Cleanup;
+    if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
+    {
+        HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
+        goto Cleanup;
+    }
+    bSuccess = TRUE;
+
+  Cleanup:
+
+    // Free the buffer for the token groups.
+    if (ptu != NULL)
+        HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
+
+    return bSuccess;
+}
+
+void
+smb_FreeSID (PSID psid)
+{
+    HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
+}
+
+
 struct smb_ext_context {
     CredHandle creds;
     CtxtHandle ctx;
     int partialTokenLen;
     void * partialToken;
-};      
+};
 
-long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
+long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
+                             char * secBlobIn, int secBlobInLength,
+                             char ** secBlobOut, int * secBlobOutLength,
+                             wchar_t **secSidString) {
     SECURITY_STATUS status, istatus;
     CredHandle creds;
     TimeStamp expiry;
@@ -292,10 +437,11 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int
     int assembledBlobLength = 0;
     ULONG flags;
 
-    OutputDebugF("In smb_AuthenticateUserExt");
+    OutputDebugF(_C("In smb_AuthenticateUserExt"));
 
     *secBlobOut = NULL;
     *secBlobOutLength = 0;
+    *secSidString = NULL;
 
     if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
         secCtx = vcp->secCtx;
@@ -306,12 +452,12 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int
     }
 
     if (secBlobIn) {
-        OutputDebugF("Received incoming token:");
+        OutputDebugF(_C("Received incoming token:"));
         OutputDebugHexDump(secBlobIn,secBlobInLength);
     }
-    
+
     if (secCtx) {
-        OutputDebugF("Continuing with existing context.");             
+        OutputDebugF(_C("Continuing with existing context."));
         creds = secCtx->creds;
         ctx = secCtx->ctx;
 
@@ -333,7 +479,7 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int
                                            &expiry);
 
         if (status != SEC_E_OK) {
-            OutputDebugF("Can't acquire Credentials handle [%lX]", status);
+            OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
             code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
             goto aue_0;
         }
@@ -375,14 +521,14 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int
                                     );
 
     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
-        OutputDebugF("Completing token...");
+        OutputDebugF(_C("Completing token..."));
         istatus = CompleteAuthToken(&ctx, &secBufOut);
         if ( istatus != SEC_E_OK )
-            OutputDebugF("Token completion failed: %lX", istatus);
+            OutputDebugF(_C("Token completion failed: %lX"), istatus);
     }
 
     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
-        OutputDebugF("Continue needed");
+        OutputDebugF(_C("Continue needed"));
 
         newSecCtx = malloc(sizeof(*newSecCtx));
 
@@ -399,19 +545,19 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int
         code = CM_ERROR_GSSCONTINUE;
     }
 
-    if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK || 
-          status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) && 
+    if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
+          status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
          secTokOut.pvBuffer) {
-        OutputDebugF("Need to send token back to client");
+        OutputDebugF(_C("Need to send token back to client"));
 
         *secBlobOutLength = secTokOut.cbBuffer;
         *secBlobOut = malloc(secTokOut.cbBuffer);
         memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
 
-        OutputDebugF("Outgoing token:");
+        OutputDebugF(_C("Outgoing token:"));
         OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
     } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
-        OutputDebugF("Incomplete message");
+        OutputDebugF(_C("Incomplete message"));
 
         newSecCtx = malloc(sizeof(*newSecCtx));
 
@@ -431,52 +577,68 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int
 
     if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
         /* woo hoo! */
-        SecPkgContext_Names names;
+        HANDLE hToken = 0;
+        SecPkgContext_NamesW names;
 
-        OutputDebugF("Authentication completed");
-        OutputDebugF("Returned flags : [%lX]", flags);
+        OutputDebugF(_C("Authentication completed"));
+        OutputDebugF(_C("Returned flags : [%lX]"), flags);
 
-        if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
-            OutputDebugF("Received name [%s]", names.sUserName);
-            strcpy(usern, names.sUserName);
-            strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
+        if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
+            OutputDebugF(_C("Received name [%s]"), names.sUserName);
+            cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
+            cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
             FreeContextBuffer(names.sUserName);
         } else {
             /* Force the user to retry if the context is invalid */
-            OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
-            code = CM_ERROR_BADPASSWORD; 
+            OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
+            code = CM_ERROR_BADPASSWORD;
+        }
+
+        /* Obtain the user's SID */
+        if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
+            PSID pSid = 0;
+            OutputDebugF(_C("Received hToken"));
+
+            if (smb_GetUserSID(hToken, &pSid))
+                ConvertSidToStringSidW(pSid, secSidString);
+
+            if (pSid)
+                smb_FreeSID(pSid);
+            CloseHandle(hToken);
+        } else {
+            OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
         }
     } else if (!code) {
         switch ( status ) {
         case SEC_E_INVALID_TOKEN:
-            OutputDebugF("Returning bad password :: INVALID_TOKEN");
+            OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
             break;
         case SEC_E_INVALID_HANDLE:
-            OutputDebugF("Returning bad password :: INVALID_HANDLE");
+            OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
             break;
         case SEC_E_LOGON_DENIED:
-            OutputDebugF("Returning bad password :: LOGON_DENIED");
+            OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
             break;
         case SEC_E_UNKNOWN_CREDENTIALS:
-            OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
+            OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
             break;
         case SEC_E_NO_CREDENTIALS:
-            OutputDebugF("Returning bad password :: NO_CREDENTIALS");
+            OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
             break;
         case SEC_E_CONTEXT_EXPIRED:
-            OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
+            OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
             break;
         case SEC_E_INCOMPLETE_CREDENTIALS:
-            OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
+            OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
             break;
         case SEC_E_WRONG_PRINCIPAL:
-            OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
+            OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
             break;
         case SEC_E_TIME_SKEW:
-            OutputDebugF("Returning bad password :: TIME_SKEW");
+            OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
             break;
         default:
-            OutputDebugF("Returning bad password :: Status == %lX", status);
+            OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
         }
         code = CM_ERROR_BADPASSWORD;
     }
@@ -505,7 +667,7 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int
 #define P_LEN 256
 #define P_RESP_LEN 128
 
-/* LsaLogonUser expects input parameters to be in a contiguous block of memory. 
+/* LsaLogonUser expects input parameters to be in a contiguous block of memory.
    So put stuff in a struct. */
 struct Lm20AuthBlob {
     MSV1_0_LM20_LOGON lmlogon;
@@ -518,7 +680,7 @@ struct Lm20AuthBlob {
     TOKEN_SOURCE tsource;
 };
 
-long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) 
+long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
 {
     NTSTATUS nts, ntsEx;
     struct Lm20AuthBlob lmAuth;
@@ -529,25 +691,25 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDom
     LUID lmSession;
     HANDLE lmToken;
 
-    OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
-    OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
+    OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
+    OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
 
     if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
-        OutputDebugF("ciPwdLength or csPwdLength is too long");
+        OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
         return CM_ERROR_BADPASSWORD;
     }
 
     memset(&lmAuth,0,sizeof(lmAuth));
 
     lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
-       
+
     lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
-    mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
+    cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
     lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
     lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
 
     lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
-    mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
+    cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
     lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
     lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
 
@@ -575,9 +737,14 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDom
     lmAuth.tgroups.Groups[0].Sid = NULL;
     lmAuth.tgroups.Groups[0].Attributes = 0;
 
+#ifdef _WIN64
     lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
+#else
+    lmAuth.tsource.SourceIdentifier.HighPart = 0;
+#endif
     lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
-    strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
+    StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
+                   "OpenAFS"); /* 8 char limit */
 
     nts = LsaLogonUser( smb_lsaHandle,
                         &smb_lsaLogonOrigin,
@@ -598,8 +765,8 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDom
         osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
                   nts, ntsEx);
 
-    OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
-    OutputDebugF("Extended status is 0x%lX", ntsEx);
+    OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
+    OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
 
     if (nts == ERROR_SUCCESS) {
         /* free the token */
@@ -612,17 +779,17 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDom
             return CM_ERROR_BADLOGONTYPE;
         else /* our catchall is a bad password though we could be more specific */
             return CM_ERROR_BADPASSWORD;
-    }       
+    }
 }
 
 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
-long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName) 
+long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
 {
-    char * atsign;
-    const char * domain;
+    clientchar_t * atsign;
+    const clientchar_t * domain;
 
     /* check if we have sane input */
-    if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
+    if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
         return 1;
 
     /* we could get : [accountName][domainName]
@@ -631,7 +798,7 @@ long smb_GetNormalizedUsername(char * usern, const char * accountName, const cha
        [user][]/[user][?]
        [][]/[][?] */
 
-    atsign = strchr(accountName, '@');
+    atsign = cm_ClientStrChr(accountName, '@');
 
     if (atsign) /* [user@domain][] -> [user@domain][domain] */
         domain = atsign + 1;
@@ -642,26 +809,26 @@ long smb_GetNormalizedUsername(char * usern, const char * accountName, const cha
        it will either return an empty string or a '?' */
     if (!domain[0] || domain[0] == '?')
         /* Empty domains and empty usernames are usually sent from tokenless contexts.
-           This way such logins will get an empty username (easy to check).  I don't know 
+           This way such logins will get an empty username (easy to check).  I don't know
            when a non-empty username would be supplied with an anonymous domain, but *shrug* */
-        strcpy(usern,accountName);
+        cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
     else {
         /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
-        strcpy(usern,domain);
-        strcat(usern,"\\");
+        cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
+        cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
         if (atsign)
-            strncat(usern,accountName,atsign - accountName);
+            cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
         else
-            strcat(usern,accountName);
-    }       
+            cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
+    }
 
-    strlwr(usern);
+    cm_ClientStrLwr(usern);
 
     return 0;
 }
 
 /* When using SMB auth, all SMB sessions have to pass through here
- * first to authenticate the user.  
+ * first to authenticate the user.
  *
  * Caveat: If not using SMB auth, the protocol does not require
  * sending a session setup packet, which means that we can't rely on a
@@ -675,24 +842,54 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     unsigned short newUid;
     unsigned long caps = 0;
     smb_username_t *unp;
-    char *s1 = " ";
-    long code = 0; 
-    char usern[SMB_MAX_USERNAME_LENGTH];
+    clientchar_t *s1 = _C(" ");
+    long code = 0;
+    clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
+    int usernIsSID = 0;
     char *secBlobOut = NULL;
     int  secBlobOutLength = 0;
+    wchar_t *secSidString = 0;
+    int  maxBufferSize = 0;
+    int  maxMpxCount = 0;
+    int  vcNumber = 0;
 
     /* Check for bad conns */
     if (vcp->flags & SMB_VCFLAG_REMOTECONN)
         return CM_ERROR_REMOTECONN;
 
+    /* maxBufferSize */
+    maxBufferSize = smb_GetSMBParm(inp, 2);
+    maxMpxCount = smb_GetSMBParm(inp, 3);
+    vcNumber = smb_GetSMBParm(inp, 4);
+
+    osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
+             maxBufferSize, maxMpxCount, vcNumber);
+
+    if (maxMpxCount > smb_maxMpxRequests) {
+        LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
+        osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
+                 maxMpxCount, smb_maxMpxRequests);
+    }
+
+    if (maxBufferSize < SMB_PACKETSIZE) {
+        LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
+        osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
+                 maxBufferSize, SMB_PACKETSIZE);
+    }
+
+    if (vcNumber == 0) {
+        osi_Log0(smb_logp, "Resetting all VCs");
+        smb_MarkAllVCsDead(vcp);
+    }
+
     if (vcp->flags & SMB_VCFLAG_USENT) {
         if (smb_authType == SMB_AUTH_EXTENDED) {
             /* extended authentication */
             char *secBlobIn;
             int secBlobInLength;
 
-            OutputDebugF("NT Session Setup: Extended");
-        
+            OutputDebugF(_C("NT Session Setup: Extended"));
+
             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
                 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
             }
@@ -700,7 +897,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             secBlobInLength = smb_GetSMBParm(inp, 7);
             secBlobIn = smb_GetSMBData(inp, NULL);
 
-            code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
+            code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
 
             if (code == CM_ERROR_GSSCONTINUE) {
                 size_t cb_data = 0;
@@ -714,7 +911,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
                     free(secBlobOut);
                     tp += secBlobOutLength;
                     cb_data += secBlobOutLength;
-                }      
+                }
                 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
                 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
                 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
@@ -726,14 +923,14 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         } else {
             unsigned ciPwdLength, csPwdLength;
             char *ciPwd, *csPwd;
-            char *accountName;
-            char *primaryDomain;
+            clientchar_t *accountName;
+            clientchar_t *primaryDomain;
             int  datalen;
 
             if (smb_authType == SMB_AUTH_NTLM)
-                OutputDebugF("NT Session Setup: NTLM");
+                OutputDebugF(_C("NT Session Setup: NTLM"));
             else
-                OutputDebugF("NT Session Setup: None");
+                OutputDebugF(_C("NT Session Setup: None"));
 
             /* TODO: parse for extended auth as well */
             ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
@@ -741,7 +938,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
             tp = smb_GetSMBData(inp, &datalen);
 
-            OutputDebugF("Session packet data size [%d]",datalen);
+            OutputDebugF(_C("Session packet data size [%d]"),datalen);
 
             ciPwd = tp;
             tp += ciPwdLength;
@@ -751,10 +948,12 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             accountName = smb_ParseString(inp, tp, &tp, 0);
             primaryDomain = smb_ParseString(inp, tp, NULL, 0);
 
-            OutputDebugF("Account Name: %s",accountName);
-            OutputDebugF("Primary Domain: %s", primaryDomain);
-            OutputDebugF("Case Sensitive Password: %s", csPwd && csPwd[0] ? "yes" : "no");
-            OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
+            OutputDebugF(_C("Account Name: %s"),accountName);
+            OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
+            OutputDebugF(_C("Case Sensitive Password: %s"),
+                         csPwd && csPwd[0] ? _C("yes") : _C("no"));
+            OutputDebugF(_C("Case Insensitive Password: %s"),
+                         ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
 
             if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
                 /* shouldn't happen */
@@ -770,26 +969,26 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             if (smb_authType == SMB_AUTH_NTLM) {
                 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
                 if ( code )
-                    OutputDebugF("LM authentication failed [%d]", code);
+                    OutputDebugF(_C("LM authentication failed [%d]"), code);
                 else
-                    OutputDebugF("LM authentication succeeded");
+                    OutputDebugF(_C("LM authentication succeeded"));
             }
         }
     }  else { /* V3 */
         unsigned ciPwdLength;
         char *ciPwd;
-        char *accountName;
-        char *primaryDomain;
+        clientchar_t *accountName;
+        clientchar_t *primaryDomain;
 
         switch ( smb_authType ) {
         case SMB_AUTH_EXTENDED:
-            OutputDebugF("V3 Session Setup: Extended");
+            OutputDebugF(_C("V3 Session Setup: Extended"));
             break;
         case SMB_AUTH_NTLM:
-            OutputDebugF("V3 Session Setup: NTLM");
+            OutputDebugF(_C("V3 Session Setup: NTLM"));
             break;
         default:
-            OutputDebugF("V3 Session Setup: None");
+            OutputDebugF(_C("V3 Session Setup: None"));
         }
         ciPwdLength = smb_GetSMBParm(inp, 7);
         tp = smb_GetSMBData(inp, NULL);
@@ -799,9 +998,9 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         accountName = smb_ParseString(inp, tp, &tp, 0);
         primaryDomain = smb_ParseString(inp, tp, NULL, 0);
 
-        OutputDebugF("Account Name: %s",accountName);
-        OutputDebugF("Primary Domain: %s", primaryDomain);
-        OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
+        OutputDebugF(_C("Account Name: %s"),accountName);
+        OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
+        OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
 
         if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
             /* shouldn't happen */
@@ -815,9 +1014,9 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
             code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
             if ( code )
-                OutputDebugF("LM authentication failed [%d]", code);
+                OutputDebugF(_C("LM authentication failed [%d]"), code);
             else
-                OutputDebugF("LM authentication succeeded");
+                OutputDebugF(_C("LM authentication succeeded"));
         }
     }
 
@@ -829,7 +1028,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         /* for the moment we can only deal with NTSTATUS */
         if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
             vcp->flags |= SMB_VCFLAG_STATUS32;
-        }       
+        }
 
 #ifdef SMB_UNICODE
         if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
@@ -844,10 +1043,21 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
        early to avoid accidently stealing someone else's tokens. */
 
     if (code) {
+        if (secSidString)
+            LocalFree(secSidString);
         return code;
     }
 
-    OutputDebugF("Received username=[%s]", usern);
+    /*
+     * If the SidString for the user could be obtained, use that
+     * for the user id
+     */
+    if (secSidString) {
+        cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
+        usernIsSID = 1;
+    }
+
+    OutputDebugF(_C("Received username=[%s]"), usern);
 
     /* On Windows 2000, this function appears to be called more often than
        it is expected to be called. This resulted in multiple smb_user_t
@@ -873,11 +1083,15 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
        lock_ObtainMutex(&unp->mx);
        if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
-           /* clear the afslogon flag so that the tickets can now 
+           /* clear the afslogon flag so that the tickets can now
             * be freed when the refCount returns to zero.
             */
            unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
+            if (usernIsSID)
+                unp->flags |= SMB_USERNAMEFLAG_SID;
        }
+    if (usernIsSID)
+        unp->flags |= SMB_USERNAMEFLAG_SID;
        lock_ReleaseMutex(&unp->mx);
 
         /* Create a new UID and cm_user_t structure */
@@ -888,7 +1102,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
        lock_ObtainMutex(&vcp->mx);
         if (!vcp->uidCounter)
             vcp->uidCounter++; /* handle unlikely wraparounds */
-        newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
+        newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
         lock_ReleaseMutex(&vcp->mx);
 
         /* Create a new smb_user_t structure and connect them up */
@@ -911,8 +1125,9 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     /* Also to the next chained message */
     ((smb_t *)inp)->uid = newUid;
 
-    osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
-             osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
+    osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
+             osi_LogSaveClientString(smb_logp, usern), newUid,
+             osi_LogSaveClientString(smb_logp, s1));
 
     smb_SetSMBParm(outp, 2, 0);
 
@@ -928,7 +1143,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
                 free(secBlobOut);
                 tp += secBlobOutLength;
                 cb_data +=  secBlobOutLength;
-            }  
+            }
 
             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
@@ -954,6 +1169,8 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         }
     }
 
+    if (secSidString)
+        LocalFree(secSidString);
     return 0;
 }
 
@@ -967,8 +1184,8 @@ long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     if (uidp) {
        smb_username_t * unp;
 
-        osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
-                  osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
+        osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
+                 osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
 
         lock_ObtainMutex(&uidp->mx);
         uidp->flags |= SMB_USERFLAG_DELETE;
@@ -995,7 +1212,7 @@ long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 
        smb_ReleaseUID(uidp);
     }
-    else    
+    else
         osi_Log0(smb_logp, "SMB3 user logoffX");
 
     smb_SetSMBDataLength(outp, 0);
@@ -1011,16 +1228,17 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     smb_tid_t *tidp;
     smb_user_t *uidp = NULL;
     unsigned short newTid;
-    char shareName[AFSPATHMAX];
-    char *sharePath;
+    clientchar_t shareName[AFSPATHMAX];
+    clientchar_t *sharePath;
     int shareFound;
     char *tp;
-    char *pathp;
-    char *passwordp;
-    char *servicep;
+    clientchar_t *slashp;
+    clientchar_t *pathp;
+    clientchar_t *passwordp;
+    clientchar_t *servicep;
     cm_user_t *userp = NULL;
     int ipc = 0;
-        
+
     osi_Log0(smb_logp, "SMB3 receive tree connect");
 
     /* parse input parameters */
@@ -1029,18 +1247,19 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
     servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
 
-    tp = strrchr(pathp, '\\');
-    if (!tp) {
+    slashp = cm_ClientStrRChr(pathp, '\\');
+    if (!slashp) {
         return CM_ERROR_BADSMB;
     }
-    strcpy(shareName, tp+1);
+    cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
 
-    osi_Log3(smb_logp, "Tree connect pathp[%s] shareName[%s] service[%s]",
-             osi_LogSaveString(smb_logp, pathp),
-             osi_LogSaveString(smb_logp, shareName),
-             osi_LogSaveString(smb_logp, servicep));
+    osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
+             osi_LogSaveClientString(smb_logp, pathp),
+             osi_LogSaveClientString(smb_logp, shareName),
+             osi_LogSaveClientString(smb_logp, servicep));
 
-    if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
+    if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
+        cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
 #ifndef NO_IPC
         osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
         ipc = 1;
@@ -1056,12 +1275,12 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     lock_ObtainMutex(&vcp->mx);
     newTid = vcp->tidCounter++;
     lock_ReleaseMutex(&vcp->mx);
-        
+
     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
 
     if (!ipc) {
-       if (!strcmp(shareName, "*."))
-           strcpy(shareName, "all");
+       if (!cm_ClientStrCmp(shareName, _C("*.")))
+           cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
        shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
        if (!shareFound) {
            if (uidp)
@@ -1086,9 +1305,9 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
                     dwAdvertiseDFS = 0;
                 RegCloseKey (parmKey);
             }
-            smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | 
+            smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
                            (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
-                            (policy << 2));
+                           (policy << 2));
         }
     } else {
         smb_SetSMBParm(outp, 2, 0);
@@ -1100,7 +1319,7 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     lock_ObtainMutex(&tidp->mx);
     tidp->userp = userp;
     tidp->pathname = sharePath;
-    if (ipc) 
+    if (ipc)
         tidp->flags |= SMB_TIDFLAG_IPC;
     lock_ReleaseMutex(&tidp->mx);
     smb_ReleaseTID(tidp, FALSE);
@@ -1111,13 +1330,13 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     if (!ipc) {
         size_t cb_data = 0;
 
-        tp = smb_UnparseString(outp, tp, "A:", &cb_data, SMB_STRF_FORCEASCII);
-        tp = smb_UnparseString(outp, tp, "AFS", &cb_data, 0);
+        tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
+        tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
         smb_SetSMBDataLength(outp, cb_data);
     } else {
         size_t cb_data = 0;
 
-        tp = smb_UnparseString(outp, tp, "IPC", &cb_data, SMB_STRF_FORCEASCII);
+        tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
         smb_SetSMBDataLength(outp, cb_data);
     }
 
@@ -1130,7 +1349,7 @@ smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
 {
     smb_tran2Packet_t *tp;
     smb_t *smbp;
-        
+
     smbp = (smb_t *) inp->data;
     for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
         if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
@@ -1140,11 +1359,11 @@ smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
 }
 
 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
-       int totalParms, int totalData)
+                                      int totalParms, int totalData)
 {
     smb_tran2Packet_t *tp;
     smb_t *smbp;
-        
+
     smbp = (smb_t *) inp->data;
     tp = malloc(sizeof(*tp));
     memset(tp, 0, sizeof(*tp));
@@ -1178,14 +1397,14 @@ smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
 }
 
 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
-                                               smb_tran2Packet_t *inp, smb_packet_t *outp,
-                                               int totalParms, int totalData)  
+                                              smb_tran2Packet_t *inp, smb_packet_t *outp,
+                                              int totalParms, int totalData)
 {
     smb_tran2Packet_t *tp;
     unsigned short parmOffset;
     unsigned short dataOffset;
     unsigned short dataAlign;
-        
+
     tp = malloc(sizeof(*tp));
     memset(tp, 0, sizeof(*tp));
     smb_HoldVC(vcp);
@@ -1218,7 +1437,7 @@ smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
     tp->datap = outp->data + dataOffset;
 
     return tp;
-}       
+}
 
 /* free a tran2 packet */
 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
@@ -1232,7 +1451,11 @@ void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
             free(t2p->parmsp);
         if (t2p->datap)
             free(t2p->datap);
-    }       
+    }
+    if (t2p->name) {
+       free(t2p->name);
+       t2p->name = NULL;
+    }
     while (t2p->stringsp) {
         cm_space_t * ns;
 
@@ -1243,8 +1466,8 @@ void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
     free(t2p);
 }
 
-unsigned char *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
-                                     char ** chainpp, int flags)
+clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
+                                    char ** chainpp, int flags)
 {
     size_t cb;
 
@@ -1253,10 +1476,12 @@ unsigned char *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
         flags |= SMB_STRF_FORCEASCII;
 #endif
 
-    cb = p->totalParms - (inp - (unsigned char *)p->parmsp);
-    if (inp < (unsigned char *) p->parmsp ||
-        inp > ((unsigned char *) p->parmsp) + p->totalParms) {
+    cb = p->totalParms - (inp - (char *)p->parmsp);
+    if (inp < (char *) p->parmsp ||
+        inp >= ((char *) p->parmsp) + p->totalParms) {
+#ifdef DEBUG_UNICODE
         DebugBreak();
+#endif
         cb = p->totalParms;
     }
 
@@ -1268,7 +1493,7 @@ unsigned char *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
  * sends an error response.
  */
 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
-       smb_packet_t *tp, long code)
+                        smb_packet_t *tp, long code)
 {
     smb_t *smbp;
     unsigned short errCode;
@@ -1276,7 +1501,7 @@ void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
     unsigned long NTStatus;
 
     if (vcp->flags & SMB_VCFLAG_STATUS32)
-        smb_MapNTError(code, &NTStatus);
+        smb_MapNTError(code, &NTStatus, FALSE);
     else
         smb_MapCoreError(code, vcp, &errCode, &errClass);
 
@@ -1286,7 +1511,7 @@ void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
     /* We can handle long names */
     if (vcp->flags & SMB_VCFLAG_USENT)
         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
-        
+
     /* now copy important fields from the tran 2 packet */
     smbp->com = t2p->com;
     smbp->tid = t2p->tid;
@@ -1306,10 +1531,10 @@ void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
         smbp->errLow = (unsigned char) (errCode & 0xff);
         smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
     }
-        
+
     /* send packet */
     smb_SendPacket(vcp, tp);
-}        
+}
 
 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
 {
@@ -1335,6 +1560,30 @@ void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp
     smbp->uid = t2p->uid;
     smbp->res[0] = t2p->res[0];
 
+    if (t2p->error_code) {
+       if (vcp->flags & SMB_VCFLAG_STATUS32) {
+           unsigned long NTStatus;
+
+           smb_MapNTError(t2p->error_code, &NTStatus, FALSE);
+
+           smbp->rcls = (unsigned char) (NTStatus & 0xff);
+           smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
+           smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
+           smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
+           smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
+       }
+       else {
+           unsigned short errCode;
+           unsigned char errClass;
+
+           smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
+
+           smbp->rcls = errClass;
+           smbp->errLow = (unsigned char) (errCode & 0xff);
+           smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
+       }
+    }
+
     totalLength = 1 + t2p->totalData + t2p->totalParms;
 
     /* now add the core parameters (tran2 info) to the packet */
@@ -1361,10 +1610,84 @@ void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp
 
     totalLength += dataAlign;
     smb_SetSMBDataLength(tp, totalLength);
-        
+
     /* next, send the datagram */
     smb_SendPacket(vcp, tp);
-}   
+}
+
+/* TRANS_SET_NMPIPE_STATE */
+long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+{
+    smb_fid_t *fidp;
+    int fd;
+    int pipeState = 0x0100;    /* default */
+    smb_tran2Packet_t *outp = NULL;
+
+    fd = p->pipeParam;
+    if (p->totalParms > 0)
+       pipeState = p->parmsp[0];
+
+    osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
+
+    fidp = smb_FindFID(vcp, fd, 0);
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
+       return CM_ERROR_BADFD;
+    }
+    lock_ObtainMutex(&fidp->mx);
+    if (pipeState & 0x8000)
+       fidp->flags |= SMB_FID_BLOCKINGPIPE;
+    if (pipeState & 0x0100)
+       fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
+    lock_ReleaseMutex(&fidp->mx);
+
+    outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
+    smb_SendTran2Packet(vcp, outp, op);
+    smb_FreeTran2Packet(outp);
+
+    smb_ReleaseFID(fidp);
+
+    return 0;
+}
+
+long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+{
+    smb_fid_t *fidp;
+    int fd;
+    int is_rpc = 0;
+
+    long code = 0;
+
+    fd = p->pipeParam;
+
+    osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
+            fd, p->totalData, p->maxReturnData);
+
+    fidp = smb_FindFID(vcp, fd, 0);
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
+       return CM_ERROR_BADFD;
+    }
+    lock_ObtainMutex(&fidp->mx);
+    if (fidp->flags & SMB_FID_RPC) {
+       is_rpc = 1;
+    }
+    lock_ReleaseMutex(&fidp->mx);
+
+    if (is_rpc) {
+       code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
+       smb_ReleaseFID(fidp);
+    } else {
+       /* We only deal with RPC pipes */
+        osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
+                 vcp, fd);
+       code = CM_ERROR_BADFD;
+    }
+
+    return code;
+}
 
 
 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
@@ -1385,7 +1708,7 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* We sometimes see 0 word count.  What to do? */
     if (*inp->wctp == 0) {
-        osi_Log0(smb_logp, "Transaction2 word count = 0"); 
+        osi_Log0(smb_logp, "Transaction2 word count = 0");
        LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
 
         smb_SetSMBDataLength(outp, 0);
@@ -1395,9 +1718,9 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     totalParms = smb_GetSMBParm(inp, 0);
     totalData = smb_GetSMBParm(inp, 1);
-        
+
     firstPacket = (inp->inCom == 0x25);
-        
+
     /* find the packet we're reassembling */
     lock_ObtainWrite(&smb_globalLock);
     asp = smb_FindTran2Packet(vcp, inp);
@@ -1405,7 +1728,7 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
     }
     lock_ReleaseWrite(&smb_globalLock);
-        
+
     /* now merge in this latest packet; start by looking up offsets */
     if (firstPacket) {
         parmDisp = dataDisp = 0;
@@ -1413,11 +1736,26 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         dataOffset = smb_GetSMBParm(inp, 12);
         parmCount = smb_GetSMBParm(inp, 9);
         dataCount = smb_GetSMBParm(inp, 11);
+       asp->setupCount = smb_GetSMBParmByte(inp, 13);
         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
         asp->maxReturnData = smb_GetSMBParm(inp, 3);
 
         osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
                   totalData, dataCount, asp->maxReturnData);
+
+       if (asp->setupCount == 2) {
+           clientchar_t * pname;
+
+           asp->pipeCommand = smb_GetSMBParm(inp, 14);
+           asp->pipeParam = smb_GetSMBParm(inp, 15);
+           pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
+           if (pname) {
+               asp->name = cm_ClientStrDup(pname);
+           }
+
+           osi_Log2(smb_logp, "  Named Pipe command id [%d] with name [%S]",
+                    asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
+       }
     }
     else {
         parmDisp = smb_GetSMBParm(inp, 4);
@@ -1429,7 +1767,7 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
                  parmCount, dataCount);
-    }   
+    }
 
     /* now copy the parms and data */
     if ( asp->totalParms > 0 && parmCount != 0 )
@@ -1445,27 +1783,91 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     asp->curParms += parmCount;
 
     /* finally, if we're done, remove the packet from the queue and dispatch it */
-    if (asp->totalParms > 0 &&
-        asp->curParms > 0 &&
+    if (((asp->totalParms > 0 && asp->curParms > 0)
+        || asp->setupCount == 2) &&
         asp->totalData <= asp->curData &&
         asp->totalParms <= asp->curParms) {
+
         /* we've received it all */
         lock_ObtainWrite(&smb_globalLock);
         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
         lock_ReleaseWrite(&smb_globalLock);
 
-        /* now dispatch it */
-        rapOp = asp->parmsp[0];
+       switch(asp->setupCount) {
+       case 0:
+           {                   /* RAP */
+               rapOp = asp->parmsp[0];
 
-        if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
-            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
-            code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
-            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return  code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
-        }
-        else {
-            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
-            code = CM_ERROR_BADOP;
-        }
+               if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
+                    smb_rapDispatchTable[rapOp].procp) {
+
+                   osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
+                            myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
+
+                   code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
+
+                   osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return  code 0x%x vcp[%x] lana[%d] lsn[%d]",
+                            code,vcp,vcp->lana,vcp->lsn);
+               }
+               else {
+                   osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
+                            rapOp, vcp, vcp->lana, vcp->lsn);
+
+                   code = CM_ERROR_BADOP;
+               }
+           }
+           break;
+
+       case 2:
+           {                   /* Named pipe operation */
+               osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
+                        myCrt_NmpipeDispatch(asp->pipeCommand),
+                        osi_LogSaveClientString(smb_logp, asp->name));
+
+               code = CM_ERROR_BADOP;
+
+               switch (asp->pipeCommand) {
+               case SMB_TRANS_SET_NMPIPE_STATE:
+                   code = smb_nmpipeSetState(vcp, asp, outp);
+                   break;
+
+               case SMB_TRANS_RAW_READ_NMPIPE:
+                   break;
+
+               case SMB_TRANS_QUERY_NMPIPE_STATE:
+                   break;
+
+               case SMB_TRANS_QUERY_NMPIPE_INFO:
+                   break;
+
+               case SMB_TRANS_PEEK_NMPIPE:
+                   break;
+
+               case SMB_TRANS_TRANSACT_NMPIPE:
+                   code = smb_nmpipeTransact(vcp, asp, outp);
+                   break;
+
+               case SMB_TRANS_RAW_WRITE_NMPIPE:
+                   break;
+
+               case SMB_TRANS_READ_NMPIPE:
+                   break;
+
+               case SMB_TRANS_WRITE_NMPIPE:
+                   break;
+
+               case SMB_TRANS_WAIT_NMPIPE:
+                   break;
+
+               case SMB_TRANS_CALL_NMPIPE:
+                   break;
+               }
+           }
+           break;
+
+       default:
+           code = CM_ERROR_BADOP;
+       }
 
         /* if an error is returned, we're supposed to send an error packet,
          * otherwise the dispatched function already did the data sending.
@@ -1530,16 +1932,13 @@ typedef struct smb_rap_share_list {
 
 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
     smb_rap_share_list_t * sp;
-    char * name;
-
-    name = dep->name;
 
-    if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
+    if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
         return 0; /* skip over '.' and '..' */
 
     sp = (smb_rap_share_list_t *) vrockp;
 
-    strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
+    strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
     sp->shares[sp->cShare].shi0_netname[12] = 0;
 
     sp->cShare++;
@@ -1548,7 +1947,7 @@ int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp
         return CM_ERROR_STOPNOW;
     else
         return 0;
-}       
+}
 
 /* RAP NetShareEnumRequest */
 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
@@ -1571,7 +1970,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     smb_rap_share_info_1_t * shares;
     USHORT cshare = 0;
     char * cstrp;
-    char thisShare[AFSPATHMAX];
+    clientchar_t thisShare[AFSPATHMAX];
     int i,j;
     DWORD dw;
     int nonrootShares;
@@ -1579,17 +1978,18 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     cm_req_t req;
     cm_user_t * userp;
     osi_hyper_t thyper;
+    cm_scache_t *rootScp;
 
     tp = p->parmsp + 1; /* skip over function number (always 0) */
 
     {
-        char * cdescp;
+        clientchar_t * cdescp;
 
         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
-        if (strcmp(cdescp, "WrLeh"))
+        if (cm_ClientStrCmp(cdescp,  _C("WrLeh")))
             return CM_ERROR_INVAL;
         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
-        if (strcmp(cdescp, "B13BWz"))
+        if (cm_ClientStrCmp(cdescp,  _C("B13BWz")))
             return CM_ERROR_INVAL;
     }
 
@@ -1641,16 +2041,17 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     rootShares.cShare = 0;
     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     userp = smb_GetTran2User(vcp,p);
 
     thyper.HighPart = 0;
     thyper.LowPart = 0;
 
-    cm_HoldSCache(cm_data.rootSCachep);
-    cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
-    cm_ReleaseSCache(cm_data.rootSCachep);
+    rootScp = cm_RootSCachep(userp, &req);
+    cm_HoldSCache(rootScp);
+    cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
+    cm_ReleaseSCache(rootScp);
 
     cm_ReleaseUser(userp);
 
@@ -1666,7 +2067,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     else {
         nSharesRet = nShares;
     }
-    
+
     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
 
     /* now for the submounts */
@@ -1676,7 +2077,8 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
 
     if (allSubmount) {
-        strcpy( shares[cshare].shi1_netname, "all" );
+        StringCchCopyA(shares[cshare].shi1_netname,
+                       lengthof(shares[cshare].shi1_netname), "all" );
         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
         /* type and pad are zero already */
         cshare++;
@@ -1686,11 +2088,12 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     if (hkSubmount) {
         for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
             len = sizeof(thisShare);
-            rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
+            rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
             if (rv == ERROR_SUCCESS &&
-                strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
-                strncpy(shares[cshare].shi1_netname, thisShare,
-                        sizeof(shares->shi1_netname)-1);
+                cm_ClientStrLen(thisShare) &&
+                (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
+                cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
+                                      lengthof( shares[cshare].shi1_netname ));
                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
                 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
                 cshare++;
@@ -1706,17 +2109,19 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     nonrootShares = cshare;
 
     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
-        /* in case there are collisions with submounts, submounts have higher priority */              
+        /* in case there are collisions with submounts, submounts have
+           higher priority */
         for (j=0; j < nonrootShares; j++)
-            if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
+            if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
                 break;
-               
+
         if (j < nonrootShares) {
             nShares--; /* uncount */
             continue;
         }
 
-        strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
+        StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
+                       rootShares.shares[i].shi0_netname);
         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
         cshare++;
         cstrp+=REMARK_LEN;
@@ -1743,7 +2148,7 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
 {
     smb_tran2Packet_t *outp;
     unsigned short * tp;
-    char * shareName;
+    clientchar_t * shareName;
     BOOL shareFound = FALSE;
     unsigned short infoLevel;
     unsigned short bufsize;
@@ -1759,22 +2164,22 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     cm_user_t   *userp;
     cm_req_t    req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     tp = p->parmsp + 1; /* skip over function number (always 1) */
 
     {
-        char * cdescp;
+        clientchar_t * cdescp;
 
         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
-        if (strcmp(cdescp, "zWrLh"))
+        if (cm_ClientStrCmp(cdescp,  _C("zWrLh")))
 
             return CM_ERROR_INVAL;
 
         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
-        if (strcmp(cdescp, "B13") &&
-            strcmp(cdescp, "B13BWz") &&
-            strcmp(cdescp, "B13BWzWWWzB9B"))
+        if (cm_ClientStrCmp(cdescp,  _C("B13")) &&
+            cm_ClientStrCmp(cdescp,  _C("B13BWz")) &&
+            cm_ClientStrCmp(cdescp,  _C("B13BWzWWWzB9B")))
 
             return CM_ERROR_INVAL;
     }
@@ -1782,7 +2187,7 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
 
     infoLevel = *tp++;
     bufsize = *tp++;
-    
+
     totalParam = 6;
 
     if (infoLevel == 0)
@@ -1794,7 +2199,7 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     else
         return CM_ERROR_INVAL;
 
-    if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
+    if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                           KEY_QUERY_VALUE, &hkParam);
         if (rv == ERROR_SUCCESS) {
@@ -1813,10 +2218,10 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     } else {
         userp = smb_GetTran2User(vcp, p);
         if (!userp) {
-            osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
+            osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
             return CM_ERROR_BADSMB;
-        }   
-        code = cm_NameI(cm_data.rootSCachep, shareName,
+        }
+        code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
                          userp, NULL, &req, &scp);
         if (code == 0) {
@@ -1826,7 +2231,7 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
             rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
                               KEY_QUERY_VALUE, &hkSubmount);
             if (rv == ERROR_SUCCESS) {
-                rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
+                rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
                 if (rv == ERROR_SUCCESS) {
                     shareFound = TRUE;
                 }
@@ -1847,18 +2252,17 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
 
     if (infoLevel == 0) {
         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
-        strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
-        info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
+        cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
+                              lengthof(info->shi0_netname));
     } else if(infoLevel == SMB_INFO_STANDARD) {
         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
-        strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
+        cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
         info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
         /* type and pad are already zero */
     } else { /* infoLevel==2 */
         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
-        strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
-        info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
+        cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
         info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
         info->shi2_permissions = ACCESS_ALL;
         info->shi2_max_uses = (unsigned short) -1;
@@ -1904,15 +2308,16 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     tp = p->parmsp + 1; /* Skip over function number */
 
     {
-        char * cdescp;
+        clientchar_t * cdescp;
 
         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
                                        SMB_STRF_FORCEASCII);
-        if (strcmp(cdescp, "WrLh"))
+        if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
             return CM_ERROR_INVAL;
+
         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
                                        SMB_STRF_FORCEASCII);
-        if (strcmp(cdescp, "zzzBBzz"))
+        if (cm_ClientStrCmp(cdescp,  _C("zzzBBzz")))
             return CM_ERROR_INVAL;
     }
 
@@ -1924,7 +2329,7 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     }
 
     totalParams = 6;
-       
+
     /* infolevel 10 */
     totalData = sizeof(*info) +                /* info */
         MAX_COMPUTERNAME_LENGTH +      /* wki10_computername */
@@ -1942,7 +2347,7 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     cstrp = (char *) (info + 1);
 
     info->wki10_computername = (DWORD) (cstrp - outp->datap);
-    strcpy(cstrp, smb_localNamep);
+    StringCbCopyA(cstrp, totalData, smb_localNamep);
     cstrp += strlen(cstrp) + 1;
 
     info->wki10_username = (DWORD) (cstrp - outp->datap);
@@ -1950,14 +2355,15 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     if (uidp) {
         lock_ObtainMutex(&uidp->mx);
         if(uidp->unp && uidp->unp->name)
-            strcpy(cstrp, uidp->unp->name);
+            cm_ClientStringToUtf8(uidp->unp->name, -1,
+                                  cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
         lock_ReleaseMutex(&uidp->mx);
         smb_ReleaseUID(uidp);
     }
     cstrp += strlen(cstrp) + 1;
 
     info->wki10_langroup = (DWORD) (cstrp - outp->datap);
-    strcpy(cstrp, "WORKGROUP");
+    StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
     cstrp += strlen(cstrp) + 1;
 
     /* TODO: Not sure what values these should take, but these work */
@@ -1965,7 +2371,8 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     info->wki10_ver_minor = 1;
 
     info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
-    strcpy(cstrp, smb_ServerDomainName);
+    cm_ClientStringToUtf8(smb_ServerDomainName, -1,
+                          cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
     cstrp += strlen(cstrp) + 1;
 
     info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
@@ -2020,16 +2427,16 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
     tp = p->parmsp + 1; /* Skip over function number */
 
     {
-        char * cdescp;
+        clientchar_t * cdescp;
 
-        cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+        cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
                                        SMB_STRF_FORCEASCII);
-        if (strcmp(cdescp, "WrLh"))
+        if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
             return CM_ERROR_INVAL;
         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
                                        SMB_STRF_FORCEASCII);
-        if (strcmp(cdescp, "B16") ||
-            strcmp(cdescp, "B16BBDz"))
+        if (cm_ClientStrCmp(cdescp,  _C("B16")) ||
+            cm_ClientStrCmp(cdescp,  _C("B16BBDz")))
             return CM_ERROR_INVAL;
     }
 
@@ -2042,7 +2449,7 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
 
     totalParams = 6;
 
-    totalData = 
+    totalData =
         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
 
@@ -2054,13 +2461,13 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
     if (infoLevel == 0) {
         info0 = (smb_rap_server_info_0_t *) outp->datap;
         cstrp = (char *) (info0 + 1);
-        strcpy(info0->sv0_name, "AFS");
+        StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
     } else { /* infoLevel == SMB_INFO_STANDARD */
         info1 = (smb_rap_server_info_1_t *) outp->datap;
         cstrp = (char *) (info1 + 1);
-        strcpy(info1->sv1_name, "AFS");
+        StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
 
-        info1->sv1_type = 
+        info1->sv1_type =
             SMB_SV_TYPE_SERVER |
             SMB_SV_TYPE_NT |
             SMB_SV_TYPE_SERVER_NT;
@@ -2069,9 +2476,9 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
         info1->sv1_version_minor = 1;
         info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
 
-        strcpy(cstrp, smb_ServerComment);
+        StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
 
-        cstrp += smb_ServerCommentLen;
+        cstrp += smb_ServerCommentLen / sizeof(char);
     }
 
     totalData = (DWORD)(cstrp - outp->datap);
@@ -2100,10 +2507,11 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     int dataCount;
     int firstPacket;
     long code = 0;
+    DWORD oldTime, newTime;
 
     /* We sometimes see 0 word count.  What to do? */
     if (*inp->wctp == 0) {
-        osi_Log0(smb_logp, "Transaction2 word count = 0"); 
+        osi_Log0(smb_logp, "Transaction2 word count = 0");
        LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
 
         smb_SetSMBDataLength(outp, 0);
@@ -2113,9 +2521,9 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     totalParms = smb_GetSMBParm(inp, 0);
     totalData = smb_GetSMBParm(inp, 1);
-        
+
     firstPacket = (inp->inCom == 0x32);
-        
+
     /* find the packet we're reassembling */
     lock_ObtainWrite(&smb_globalLock);
     asp = smb_FindTran2Packet(vcp, inp);
@@ -2123,7 +2531,7 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
     }
     lock_ReleaseWrite(&smb_globalLock);
-        
+
     /* now merge in this latest packet; start by looking up offsets */
     if (firstPacket) {
         parmDisp = dataDisp = 0;
@@ -2147,7 +2555,7 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
                  parmCount, dataCount);
-    }   
+    }
 
     /* now copy the parms and data */
     if ( asp->totalParms > 0 && parmCount != 0 )
@@ -2172,6 +2580,8 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
         lock_ReleaseWrite(&smb_globalLock);
 
+        oldTime = GetTickCount();
+
         /* now dispatch it */
         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
@@ -2191,6 +2601,46 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             smb_SendTran2Error(vcp, asp, outp, code);
         }
 
+        newTime = GetTickCount();
+        if (newTime - oldTime > 45000) {
+            smb_user_t *uidp;
+            smb_fid_t *fidp;
+            clientchar_t *treepath = NULL;  /* do not free */
+            clientchar_t *pathname = NULL;
+            cm_fid_t afid = {0,0,0,0,0};
+
+            uidp = smb_FindUID(vcp, asp->uid, 0);
+            smb_LookupTIDPath(vcp, asp->tid, &treepath);
+            fidp = smb_FindFID(vcp, inp->fid, 0);
+
+            if (fidp) {
+                lock_ObtainMutex(&fidp->mx);
+                if (fidp->NTopen_pathp)
+                    pathname = fidp->NTopen_pathp;
+                if (fidp->scp)
+                    afid = fidp->scp->fid;
+            } else {
+                if (inp->stringsp->wdata)
+                    pathname = inp->stringsp->wdata;
+            }
+
+            afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
+                      myCrt_2Dispatch(asp->opcode), newTime - oldTime,
+                      asp->uid, uidp ? uidp->unp->name : NULL,
+                      asp->pid, asp->mid, asp->tid,
+                      treepath,
+                      pathname,
+                      afid.cell, afid.volume, afid.vnode, afid.unique);
+
+            if (fidp)
+                lock_ReleaseMutex(&fidp->mx);
+
+            if (uidp)
+                smb_ReleaseUID(uidp);
+            if (fidp)
+                smb_ReleaseFID(fidp);
+        }
+
         /* free the input tran 2 packet */
         smb_FreeTran2Packet(asp);
     }
@@ -2208,7 +2658,7 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 /* TRANS2_OPEN2 */
 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
-    char *pathp;
+    clientchar_t *pathp;
     smb_tran2Packet_t *outp;
     long code = 0;
     cm_space_t *spacep;
@@ -2217,10 +2667,9 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     cm_scache_t *dscp;         /* dir we're dealing with */
     cm_scache_t *scp;          /* file we're creating */
     cm_attr_t setAttr;
-    int initialModeBits;
     smb_fid_t *fidp;
     int attributes;
-    char *lastNamep;
+    clientchar_t *lastNamep;
     afs_uint32 dosTime;
     int openFun;
     int trunc;
@@ -2229,14 +2678,16 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     int openAction;
     int parmSlot;                      /* which parm we're dealing with */
     long returnEALength;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     cm_req_t req;
     int created = 0;
+    BOOL is_rpc = FALSE;
+    BOOL is_ipc = FALSE;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     scp = NULL;
-        
+
     extraInfo = (p->parmsp[0] & 1);    /* return extra info */
     returnEALength = (p->parmsp[0] & 8);       /* return extended attr length */
 
@@ -2248,30 +2699,51 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 
     attributes = p->parmsp[3];
     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
-        
-    /* compute initial mode bits based on read-only flag in attributes */
-    initialModeBits = 0666;
-    if (attributes & SMB_ATTR_READONLY) 
-        initialModeBits &= ~0222;
-        
+
     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
                                   SMB_STRF_ANSIPATH);
-    
+
     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
 
+    code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+    if (code == CM_ERROR_TIDIPC) {
+       is_ipc = TRUE;
+        osi_Log0(smb_logp, "Tran2Open received IPC TID");
+    }
+
     spacep = cm_GetSpace();
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    /* smb_StripLastComponent will strip "::$DATA" if present */
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
+
+    if (lastNamep &&
 
-    if (lastNamep && 
-         (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
-           stricmp(lastNamep, "\\srvsvc") == 0 ||
-           stricmp(lastNamep, "\\wkssvc") == 0 ||
-           stricmp(lastNamep, "\\ipc$") == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
+        (cm_ClientStrCmpI(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
+
+        /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
+        (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
+
+       unsigned short file_type = 0;
+       unsigned short device_state = 0;
+
         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-        smb_SetupIoctlFid(fidp, spacep);
+
+       if (is_rpc) {
+           code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
+           osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
+                     fidp->fid, code);
+           if (code) {
+               smb_ReleaseFID(fidp);
+               smb_FreeTran2Packet(outp);
+               osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
+               return code;
+           }
+       } else {
+           smb_SetupIoctlFid(fidp, spacep);
+           osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
+       }
 
         /* copy out remainder of the parms */
         parmSlot = 0;
@@ -2279,13 +2751,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         if (extraInfo) {
             outp->parmsp[parmSlot++] = 0;       /* attrs */
             outp->parmsp[parmSlot++] = 0;       /* mod time */
-            outp->parmsp[parmSlot++] = 0; 
+            outp->parmsp[parmSlot++] = 0;
             outp->parmsp[parmSlot++] = 0;       /* len */
             outp->parmsp[parmSlot++] = 0x7fff;
             outp->parmsp[parmSlot++] = openMode;
-            outp->parmsp[parmSlot++] = 0;       /* file type 0 ==> normal file or dir */
-            outp->parmsp[parmSlot++] = 0;       /* IPC junk */
-        }   
+            outp->parmsp[parmSlot++] = file_type;
+            outp->parmsp[parmSlot++] = device_state;
+        }
         /* and the final "always present" stuff */
         outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
         /* next write out the "unique" ID */
@@ -2295,13 +2767,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         if (returnEALength) {
             outp->parmsp[parmSlot++] = 0;
             outp->parmsp[parmSlot++] = 0;
-        }       
-                
+        }
+
         outp->totalData = 0;
         outp->totalParms = parmSlot * 2;
-                
+
         smb_SendTran2Packet(vcp, outp, op);
-                
+
         smb_FreeTran2Packet(outp);
 
         /* and clean up fid reference */
@@ -2309,6 +2781,30 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         return 0;
     }
 
+#ifndef DFS_SUPPORT
+    if (is_ipc) {
+        osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
+       smb_FreeTran2Packet(outp);
+       return CM_ERROR_BADFD;
+    }
+#endif
+
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
+#endif
+        smb_FreeTran2Packet(outp);
+        return CM_ERROR_BADNTFILENAME;
+    }
+
 #ifdef DEBUG_VERBOSE
     {
         char *hexp, *asciip;
@@ -2316,7 +2812,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         hexp = osi_HexifyString( asciip );
         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
         free(hexp);
-    }       
+    }
 #endif
 
     userp = smb_GetTran2User(vcp, p);
@@ -2327,29 +2823,17 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         return CM_ERROR_BADSMB;
     }
 
-    code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
-    if (code == CM_ERROR_TIDIPC) {
-        /* Attempt to use a TID allocated for IPC.  The client
-         * is probably looking for DCE RPC end points which we
-         * don't support OR it could be looking to make a DFS
-         * referral request. 
-         */
-        osi_Log0(smb_logp, "Tran2Open received IPC TID");
-#ifndef DFS_SUPPORT
-        cm_ReleaseUser(userp);
-        smb_FreeTran2Packet(outp);
-        return CM_ERROR_NOSUCHPATH;
-#endif
-    }
-
     dscp = NULL;
-    code = cm_NameI(cm_data.rootSCachep, pathp,
+    code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                      userp, tidPathp, &req, &scp);
     if (code != 0) {
-        code = cm_NameI(cm_data.rootSCachep, spacep->data,
-                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                         userp, tidPathp, &req, &dscp);
+        if (code == CM_ERROR_NOSUCHFILE ||
+            code == CM_ERROR_NOSUCHPATH ||
+            code == CM_ERROR_BPLUS_NOMATCH)
+            code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
+                            CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                            userp, tidPathp, &req, &dscp);
         cm_FreeSpace(spacep);
 
         if (code) {
@@ -2357,17 +2841,18 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             smb_FreeTran2Packet(outp);
             return code;
         }
-        
+
 #ifdef DFS_SUPPORT
         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+                                                      (clientchar_t*) spacep->data);
             cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
             smb_FreeTran2Packet(outp);
             if ( WANTS_DFS_PATHNAMES(p) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
 
@@ -2375,9 +2860,9 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
          * and truncate the file if we find it, otherwise we create the
          * file.
          */
-        if (!lastNamep) 
+        if (!lastNamep)
             lastNamep = pathp;
-        else 
+        else
             lastNamep++;
         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
                          &req, &scp);
@@ -2388,6 +2873,9 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             return code;
         }
     } else {
+        /* macintosh is expensive to program for it */
+        cm_FreeSpace(spacep);
+
 #ifdef DFS_SUPPORT
         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
@@ -2397,21 +2885,18 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             if ( WANTS_DFS_PATHNAMES(p) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
-
-        /* macintosh is expensive to program for it */
-        cm_FreeSpace(spacep);
     }
-        
+
     /* if we get here, if code is 0, the file exists and is represented by
      * scp.  Otherwise, we have to create it.
      */
     if (code == 0) {
         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
         if (code) {
-            if (dscp) 
+            if (dscp)
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -2421,7 +2906,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 
         if (excl) {
             /* oops, file shouldn't be there */
-            if (dscp) 
+            if (dscp)
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -2435,13 +2920,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             setAttr.length.HighPart = 0;
             code = cm_SetAttr(scp, &setAttr, userp, &req);
             openAction = 3;    /* truncated existing file */
-        }   
-        else 
+        }
+        else
             openAction = 1;    /* found existing file */
     }
     else if (!(openFun & 0x10)) {
         /* don't create if not found */
-        if (dscp) 
+        if (dscp)
             cm_ReleaseSCache(dscp);
         osi_assertx(scp == NULL, "null cm_scache_t");
         cm_ReleaseUser(userp);
@@ -2452,14 +2937,16 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
         openAction = 2;        /* created file */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
-        smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
+        cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
+        smb_SetInitialModeBitsForFile(attributes, &setAttr);
+
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                           &req);
         if (code == 0) {
            created = 1;
            if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
                smb_NotifyChange(FILE_ACTION_ADDED,
-                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
                                  dscp, lastNamep, NULL, TRUE);
        } else if (!excl && code == CM_ERROR_EXISTS) {
             /* not an exclusive create, and someone else tried
@@ -2477,24 +2964,24 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
                     setAttr.length.HighPart = 0;
                     code = cm_SetAttr(scp, &setAttr, userp,
                                        &req);
-                }   
+                }
             }  /* lookup succeeded */
         }
     }
-        
+
     /* we don't need this any longer */
-    if (dscp) 
+    if (dscp)
         cm_ReleaseSCache(dscp);
 
     if (code) {
         /* something went wrong creating or truncating the file */
-        if (scp) 
+        if (scp)
             cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         smb_FreeTran2Packet(outp);
         return code;
     }
-        
+
     /* make sure we're about to open a file */
     if (scp->fileType != CM_SCACHETYPE_FILE) {
         code = 0;
@@ -2523,7 +3010,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     /* now all we have to do is open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
     osi_assertx(fidp, "null smb_fid_t");
-       
+
     cm_HoldUser(userp);
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
@@ -2532,12 +3019,12 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
     lock_ReleaseWrite(&scp->rw);
-    
+
     /* and the user */
     fidp->userp = userp;
-        
+
     /* compute open mode */
-    if (openMode != 1) 
+    if (openMode != 1)
        fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     if (openMode == 1 || openMode == 2)
         fidp->flags |= SMB_FID_OPENWRITE;
@@ -2549,7 +3036,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     lock_ReleaseMutex(&fidp->mx);
 
     smb_ReleaseFID(fidp);
-        
+
     cm_Open(scp, 0, userp);
 
     /* copy out remainder of the parms */
@@ -2558,7 +3045,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     lock_ObtainRead(&scp->rw);
     if (extraInfo) {
         outp->parmsp[parmSlot++] = smb_Attributes(scp);
-        smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+        cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
@@ -2566,17 +3053,17 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         outp->parmsp[parmSlot++] = openMode;
         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
-    }   
+    }
     /* and the final "always present" stuff */
     outp->parmsp[parmSlot++] = openAction;
     /* next write out the "unique" ID */
-    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
-    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
-    outp->parmsp[parmSlot++] = 0; 
+    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
+    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
+    outp->parmsp[parmSlot++] = 0;
     if (returnEALength) {
-        outp->parmsp[parmSlot++] = 0; 
-        outp->parmsp[parmSlot++] = 0; 
-    }   
+        outp->parmsp[parmSlot++] = 0;
+        outp->parmsp[parmSlot++] = 0;
+    }
     lock_ReleaseRead(&scp->rw);
     outp->totalData = 0;               /* total # of data bytes */
     outp->totalParms = parmSlot * 2;   /* shorts are two bytes */
@@ -2588,7 +3075,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     cm_ReleaseUser(userp);
     /* leave scp held since we put it in fidp->scp */
     return 0;
-}   
+}
 
 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
@@ -2598,7 +3085,7 @@ long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     infolevel = p->parmsp[0];
     fid = p->parmsp[1];
     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
-    
+
     return CM_ERROR_BAD_LEVEL;
 }
 
@@ -2609,13 +3096,13 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
     smb_tran2QFSInfo_t qi;
     int responseSize;
     size_t sz = 0;
-        
+
     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
 
     switch (p->parmsp[0]) {
-    case SMB_INFO_ALLOCATION: 
+    case SMB_INFO_ALLOCATION:
         /* alloc info */
-       responseSize = sizeof(qi.u.allocInfo); 
+       responseSize = sizeof(qi.u.allocInfo);
 
         qi.u.allocInfo.FSID = 0;
         qi.u.allocInfo.sectorsPerAllocUnit = 1;
@@ -2624,19 +3111,19 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         qi.u.allocInfo.bytesPerSector = 1024;
         break;
 
-    case SMB_INFO_VOLUME: 
+    case SMB_INFO_VOLUME:
         /* volume info */
         qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
-        qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
+        qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
 
         /* we're supposed to pad it out with zeroes to the end */
         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
-        smb_UnparseString(op, qi.u.volumeInfo.label, "AFS", &sz, 0);
+        smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
 
         responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
         break;
 
-    case SMB_QUERY_FS_VOLUME_INFO: 
+    case SMB_QUERY_FS_VOLUME_INFO:
         /* FS volume info */
        responseSize = sizeof(qi.u.FSvolumeInfo);
 
@@ -2646,13 +3133,14 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         }
 
         qi.u.FSvolumeInfo.vsn = 1234;
-        qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
+        qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
+        memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
         memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
         break;
 
-    case SMB_QUERY_FS_SIZE_INFO: 
+    case SMB_QUERY_FS_SIZE_INFO:
         /* FS size info */
-       responseSize = sizeof(qi.u.FSsizeInfo); 
+       responseSize = sizeof(qi.u.FSsizeInfo);
 
         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
        qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
@@ -2662,20 +3150,21 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         qi.u.FSsizeInfo.bytesPerSector = 1024;
         break;
 
-    case SMB_QUERY_FS_DEVICE_INFO: 
+    case SMB_QUERY_FS_DEVICE_INFO:
         /* FS device info */
-       responseSize = sizeof(qi.u.FSdeviceInfo); 
+       responseSize = sizeof(qi.u.FSdeviceInfo);
 
         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
         break;
 
-    case SMB_QUERY_FS_ATTRIBUTE_INFO: 
+    case SMB_QUERY_FS_ATTRIBUTE_INFO:
         /* FS attribute info */
 
         /* attributes, defined in WINNT.H:
          *     FILE_CASE_SENSITIVE_SEARCH      0x1
          *     FILE_CASE_PRESERVED_NAMES       0x2
+         *      FILE_UNICODE_ON_DISK            0x4
         *      FILE_VOLUME_QUOTAS              0x10
          *     <no name defined>               0x4000
          *        If bit 0x4000 is not set, Windows 95 thinks
@@ -2685,15 +3174,10 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         qi.u.FSattributeInfo.attributes = 0x4003;
         /* The maxCompLength is supposed to be in bytes */
 #ifdef SMB_UNICODE
-        if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
-            qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
-        else {
-#endif
-        qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
-#ifdef SMB_UNICODE
-        }
+        qi.u.FSattributeInfo.attributes |= 0x04;
 #endif
-        smb_UnparseString(op, qi.u.FSattributeInfo.FSname, "AFS", &sz, 0);
+        qi.u.FSattributeInfo.maxCompLength = 255;
+        smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
         qi.u.FSattributeInfo.FSnameLength = sz;
 
        responseSize =
@@ -2706,12 +3190,12 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
 
     case SMB_INFO_UNIX:        /* CIFS Unix Info */
     case SMB_INFO_MACOS:       /* Mac FS Info */
-    default: 
+    default:
        return CM_ERROR_BADOP;
-    }   
-        
+    }
+
     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
-        
+
     /* copy out return data, and set corresponding sizes */
     outp->totalParms = 0;
     outp->totalData = responseSize;
@@ -2731,37 +3215,47 @@ long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 }
 
 struct smb_ShortNameRock {
-    char *maskp;
+    clientchar_t *maskp;
     unsigned int vnode;
-    char *shortName;
+    clientchar_t *shortName;
     size_t shortNameLen;
-};      
+};
 
 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
                          osi_hyper_t *offp)
-{       
+{
     struct smb_ShortNameRock *rockp;
-    char *shortNameEnd;
+    normchar_t normName[MAX_PATH];
+    clientchar_t *shortNameEnd;
 
     rockp = vrockp;
+
+    if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
+
     /* compare both names and vnodes, though probably just comparing vnodes
      * would be safe enough.
      */
-    if (cm_stricmp(dep->name, rockp->maskp) != 0)
+    if (cm_NormStrCmpI(normName,  rockp->maskp) != 0)
         return 0;
     if (ntohl(dep->fid.vnode) != rockp->vnode)
         return 0;
+
     /* This is the entry */
     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
     rockp->shortNameLen = shortNameEnd - rockp->shortName;
+
     return CM_ERROR_STOPNOW;
-}       
+}
 
-long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
-       char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
+long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
+       clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
 {
     struct smb_ShortNameRock rock;
-    char *lastNamep;
+    clientchar_t *lastNamep;
     cm_space_t *spacep;
     cm_scache_t *dscp;
     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
@@ -2769,19 +3263,23 @@ long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
     osi_hyper_t thyper;
 
     spacep = cm_GetSpace();
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    /* smb_StripLastComponent will strip "::$DATA" if present */
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
-    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
-                     reqp, &dscp);
+    code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
+                    caseFold, userp, tidPathp,
+                    reqp, &dscp);
     cm_FreeSpace(spacep);
-    if (code) 
+    if (code)
         return code;
 
 #ifdef DFS_SUPPORT
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
+#ifdef DEBUG
         DebugBreak();
+#endif
         return CM_ERROR_PATH_NOT_COVERED;
     }
 #endif /* DFS_SUPPORT */
@@ -2817,27 +3315,27 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     int responseSize;
     unsigned short attributes;
     unsigned long extAttributes;
-    char shortName[13];
+    clientchar_t shortName[13];
     size_t len;
     cm_user_t *userp;
     cm_space_t *spacep;
     cm_scache_t *scp, *dscp;
-    int scp_mx_held = 0;
+    int scp_rw_held = 0;
     int delonclose = 0;
     long code = 0;
-    char *pathp;
-    char *tidPathp;
-    char *lastComp;
+    clientchar_t *pathp;
+    clientchar_t *tidPathp;
+    clientchar_t *lastComp;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     infoLevel = p->parmsp[0];
-    if (infoLevel == SMB_INFO_IS_NAME_VALID) 
+    if (infoLevel == SMB_INFO_IS_NAME_VALID)
         responseSize = 0;
-    else if (infoLevel == SMB_INFO_STANDARD) 
+    else if (infoLevel == SMB_INFO_STANDARD)
         responseSize = sizeof(qpi.u.QPstandardInfo);
-    else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
+    else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
         responseSize = sizeof(qpi.u.QPeaSizeInfo);
     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
         responseSize = sizeof(qpi.u.QPfileBasicInfo);
@@ -2845,22 +3343,25 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        responseSize = sizeof(qpi.u.QPfileStandardInfo);
     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
         responseSize = sizeof(qpi.u.QPfileEaInfo);
-    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
         responseSize = sizeof(qpi.u.QPfileNameInfo);
-    else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
         responseSize = sizeof(qpi.u.QPfileAllInfo);
-    else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
+    else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
+        responseSize = sizeof(qpi.u.QPfileStreamInfo);
     else {
-        osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+        osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         return 0;
     }
+    memset(&qpi, 0, sizeof(qpi));
 
     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
-    osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
-              osi_LogSaveString(smb_logp, pathp));
+    osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
+              osi_LogSaveClientString(smb_logp, pathp));
 
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
 
@@ -2868,8 +3369,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         outp->totalParms = 2;
     else
         outp->totalParms = 0;
-    outp->totalData = responseSize;
-        
+
     /* now, if we're at infoLevel 6, we're only being asked to check
      * the syntax, so we just OK things now.  In particular, we're *not*
      * being asked to verify anything about the state of any parent dirs.
@@ -2878,8 +3378,8 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         smb_SendTran2Packet(vcp, outp, opx);
         smb_FreeTran2Packet(outp);
         return 0;
-    }   
-        
+    }
+
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
@@ -2889,12 +3389,16 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
     if(code) {
+        osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
         cm_ReleaseUser(userp);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
         smb_FreeTran2Packet(outp);
         return 0;
     }
 
+    osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
+              osi_LogSaveClientString(smb_logp, tidPathp));
+
     /*
      * XXX Strange hack XXX
      *
@@ -2911,12 +3415,13 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
      */
     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
         spacep = cm_GetSpace();
-        smb_StripLastComponent(spacep->data, &lastComp, pathp);
+        /* smb_StripLastComponent will strip "::$DATA" if present */
+        smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
 #ifndef SPECIAL_FOLDERS
         /* Make sure that lastComp is not NULL */
         if (lastComp) {
-            if (stricmp(lastComp, "\\desktop.ini") == 0) {
-                code = cm_NameI(cm_data.rootSCachep, spacep->data,
+            if (cm_ClientStrCmpIA(lastComp,  _C("\\desktop.ini")) == 0) {
+                code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
                                  CM_FLAG_CASEFOLD
                                  | CM_FLAG_DIRSEARCH
                                  | CM_FLAG_FOLLOW,
@@ -2924,17 +3429,18 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 if (code == 0) {
 #ifdef DFS_SUPPORT
                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+                                                                  spacep->wdata);
                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
                             code = CM_ERROR_PATH_NOT_COVERED;
                         else
-                            code = CM_ERROR_BADSHARENAME;
+                            code = CM_ERROR_NOSUCHPATH;
                     } else
 #endif /* DFS_SUPPORT */
                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
                         code = CM_ERROR_NOSUCHFILE;
                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
-                        cm_buf_t *bp = buf_Find(dscp, &hzero);
+                        cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
                         if (bp) {
                             buf_Release(bp);
                             bp = NULL;
@@ -2958,9 +3464,14 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         cm_FreeSpace(spacep);
     }
 
-    /* now do namei and stat, and copy out the info */
-    code = cm_NameI(cm_data.rootSCachep, pathp,
-                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
+    if (code == 0 ||
+        code == CM_ERROR_NOSUCHFILE ||
+        code == CM_ERROR_NOSUCHPATH ||
+        code == CM_ERROR_BPLUS_NOMATCH) {
+        /* now do namei and stat, and copy out the info */
+        code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
+                        CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
+    }
 
     if (code) {
         cm_ReleaseUser(userp);
@@ -2977,7 +3488,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         if ( WANTS_DFS_PATHNAMES(p) || pnc )
             code = CM_ERROR_PATH_NOT_COVERED;
         else
-            code = CM_ERROR_BADSHARENAME;
+            code = CM_ERROR_NOSUCHPATH;
         smb_SendTran2Error(vcp, p, opx, code);
         smb_FreeTran2Packet(outp);
         return 0;
@@ -2985,14 +3496,16 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 #endif /* DFS_SUPPORT */
 
     lock_ObtainWrite(&scp->rw);
-    scp_mx_held = 1;
+    scp_rw_held = 2;
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) goto done;
+    if (code)
+        goto done;
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        
+
     lock_ConvertWToR(&scp->rw);
+    scp_rw_held = 1;
 
     len = 0;
 
@@ -3008,19 +3521,17 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             goto done;
         }
 
-        smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, 0);
+        smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
        qpi.u.QPfileAltNameInfo.fileNameLength = len;
-
-        goto done;
+        responseSize = sizeof(unsigned long) + len;
     }
     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
-        smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, 0);
+        smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
        qpi.u.QPfileNameInfo.fileNameLength = len;
-
-        goto done;
+        responseSize = sizeof(unsigned long) + len;
     }
     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
-        smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+        cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
        qpi.u.QPstandardInfo.creationDateTime = dosTime;
        qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
        qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
@@ -3031,7 +3542,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        qpi.u.QPstandardInfo.eaSize = 0;
     }
     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         qpi.u.QPfileBasicInfo.creationTime = ft;
         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
@@ -3041,20 +3552,22 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        qpi.u.QPfileBasicInfo.reserved = 0;
     }
     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
-       smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
+       smb_fid_t * fidp;
+
+        lock_ReleaseRead(&scp->rw);
+        scp_rw_held = 0;
+        fidp = smb_FindFIDByScache(vcp, scp);
 
         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
-        qpi.u.QPfileStandardInfo.directory = 
+        qpi.u.QPfileStandardInfo.directory =
            ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
              scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
         qpi.u.QPfileStandardInfo.reserved = 0;
 
        if (fidp) {
-           lock_ReleaseRead(&scp->rw);
-           scp_mx_held = 0;
            lock_ObtainMutex(&fidp->mx);
            delonclose = fidp->flags & SMB_FID_DELONCLOSE;
            lock_ReleaseMutex(&fidp->mx);
@@ -3066,7 +3579,13 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         qpi.u.QPfileEaInfo.eaSize = 0;
     }
     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+       smb_fid_t * fidp;
+
+        lock_ReleaseRead(&scp->rw);
+        scp_rw_held = 0;
+        fidp = smb_FindFIDByScache(vcp, scp);
+
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         qpi.u.QPfileAllInfo.creationTime = ft;
         qpi.u.QPfileAllInfo.lastAccessTime = ft;
         qpi.u.QPfileAllInfo.lastWriteTime = ft;
@@ -3077,29 +3596,69 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         qpi.u.QPfileAllInfo.endOfFile = scp->length;
         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
         qpi.u.QPfileAllInfo.deletePending = 0;
-        qpi.u.QPfileAllInfo.directory = 
+        qpi.u.QPfileAllInfo.directory =
            ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
              scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
-       qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
-       qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
+       qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
+       qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.unique;
        qpi.u.QPfileAllInfo.eaSize = 0;
-       qpi.u.QPfileAllInfo.accessFlags = 0;
-       qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
-       qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
+        qpi.u.QPfileAllInfo.accessFlags = 0;
+        if (fidp) {
+           lock_ObtainMutex(&fidp->mx);
+            if (fidp->flags & SMB_FID_OPENDELETE)
+                qpi.u.QPfileAllInfo.accessFlags |= DELETE;
+            if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
+                qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
+            if (fidp->flags & SMB_FID_OPENWRITE)
+                qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
+            if (fidp->flags & SMB_FID_DELONCLOSE)
+                qpi.u.QPfileAllInfo.deletePending = 1;
+           lock_ReleaseMutex(&fidp->mx);
+           smb_ReleaseFID(fidp);
+        }
+       qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
+       qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.volume;
        qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
        qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
        qpi.u.QPfileAllInfo.mode = 0;
        qpi.u.QPfileAllInfo.alignmentRequirement = 0;
 
-        smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, 0);
+        smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
        qpi.u.QPfileAllInfo.fileNameLength = len;
+        responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
+    }
+    else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
+        size_t len = 0;
+        /* For now we have no streams */
+        qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
+        if (scp->fileType == CM_SCACHETYPE_FILE) {
+            qpi.u.QPfileStreamInfo.streamSize = scp->length;
+            qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
+            smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
+            qpi.u.QPfileStreamInfo.streamNameLength = len;
+            responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
+        } else {
+            qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
+            qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
+            smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
+            qpi.u.QPfileStreamInfo.streamNameLength = 0;
+            responseSize = 0;
+        }
     }
+    outp->totalData = responseSize;
 
     /* send and free the packets */
   done:
-    if (scp_mx_held)
+    switch (scp_rw_held) {
+    case 1:
        lock_ReleaseRead(&scp->rw);
+        break;
+    case 2:
+        lock_ReleaseWrite(&scp->rw);
+        break;
+    }
+    scp_rw_held = 0;
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     if (code == 0) {
@@ -3121,50 +3680,49 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     return CM_ERROR_BADOP;
 #else
     long code = 0;
-    smb_fid_t *fidp;
     unsigned short infoLevel;
-    char * pathp;
+    clientchar_t * pathp;
     smb_tran2Packet_t *outp;
     smb_tran2QPathInfo_t *spi;
     cm_user_t *userp;
     cm_scache_t *scp, *dscp;
     cm_req_t req;
     cm_space_t *spacep;
-    char *tidPathp;
-    char *lastComp;
+    clientchar_t *tidPathp;
+    clientchar_t *lastComp;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     infoLevel = p->parmsp[0];
     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
-    if (infoLevel != SMB_INFO_STANDARD && 
+    if (infoLevel != SMB_INFO_STANDARD &&
        infoLevel != SMB_INFO_QUERY_EA_SIZE &&
        infoLevel != SMB_INFO_QUERY_ALL_EAS) {
-        osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+        osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
-        smb_SendTran2Error(vcp, p, opx, 
+        smb_SendTran2Error(vcp, p, opx,
                            infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
         return 0;
     }
 
     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
 
-    osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
-              osi_LogSaveString(smb_logp, pathp));
+    osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
+              osi_LogSaveClientString(smb_logp, pathp));
 
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
        osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
        code = CM_ERROR_BADSMB;
        goto done;
-    }   
+    }
 
     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
     if (code == CM_ERROR_TIDIPC) {
         /* Attempt to use a TID allocated for IPC.  The client
          * is probably looking for DCE RPC end points which we
          * don't support OR it could be looking to make a DFS
-         * referral request. 
+         * referral request.
          */
         osi_Log0(smb_logp, "Tran2Open received IPC TID");
         cm_ReleaseUser(userp);
@@ -3187,12 +3745,13 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     */
     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
         spacep = cm_GetSpace();
-        smb_StripLastComponent(spacep->data, &lastComp, pathp);
+        /* smb_StripLastComponent will strip "::$DATA" if present */
+        smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
 #ifndef SPECIAL_FOLDERS
         /* Make sure that lastComp is not NULL */
         if (lastComp) {
-            if (stricmp(lastComp, "\\desktop.ini") == 0) {
-                code = cm_NameI(cm_data.rootSCachep, spacep->data,
+            if (cm_ClientStrCmpI(lastComp,  _C("\\desktop.ini")) == 0) {
+                code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
                                  CM_FLAG_CASEFOLD
                                  | CM_FLAG_DIRSEARCH
                                  | CM_FLAG_FOLLOW,
@@ -3200,17 +3759,18 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                 if (code == 0) {
 #ifdef DFS_SUPPORT
                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+                                                                  spacep->wdata);
                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
                             code = CM_ERROR_PATH_NOT_COVERED;
                         else
-                            code = CM_ERROR_BADSHARENAME;
+                            code = CM_ERROR_NOSUCHPATH;
                     } else
 #endif /* DFS_SUPPORT */
                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
                         code = CM_ERROR_NOSUCHFILE;
                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
-                        cm_buf_t *bp = buf_Find(dscp, &hzero);
+                        cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
                         if (bp) {
                             buf_Release(bp);
                             bp = NULL;
@@ -3233,33 +3793,20 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         cm_FreeSpace(spacep);
     }
 
-    /* now do namei and stat, and copy out the info */
-    code = cm_NameI(cm_data.rootSCachep, pathp,
-                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
-    if (code) {
-        cm_ReleaseUser(userp);
-        smb_SendTran2Error(vcp, p, opx, code);
-        return 0;
-    }
-
-    fidp = smb_FindFIDByScache(vcp, scp);
-    if (!fidp) {
-        cm_ReleaseSCache(scp);
-        cm_ReleaseUser(userp);
-       smb_SendTran2Error(vcp, p, opx, code);
-        return 0;
+    if (code == 0 ||
+        code == CM_ERROR_NOSUCHFILE ||
+        code == CM_ERROR_NOSUCHPATH ||
+        code == CM_ERROR_BPLUS_NOMATCH) {
+        /* now do namei and stat, and copy out the info */
+        code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
+                        CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
     }
 
-    lock_ObtainMutex(&fidp->mx);
-    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
-       lock_ReleaseMutex(&fidp->mx);
-        cm_ReleaseSCache(scp);
-        smb_ReleaseFID(fidp);
+    if (code) {
         cm_ReleaseUser(userp);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
+        smb_SendTran2Error(vcp, p, opx, code);
         return 0;
     }
-    lock_ReleaseMutex(&fidp->mx);
 
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
 
@@ -3283,29 +3830,24 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         }
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-       lock_ReleaseWrite(&scp->rw);
-       lock_ObtainMutex(&fidp->mx);
-       lock_ObtainRead(&scp->rw);
-
         /* prepare for setattr call */
         attr.mask = CM_ATTRMASK_LENGTH;
         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
         attr.length.HighPart = 0;
 
        if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
-           smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
+           cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
-            fidp->flags |= SMB_FID_MTIMESETDONE;
         }
-               
+
         if (spi->u.QPstandardInfo.attributes != 0) {
-            if ((scp->unixModeBits & 0222)
+            if ((scp->unixModeBits & 0200)
                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
                 /* make a writable file read-only */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
                 attr.unixModeBits = scp->unixModeBits & ~0222;
             }
-            else if ((scp->unixModeBits & 0222) == 0
+            else if ((scp->unixModeBits & 0200) == 0
                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
                 /* make a read-only file writable */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
@@ -3313,26 +3855,24 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
             }
         }
         lock_ReleaseRead(&scp->rw);
-       lock_ReleaseMutex(&fidp->mx);
 
         /* call setattr */
         if (attr.mask)
             code = cm_SetAttr(scp, &attr, userp, &req);
         else
             code = 0;
-    }               
+    }
     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
        /* we don't support EAs */
        code = CM_ERROR_EAS_NOT_SUPPORTED;
-    }       
+    }
 
   done:
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
-    smb_ReleaseFID(fidp);
-    if (code == 0) 
+    if (code == 0)
         smb_SendTran2Packet(vcp, outp, opx);
-    else 
+    else
         smb_SendTran2Error(vcp, p, opx, code);
     smb_FreeTran2Packet(outp);
 
@@ -3358,40 +3898,48 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     int  readlock = 0;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = p->parmsp[0];
     fidp = smb_FindFID(vcp, fid, 0);
 
     if (fidp == NULL) {
+        osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
         return 0;
     }
 
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return 0;
     }
+    lock_ReleaseMutex(&fidp->mx);
 
     infoLevel = p->parmsp[1];
-    if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
+    if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
         responseSize = sizeof(qfi.u.QFbasicInfo);
-    else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
         responseSize = sizeof(qfi.u.QFstandardInfo);
     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
         responseSize = sizeof(qfi.u.QFeaInfo);
-    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
+    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
         responseSize = sizeof(qfi.u.QFfileNameInfo);
+    else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
+        responseSize = sizeof(qfi.u.QFfileStreamInfo);
     else {
-        osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+        osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         smb_ReleaseFID(fidp);
         return 0;
     }
     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
+    memset(&qfi, 0, sizeof(qfi));
 
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
 
@@ -3399,14 +3947,13 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         outp->totalParms = 2;
     else
         outp->totalParms = 0;
-    outp->totalData = responseSize;
 
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
        osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
        code = CM_ERROR_BADSMB;
        goto done;
-    }   
+    }
 
     lock_ObtainMutex(&fidp->mx);
     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
@@ -3417,7 +3964,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) 
+    if (code)
         goto done;
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
@@ -3429,7 +3976,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
      * Marshall the output data.
      */
     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         qfi.u.QFbasicInfo.creationTime = ft;
         qfi.u.QFbasicInfo.lastAccessTime = ft;
         qfi.u.QFbasicInfo.lastWriteTime = ft;
@@ -3442,7 +3989,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        qfi.u.QFstandardInfo.endOfFile = scp->length;
         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
-        qfi.u.QFstandardInfo.directory = 
+        qfi.u.QFstandardInfo.directory =
            ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
              scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
@@ -3452,7 +3999,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     }
     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
         size_t len = 0;
-        char *name;
+        clientchar_t *name;
 
        lock_ReleaseRead(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
@@ -3460,13 +4007,32 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         if (fidp->NTopen_wholepathp)
             name = fidp->NTopen_wholepathp;
         else
-            name = "\\";       /* probably can't happen */
+            name = _C("\\");   /* probably can't happen */
        lock_ReleaseMutex(&fidp->mx);
 
-        smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, 0);
-        outp->totalData = len + 4;     /* this is actually what we want to return */
+        smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
+        responseSize = len + 4;        /* this is actually what we want to return */
         qfi.u.QFfileNameInfo.fileNameLength = len;
     }
+    else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
+        size_t len = 0;
+
+        if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+            scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+            scp->fileType == CM_SCACHETYPE_INVALID) {
+            /* Do not return the alternate streams for directories */
+            responseSize = 0;
+        } else {
+            /* For now we have no alternate streams */
+            qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
+            qfi.u.QFfileStreamInfo.streamSize = scp->length;
+            qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
+            smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
+            qfi.u.QFfileStreamInfo.streamNameLength = len;
+            responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
+        }
+    }
+    outp->totalData = responseSize;
 
     /* send and free the packets */
   done:
@@ -3486,7 +4052,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     smb_FreeTran2Packet(outp);
 
     return 0;
-}       
+}
 
 
 /* TRANS2_SET_FILE_INFORMATION */
@@ -3501,27 +4067,22 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     cm_scache_t *scp = NULL;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = p->parmsp[0];
     fidp = smb_FindFID(vcp, fid, 0);
 
     if (fidp == NULL) {
+        osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
         return 0;
     }
 
-    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
-        smb_CloseFID(vcp, fidp, NULL, 0);
-        smb_ReleaseFID(fidp);
-        return 0;
-    }
-
     infoLevel = p->parmsp[1];
     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
-        osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+        osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         smb_ReleaseFID(fidp);
@@ -3529,19 +4090,27 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     }
 
     lock_ObtainMutex(&fidp->mx);
-    if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return 0;
+    }
+
+    if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
        !(fidp->flags & SMB_FID_OPENDELETE)) {
-       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
                  fidp, fidp->scp, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
         return 0;
     }
-    if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
+    if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
         infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
          && !(fidp->flags & SMB_FID_OPENWRITE)) {
-       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
                  fidp, fidp->scp, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
@@ -3564,7 +4133,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
        code = CM_ERROR_BADSMB;
        goto done;
-    }   
+    }
 
     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
         FILETIME lastMod;
@@ -3596,26 +4165,26 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         attr.mask = 0;
 
         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
-        /* when called as result of move a b, lastMod is (-1, -1). 
+        /* when called as result of move a b, lastMod is (-1, -1).
          * If the check for -1 is not present, timestamp
          * of the resulting file will be 1969 (-1)
          */
-        if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
+        if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
-            smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
+            cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
             fidp->flags |= SMB_FID_MTIMESETDONE;
         }
-               
+
         attribute = sfi->u.QFbasicInfo.attributes;
         if (attribute != 0) {
-            if ((scp->unixModeBits & 0222)
+            if ((scp->unixModeBits & 0200)
                  && (attribute & SMB_ATTR_READONLY) != 0) {
                 /* make a writable file read-only */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
                 attr.unixModeBits = scp->unixModeBits & ~0222;
             }
-            else if ((scp->unixModeBits & 0222) == 0
+            else if ((scp->unixModeBits & 0200) == 0
                       && (attribute & SMB_ATTR_READONLY) == 0) {
                 /* make a read-only file writable */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
@@ -3633,7 +4202,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     }
     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
        int delflag = *((char *)(p->datap));
-       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p", 
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
                 delflag, fidp, scp);
         if (*((char *)(p->datap))) {   /* File is Deleted */
             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
@@ -3643,17 +4212,17 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                 fidp->flags |= SMB_FID_DELONCLOSE;
                lock_ReleaseMutex(&fidp->mx);
            } else {
-               osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x", 
+               osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
                         fidp, scp, code);
            }
-       }               
-        else {  
+       }
+        else {
             code = 0;
            lock_ObtainMutex(&fidp->mx);
             fidp->flags &= ~SMB_FID_DELONCLOSE;
            lock_ReleaseMutex(&fidp->mx);
         }
-    }       
+    }
     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
             infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
@@ -3663,15 +4232,15 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         attr.length.LowPart = size.LowPart;
         attr.length.HighPart = size.HighPart;
         code = cm_SetAttr(scp, &attr, userp, &req);
-    }       
+    }
 
   done:
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
-    if (code == 0) 
+    if (code == 0)
         smb_SendTran2Packet(vcp, outp, opx);
-    else 
+    else
         smb_SendTran2Error(vcp, p, opx, code);
     smb_FreeTran2Packet(outp);
 
@@ -3679,7 +4248,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
 }
 
 /* TRANS2_FSCTL */
-long 
+long
 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
@@ -3687,7 +4256,7 @@ smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 }
 
 /* TRANS2_IOCTL2 */
-long 
+long
 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
@@ -3695,7 +4264,7 @@ smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 }
 
 /* TRANS2_FIND_NOTIFY_FIRST */
-long 
+long
 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
@@ -3703,7 +4272,7 @@ smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
 }
 
 /* TRANS2_FIND_NOTIFY_NEXT */
-long 
+long
 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
@@ -3711,7 +4280,7 @@ smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 }
 
 /* TRANS2_CREATE_DIRECTORY */
-long 
+long
 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
@@ -3719,7 +4288,7 @@ smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
 }
 
 /* TRANS2_SESSION_SETUP */
-long 
+long
 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
@@ -3737,7 +4306,7 @@ struct smb_v2_referral {
 };
 
 /* TRANS2_GET_DFS_REFERRAL */
-long 
+long
 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     /* This is a UNICODE only request (bit15 of Flags2) */
@@ -3752,8 +4321,8 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 #ifdef DFS_SUPPORT
     long code = 0;
     int maxReferralLevel = 0;
-    char requestFileName[1024] = "";
-    char referralPath[1024] = "";
+    clientchar_t requestFileName[1024] = _C("");
+    clientchar_t referralPath[1024] = _C("");
     smb_tran2Packet_t *outp = 0;
     cm_user_t *userp = 0;
     cm_scache_t *scp = 0;
@@ -3763,31 +4332,29 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     int i, nbnLen, reqLen, refLen;
     int idx;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     maxReferralLevel = p->parmsp[0];
 
     GetCPInfo(CP_ACP, &CodePageInfo);
-    WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1, 
-                        requestFileName, 1024, NULL, NULL);
+    cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
 
-    osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
-             maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
+    osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
+             maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
 
-    nbnLen = (int)strlen(cm_NetbiosName);
-    reqLen = (int)strlen(requestFileName);
+    nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
+    reqLen = (int)cm_ClientStrLen(requestFileName);
 
     if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
-        !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
-        requestFileName[nbnLen+1] == '\\') 
+        !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
+        requestFileName[nbnLen+1] == '\\')
     {
         int found = 0;
 
-        if (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
-             !_strnicmp("*.",&requestFileName[nbnLen+2],2)) 
-        {
+        if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
+            !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
             found = 1;
-            strcpy(referralPath, requestFileName);
+            cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
             refLen = reqLen;
         } else {
             userp = smb_GetTran2User(vcp, p);
@@ -3795,36 +4362,42 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
                 code = CM_ERROR_BADSMB;
                 goto done;
-            }   
+            }
 
-            /* 
-             * We have a requested path.  Check to see if it is something 
+            /*
+             * We have a requested path.  Check to see if it is something
              * we know about.
-                        *
-                        * But be careful because the name that we might be searching
-                        * for might be a known name with the final character stripped
-                        * off.  If we 
+             *
+             * But be careful because the name that we might be searching
+             * for might be a known name with the final character stripped
+             * off.
              */
-            code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
+            code = cm_NameI(cm_RootSCachep(userp, &req), &requestFileName[nbnLen+2],
                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
                             userp, NULL, &req, &scp);
-            if (code == 0) {
+            if (code == 0 ||
+                code == CM_ERROR_ALLDOWN ||
+                code == CM_ERROR_ALLBUSY ||
+                code == CM_ERROR_ALLOFFLINE ||
+                code == CM_ERROR_NOSUCHCELL ||
+                code == CM_ERROR_NOSUCHVOLUME ||
+                code == CM_ERROR_NOACCESS) {
                 /* Yes it is. */
                 found = 1;
-                strcpy(referralPath, requestFileName);
+                cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
                 refLen = reqLen;
             } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
-                char temp[1024];
-                char pathName[1024];
-                char *lastComponent;
-                /* 
+                clientchar_t temp[1024];
+                clientchar_t pathName[1024];
+                clientchar_t *lastComponent;
+                /*
                  * we have a msdfs link somewhere in the path
                  * we should figure out where in the path the link is.
                  * and return it.
                  */
-                osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%s]", requestFileName);
+                osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
 
-                strcpy(temp, &requestFileName[nbnLen+2]);
+                cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
 
                 do {
                     if (dscp) {
@@ -3835,9 +4408,10 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                         cm_ReleaseSCache(scp);
                         scp = 0;
                     }
+                    /* smb_StripLastComponent will strip "::$DATA" if present */
                     smb_StripLastComponent(pathName, &lastComponent, temp);
 
-                    code = cm_NameI(cm_data.rootSCachep, pathName,
+                    code = cm_NameI(cm_RootSCachep(userp, &req), pathName,
                                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                                     userp, NULL, &req, &dscp);
                     if (code == 0) {
@@ -3852,15 +4426,16 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 /* scp should now be the DfsLink we are looking for */
                 if (scp) {
                     /* figure out how much of the input path was used */
-                    reqLen = (int)(nbnLen+2 + strlen(pathName) + 1 + strlen(lastComponent));
+                    reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
 
-                    strcpy(referralPath, &scp->mountPointStringp[strlen("msdfs:")]);
-                    refLen = (int)strlen(referralPath);
+                    cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
+                                              referralPath, lengthof(referralPath));
+                    refLen = (int)cm_ClientStrLen(referralPath);
                     found = 1;
                 }
             } else {
-                char shareName[MAX_PATH + 1];
-                char *p, *q;
+                clientchar_t shareName[MAX_PATH + 1];
+                clientchar_t *p, *q;
                 /* we may have a sharename that is a volume reference */
 
                 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
@@ -3868,22 +4443,23 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                     *q = *p;
                 }
                 *q = '\0';
-                
+
                 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
-                    code = cm_NameI(cm_data.rootSCachep, "", 
+                    code = cm_NameI(cm_RootSCachep(userp, &req), _C(""),
                                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
                                     userp, p, &req, &scp);
                     free(p);
 
                     if (code == 0) {
                         found = 1;
-                        strcpy(referralPath, requestFileName);
+                        cm_ClientStrCpy(referralPath, lengthof(referralPath),
+                                        requestFileName);
                         refLen = reqLen;
                     }
                 }
             }
         }
-        
+
         if (found)
         {
             USHORT * sp;
@@ -3897,7 +4473,7 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             sp[idx++] = 0x03;     /* flags */
 #ifdef DFS_VERSION_1
             sp[idx++] = 1;        /* Version Number */
-            sp[idx++] = refLen + 4;  /* Referral Size */ 
+            sp[idx++] = refLen + 4;  /* Referral Size */
             sp[idx++] = 1;        /* Type = SMB Server */
             sp[idx++] = 0;        /* Do not strip path consumed */
             for ( i=0;i<=refLen; i++ )
@@ -3917,11 +4493,13 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             for ( i=0;i<=refLen; i++ )
                 sp[i+idx] = referralPath[i];
 #endif
-        } 
+        } else {
+            code = CM_ERROR_NOSUCHPATH;
+        }
     } else {
         code = CM_ERROR_NOSUCHPATH;
     }
-         
+
   done:
     if (dscp)
         cm_ReleaseSCache(dscp);
@@ -3929,29 +4507,29 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         cm_ReleaseSCache(scp);
     if (userp)
         cm_ReleaseUser(userp);
-    if (code == 0) 
+    if (code == 0)
         smb_SendTran2Packet(vcp, outp, op);
-    else 
+    else
         smb_SendTran2Error(vcp, p, op, code);
     if (outp)
         smb_FreeTran2Packet(outp);
+
     return 0;
 #else /* DFS_SUPPORT */
-    osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
+    osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
     return CM_ERROR_NOSUCHDEVICE;
 #endif /* DFS_SUPPORT */
 }
 
 /* TRANS2_REPORT_DFS_INCONSISTENCY */
-long 
+long
 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     /* This is a UNICODE only request (bit15 of Flags2) */
 
     /* There is nothing we can do about this operation.  The client is going to
      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
-     * Unfortunately, there is really nothing we can do about it other then log it 
+     * Unfortunately, there is really nothing we can do about it other then log it
      * somewhere.  Even then I don't think there is anything for us to do.
      * So let's return an error value.
      */
@@ -3960,11 +4538,10 @@ smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_
     return CM_ERROR_BADOP;
 }
 
-static long 
-smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp, 
-                          char * tidPathp, char * relPathp, 
-                          int infoLevel, cm_user_t *userp,
-                          cm_req_t *reqp)
+static long
+smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
+                          clientchar_t * tidPathp, clientchar_t * relPathp,
+                          int infoLevel, cm_user_t *userp, cm_req_t *reqp)
 {
     long code = 0;
     cm_scache_t *scp;
@@ -3977,40 +4554,132 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
     smb_dirListPatch_t *npatchp;
     afs_uint32 rights;
     afs_int32 mustFake = 0;
-    char path[AFSPATHMAX];
+    clientchar_t path[AFSPATHMAX];
 
+    lock_ObtainWrite(&dscp->rw);
     code = cm_FindACLCache(dscp, userp, &rights);
-    if (code == 0 && !(rights & PRSFS_READ))
-        mustFake = 1;
-    else if (code == -1) {
-        lock_ObtainWrite(&dscp->rw);
+    if (code == -1) {
         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        lock_ReleaseWrite(&dscp->rw);
+        if (code == 0)
+            cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         if (code == CM_ERROR_NOACCESS) {
             mustFake = 1;
             code = 0;
         }
     }
+    lock_ReleaseWrite(&dscp->rw);
     if (code)
-        return code;
+        goto cleanup;
+
+    if (!mustFake) {    /* Bulk Stat */
+        afs_uint32 count;
+        cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
+
+        memset(bsp, 0, sizeof(cm_bulkStat_t));
+
+        for (patchp = *dirPatchespp, count=0;
+             patchp;
+             patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+            cm_scache_t *tscp = NULL;
+            int i;
 
-    for(patchp = *dirPatchespp; patchp; patchp =
-         (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
-        snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
+            /* Do not look for a cm_scache_t or bulkstat an ioctl entry */
+            if (patchp->flags & SMB_DIRLISTPATCH_IOCTL)
+                continue;
+
+            code = cm_GetSCache(&patchp->fid, &dscp->fid, &tscp, userp, reqp);
+            if (code == 0) {
+                if (lock_TryWrite(&tscp->rw)) {
+                    /* we have an entry that we can look at */
+#ifdef AFS_FREELANCE_CLIENT
+                    if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
+                        code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
+                                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+                        if (code == 0)
+                            cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+                        lock_ReleaseWrite(&tscp->rw);
+                        cm_ReleaseSCache(tscp);
+                        continue;
+                    }
+#endif /* AFS_FREELANCE_CLIENT */
+                    if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+                        /* we have a callback on it.  Don't bother
+                        * fetching this stat entry, since we're happy
+                        * with the info we have.
+                        */
+                        lock_ReleaseWrite(&tscp->rw);
+                        cm_ReleaseSCache(tscp);
+                        continue;
+                    }
+                    lock_ReleaseWrite(&tscp->rw);
+                } /* got lock */
+                cm_ReleaseSCache(tscp);
+            }  /* found entry */
+
+            i = bsp->counter++;
+            bsp->fids[i].Volume = patchp->fid.volume;
+            bsp->fids[i].Vnode = patchp->fid.vnode;
+            bsp->fids[i].Unique = patchp->fid.unique;
+
+            if (bsp->counter == AFSCBMAX) {
+                code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+                memset(bsp, 0, sizeof(cm_bulkStat_t));
+            }
+        }
+
+        if (bsp->counter > 0)
+            code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+
+        free(bsp);
+    }
+
+    for( patchp = *dirPatchespp;
+         patchp;
+         patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+        cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
+                            relPathp ? relPathp : _C(""), patchp->dep->name);
         reqp->relPathp = path;
         reqp->tidPathp = tidPathp;
 
-        code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
+        if (patchp->flags & SMB_DIRLISTPATCH_IOCTL) {
+            /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
+               errors in the client. */
+            if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+                smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
+
+                /* 1969-12-31 23:59:59 +00 */
+                ft.dwHighDateTime = 0x19DB200;
+                ft.dwLowDateTime = 0x5BB78980;
+
+                /* copy to Creation Time */
+                fa->creationTime = ft;
+                fa->lastAccessTime = ft;
+                fa->lastWriteTime = ft;
+                fa->lastChangeTime = ft;
+                fa->extFileAttributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
+            } else {
+                smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+
+                /* 1969-12-31 23:59:58 +00*/
+                dosTime = 0xEBBFBF7D;
+
+                fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
+                fa->lastAccessDateTime = fa->creationDateTime;
+                fa->lastWriteDateTime = fa->creationDateTime;
+                fa->attributes = SMB_ATTR_SYSTEM|SMB_ATTR_HIDDEN;
+            }
+            continue;
+        }
+
+        code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
         reqp->relPathp = reqp->tidPathp = NULL;
-        if (code) 
+        if (code)
             continue;
 
         lock_ObtainWrite(&scp->rw);
-        if (mustFake == 0)
-            code = cm_SyncOp(scp, NULL, userp, reqp, 0,
-                             CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        if (mustFake || code) { 
+        if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
             lock_ReleaseWrite(&scp->rw);
 
             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
@@ -4031,23 +4700,27 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                 switch (scp->fileType) {
                 case CM_SCACHETYPE_DIRECTORY:
                 case CM_SCACHETYPE_MOUNTPOINT:
-                case CM_SCACHETYPE_SYMLINK:
                 case CM_SCACHETYPE_INVALID:
                     fa->extFileAttributes = SMB_ATTR_DIRECTORY;
                     break;
+                case CM_SCACHETYPE_SYMLINK:
+                    if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+                        fa->extFileAttributes = SMB_ATTR_DIRECTORY;
+                    else
+                        fa->extFileAttributes = SMB_ATTR_NORMAL;
+                    break;
                 default:
                     /* if we get here we either have a normal file
-                     * or we have a file for which we have never 
+                     * or we have a file for which we have never
                      * received status info.  In this case, we can
                      * check the even/odd value of the entry's vnode.
-                     * even means it is to be treated as a directory
-                     * and odd means it is to be treated as a file.
+                     * odd means it is to be treated as a directory
+                     * and even means it is to be treated as a file.
                      */
                     if (mustFake && (scp->fid.vnode & 0x1))
                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
                     else
                         fa->extFileAttributes = SMB_ATTR_NORMAL;
-                        
                 }
                 /* merge in hidden attribute */
                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
@@ -4067,29 +4740,45 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                 switch (scp->fileType) {
                 case CM_SCACHETYPE_DIRECTORY:
                 case CM_SCACHETYPE_MOUNTPOINT:
-                case CM_SCACHETYPE_SYMLINK:
                 case CM_SCACHETYPE_INVALID:
                     fa->attributes = SMB_ATTR_DIRECTORY;
+                    break;
+                case CM_SCACHETYPE_SYMLINK:
+                    if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+                        fa->attributes = SMB_ATTR_DIRECTORY;
+                    else
+                        fa->attributes = SMB_ATTR_NORMAL;
+                    break;
                 default:
-                    fa->attributes = SMB_ATTR_NORMAL;
+                    /* if we get here we either have a normal file
+                     * or we have a file for which we have never
+                     * received status info.  In this case, we can
+                     * check the even/odd value of the entry's vnode.
+                     * even means it is to be treated as a directory
+                     * and odd means it is to be treated as a file.
+                     */
+                    if (mustFake && (scp->fid.vnode & 0x1))
+                        fa->attributes = SMB_ATTR_DIRECTORY;
+                    else
+                        fa->attributes = SMB_ATTR_NORMAL;
                 }
+
                 /* merge in hidden (dot file) attribute */
                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
                     fa->attributes |= SMB_ATTR_HIDDEN;
-                }       
+                }
             }
-            
+
             cm_ReleaseSCache(scp);
             continue;
         }
-        
-       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
         /* now watch for a symlink */
         code = 0;
         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
             lock_ReleaseWrite(&scp->rw);
-            snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
+            cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
+                                relPathp ? relPathp : _C(""), patchp->dep->name);
             reqp->relPathp = path;
             reqp->tidPathp = tidPathp;
             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
@@ -4113,7 +4802,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
             smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
 
             /* get filetime */
-            smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+            cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
 
             fa->creationTime = ft;
             fa->lastAccessTime = ft;
@@ -4126,7 +4815,9 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
 
             /* Copy attributes */
             lattr = smb_ExtAttributes(scp);
-            if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
+            if ((code == CM_ERROR_NOSUCHPATH &&
+                (scp->fileType == CM_SCACHETYPE_SYMLINK &&
+                cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
                 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
                 if (lattr == SMB_ATTR_NORMAL)
                     lattr = SMB_ATTR_DIRECTORY;
@@ -4146,7 +4837,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
             smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
 
             /* get dos time */
-            smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+            cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
 
             fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
             fa->lastAccessDateTime = fa->creationDateTime;
@@ -4173,159 +4864,36 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
         lock_ReleaseRead(&scp->rw);
         cm_ReleaseSCache(scp);
     }
-        
+
     /* now free the patches */
     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
         free(patchp);
     }
-        
+
     /* and mark the list as empty */
     *dirPatchespp = NULL;
 
+  cleanup:
     return code;
 }
 
-// char table for case insensitive comparison
-char mapCaseTable[256];
+/* smb_ReceiveTran2SearchDir implements both
+ * Tran2_Find_First and Tran2_Find_Next
+ */
+#define TRAN2_FIND_FLAG_CLOSE_SEARCH           0x01
+#define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END    0x02
+#define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS     0x04
+#define TRAN2_FIND_FLAG_CONTINUE_SEARCH                0x08
+#define TRAN2_FIND_FLAG_BACKUP_INTENT          0x10
 
-VOID initUpperCaseTable(VOID) 
-{
-    int i;
-    for (i = 0; i < 256; ++i) 
-       mapCaseTable[i] = toupper(i);
-    // make '"' match '.' 
-    mapCaseTable[(int)'"'] = toupper('.');
-    // make '<' match '*' 
-    mapCaseTable[(int)'<'] = toupper('*');
-    // make '>' match '?' 
-    mapCaseTable[(int)'>'] = toupper('?');    
-}
+/* this is an optimized handler for T2SearchDir that handles the case
+   where there are no wildcards in the search path.  I.e. an
+   application is using FindFirst(Ex) to get information about a
+   single file or directory.  It will attempt to do a single lookup.
+   If that fails, then smb_ReceiveTran2SearchDir() will fall back to
+   the usual mechanism.
 
-// Compare 'pattern' (containing metacharacters '*' and '?') with the file
-// name 'name'.
-// Note : this procedure works recursively calling itself.
-// Parameters
-// PSZ pattern    : string containing metacharacters.
-// PSZ name       : file name to be compared with 'pattern'.
-// Return value
-// BOOL : TRUE/FALSE (match/mistmatch)
-
-BOOL 
-szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
-{
-    PSZ pename;         // points to the last 'name' character
-    PSZ p;
-    pename = name + strlen(name) - 1;
-    while (*name) {
-        switch (*pattern) {
-        case '?':
-           ++pattern;
-            if (*name == '.')
-               continue;
-            ++name;
-            break;
-         case '*':
-            ++pattern;
-            if (*pattern == '\0')
-                return TRUE;
-            for (p = pename; p >= name; --p) {
-                if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
-                     !casefold && (*p == *pattern)) &&
-                     szWildCardMatchFileName(pattern + 1, p + 1, casefold))
-                    return TRUE;
-            } /* endfor */
-            return FALSE;
-        default:
-            if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
-                (!casefold && *name != *pattern))
-                return FALSE;
-            ++pattern, ++name;
-            break;
-        } /* endswitch */
-    } /* endwhile */ 
-
-    /* if all we have left are wildcards, then we match */
-    for (;*pattern; pattern++) {
-       if (*pattern != '*' && *pattern != '?')
-           return FALSE;
-    }
-    return TRUE;
-}
-
-/* do a case-folding search of the star name mask with the name in namep.
- * Return 1 if we match, otherwise 0.
- */
-int smb_V3MatchMask(char *namep, char *maskp, int flags) 
-{
-    char * newmask;
-    int    i, j, star, qmark, casefold, retval;
-
-    /* make sure we only match 8.3 names, if requested */
-    if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
-        return 0;
-    
-    casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
-
-    /* optimize the pattern:
-     * if there is a mixture of '?' and '*',
-     * for example  the sequence "*?*?*?*"
-     * must be turned into the form "*"
-     */
-    newmask = (char *)malloc(strlen(maskp)+1);
-    for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
-        switch ( maskp[i] ) {
-        case '?':
-        case '>':
-            qmark++;
-            break;
-        case '<':
-        case '*':
-            star++;
-            break;
-        default:
-            if ( star ) {
-                newmask[j++] = '*';
-            } else if ( qmark ) {
-                while ( qmark-- )
-                    newmask[j++] = '?';
-            }
-            newmask[j++] = maskp[i];
-            star = 0;
-            qmark = 0;
-        }
-    }
-    if ( star ) {
-        newmask[j++] = '*';
-    } else if ( qmark ) {
-        while ( qmark-- )
-            newmask[j++] = '?';
-    }
-    newmask[j++] = '\0';
-
-    retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
-
-    free(newmask);
-    return retval;
-}
-
-
-/* smb_ReceiveTran2SearchDir implements both 
- * Tran2_Find_First and Tran2_Find_Next
- */
-#define TRAN2_FIND_FLAG_CLOSE_SEARCH           0x01
-#define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END    0x02
-#define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS     0x04
-#define TRAN2_FIND_FLAG_CONTINUE_SEARCH                0x08
-#define TRAN2_FIND_FLAG_BACKUP_INTENT          0x10
-
-/* this is an optimized handler for T2SearchDir that handles the case
-   where there are no wildcards in the search path.  I.e. an
-   application is using FindFirst(Ex) to get information about a
-   single file or directory.  It will attempt to do a single lookup.
-   If that fails, then smb_ReceiveTran2SearchDir() will fall back to
-   the usual mechanism. 
-   
    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
 
    TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
@@ -4335,7 +4903,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     int attribute;
     long nextCookie;
     long code = 0, code2 = 0;
-    char *pathp = 0;
+    clientchar_t *pathp = 0;
     int maxCount;
     smb_dirListPatch_t *dirListPatchesp;
     smb_dirListPatch_t *curPatchp;
@@ -4343,7 +4911,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     size_t ohbytes;                    /* # of bytes, except file name */
     size_t onbytes;                    /* # of bytes in name, incl. term. null */
     cm_scache_t *scp = NULL;
-    cm_scache_t *targetscp = NULL;
+    cm_scache_t *targetScp = NULL;
     cm_user_t *userp = NULL;
     char *op;                          /* output data ptr */
     char *origOp;                      /* original value of op */
@@ -4351,23 +4919,25 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     unsigned long maxReturnData;       /* max # of return data */
     long maxReturnParms;               /* max # of return parms */
     long bytesInBuffer;                        /* # data bytes in the output buffer */
-    char *maskp;                       /* mask part of path */
+    clientchar_t *maskp;                       /* mask part of path */
     int infoLevel;
     int searchFlags;
     int eos;
     smb_tran2Packet_t *outp;           /* response packet */
-    char *tidPathp = 0;
+    clientchar_t *tidPathp = 0;
     int align;
-    char shortName[13];                        /* 8.3 name if needed */
+    clientchar_t shortName[13];                /* 8.3 name if needed */
     int NeedShortName;
-    char *shortNameEnd;
+    clientchar_t *shortNameEnd;
     cm_dirEntry_t * dep = NULL;
     cm_req_t req;
     char * s;
     void * attrp = NULL;
     smb_tran2Find_t * fp;
+    int afs_ioctl = 0;                  /* is this query for _._AFS_IOCTL_._? */
+    cm_dirFid_t dfid;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     eos = 0;
     osi_assertx(p->opcode == 1, "invalid opcode");
@@ -4383,16 +4953,16 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     searchFlags = p->parmsp[2];
     pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
     nextCookie = 0;
-    maskp = strrchr(pathp, '\\');
-    if (maskp == NULL) 
+    maskp = cm_ClientStrRChr(pathp,  '\\');
+    if (maskp == NULL)
        maskp = pathp;
-    else 
+    else
        maskp++;        /* skip over backslash */
     /* track if this is likely to match a lot of entries */
 
-    osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
-            osi_LogSaveString(smb_logp, pathp),
-            osi_LogSaveString(smb_logp, maskp));
+    osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
+             osi_LogSaveClientString(smb_logp, pathp),
+             osi_LogSaveClientString(smb_logp, maskp));
 
     switch ( infoLevel ) {
     case SMB_INFO_STANDARD:
@@ -4440,7 +5010,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     osi_Log4(smb_logp,
              "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
              attribute, infoLevel, maxCount, searchFlags);
-    
+
     if (ohbytes == 0) {
         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
         return CM_ERROR_INVAL;
@@ -4458,23 +5028,18 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     maxReturnParms = 10;       /* return params for findfirst, which
                                    is the only one we handle.*/
 
-#ifndef CM_CONFIG_MULTITRAN2RESPONSES
-    if (maxReturnData > 6000) 
-        maxReturnData = 6000;
-#endif /* CM_CONFIG_MULTITRAN2RESPONSES */
-
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                       maxReturnData);
 
-    osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
-             maxCount, osi_LogSaveString(smb_logp, pathp));
-        
+    osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
+             maxCount, osi_LogSaveClientString(smb_logp, pathp));
+
     /* bail out if request looks bad */
     if (!pathp) {
         smb_FreeTran2Packet(outp);
         return CM_ERROR_BADSMB;
     }
-        
+
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
        osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
@@ -4484,7 +5049,8 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
     /* try to get the vnode for the path name next */
     spacep = cm_GetSpace();
-    smb_StripLastComponent(spacep->data, NULL, pathp);
+    /* smb_StripLastComponent will strip "::$DATA" if present */
+    smb_StripLastComponent(spacep->wdata, NULL, pathp);
     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
     if (code) {
         cm_ReleaseUser(userp);
@@ -4493,7 +5059,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
         return 0;
     }
 
-    code = cm_NameI(cm_data.rootSCachep, spacep->data,
+    code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                     userp, tidPathp, &req, &scp);
     cm_FreeSpace(spacep);
@@ -4513,7 +5079,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
         if ( WANTS_DFS_PATHNAMES(p) || pnc )
            code = CM_ERROR_PATH_NOT_COVERED;
        else
-           code = CM_ERROR_BADSHARENAME;
+           code = CM_ERROR_NOSUCHPATH;
        smb_SendTran2Error(vcp, p, opx, code);
        smb_FreeTran2Packet(outp);
        return 0;
@@ -4521,32 +5087,43 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 #endif /* DFS_SUPPORT */
     osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
 
-    /* now do a single case sensitive lookup for the file in question */
-    code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
+    afs_ioctl = (cm_ClientStrCmpI(maskp, CM_IOCTL_FILENAME_NOSLASH_W) == 0);
 
-    /* if a case sensitive match failed, we try a case insensitive one
-       next. */
-    if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
-        code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
-    }
+    /*
+     * If we are not searching for _._AFS_IOCTL_._, then we need to obtain
+     * the target scp.
+     */
+    if (!afs_ioctl) {
+        /* now do a single case sensitive lookup for the file in question */
+        code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetScp);
 
-    if (code == 0 && targetscp->fid.vnode == 0) {
-        cm_ReleaseSCache(targetscp);
-        code = CM_ERROR_NOSUCHFILE;
-    }
+        /*
+         * if a case sensitive match failed, we try a case insensitive
+         * one next.
+         */
+        if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
+            code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetScp);
 
-    if (code) {
-        /* if we can't find the directory entry, this block will
-           return CM_ERROR_NOSUCHFILE, which we will pass on to
-           smb_ReceiveTran2SearchDir(). */
-        cm_ReleaseSCache(scp);
-        cm_ReleaseUser(userp);
-       if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
-           smb_SendTran2Error(vcp, p, opx, code);
-           code = 0;
-       }
-       smb_FreeTran2Packet(outp);
-        return code;
+        if (code == 0 && targetScp->fid.vnode == 0) {
+            cm_ReleaseSCache(targetScp);
+            code = CM_ERROR_NOSUCHFILE;
+        }
+
+        if (code) {
+            /*
+             * if we can't find the directory entry, this block will
+             * return CM_ERROR_NOSUCHFILE, which we will pass on to
+             * smb_ReceiveTran2SearchDir().
+             */
+            cm_ReleaseSCache(scp);
+            cm_ReleaseUser(userp);
+            if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
+                smb_SendTran2Error(vcp, p, opx, code);
+                code = 0;
+            }
+            smb_FreeTran2Packet(outp);
+            return code;
+        }
     }
 
     /* now that we have the target in sight, we proceed with filling
@@ -4563,24 +5140,32 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     fp = (smb_tran2Find_t *) op;
 
     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
-        && targetscp->fid.vnode != 0
         && !cm_Is8Dot3(maskp)) {
 
-        cm_dirFid_t dfid;
-        dfid.vnode = htonl(targetscp->fid.vnode);
-        dfid.unique = htonl(targetscp->fid.unique);
+        /*
+         * Since the _._AFS_IOCTL_._ file does not actually exist
+         * we will make up a per directory FID equivalent to the
+         * directory vnode and the uniqifier 0.
+         */
+        if (afs_ioctl) {
+            dfid.vnode = htonl(scp->fid.vnode);
+            dfid.unique = htonl(0);
+        } else {
+            dfid.vnode = htonl(targetScp->fid.vnode);
+            dfid.unique = htonl(targetScp->fid.unique);
+        }
 
-        cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
+        cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
         NeedShortName = 1;
     } else {
         NeedShortName = 0;
     }
 
-    osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
-             htonl(targetscp->fid.vnode),
-             htonl(targetscp->fid.unique),
-             osi_LogSaveString(smb_logp, pathp),
-             NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
+    osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
+             ntohl(dfid.vnode),
+             ntohl(dfid.unique),
+             osi_LogSaveClientString(smb_logp, pathp),
+             (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
 
     /* Eliminate entries that don't match requested attributes */
     if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
@@ -4593,10 +5178,11 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     }
 
     if (!(attribute & SMB_ATTR_DIRECTORY) &&
-        (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
-         targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
-         targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
-         targetscp->fileType == CM_SCACHETYPE_INVALID)) {
+        !afs_ioctl &&
+        (targetScp->fileType == CM_SCACHETYPE_DIRECTORY ||
+         targetScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+         targetScp->fileType == CM_SCACHETYPE_DFSLINK ||
+         targetScp->fileType == CM_SCACHETYPE_INVALID)) {
 
         code = CM_ERROR_NOSUCHFILE;
         osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
@@ -4606,7 +5192,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
     /* add header to name & term. null */
     onbytes = 0;
-    smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH);
+    smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
     orbytes = ohbytes + onbytes;
 
     /* now, we round up the record to a 4 byte alignment, and we make
@@ -4638,7 +5224,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     memset(origOp, 0, orbytes);
 
     onbytes = 0;
-    smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH);
+    smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
 
     switch (infoLevel) {
     case SMB_INFO_STANDARD:
@@ -4663,19 +5249,18 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 #ifdef SMB_UNICODE
             int nchars;
 
-            nchars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
-                                         shortName, -1,
-                                         fp->u.FfileBothDirectoryInfo.shortName,
-                                         sizeof(fp->u.FfileBothDirectoryInfo.shortName) / sizeof(wchar_t));
+            nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
+                                            fp->u.FfileBothDirectoryInfo.shortName,
+                                            sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
             if (nchars > 0)
-                fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
+                fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
             else
                 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
             fp->u.FfileBothDirectoryInfo.reserved = 0;
 #else
             strcpy(fp->u.FfileBothDirectoryInfo.shortName,
                    shortName);
-            fp->u.FfileBothDirectoryInfo.shortNameLength = strlen(shortName);
+            fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
 #endif
     }
         /* Fallthrough */
@@ -4716,15 +5301,26 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
             curPatchp->flags = 0;
         }
 
-        cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
-
         /* temp */
-        dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+strlen(maskp));
-        strcpy(dep->name, maskp);
-        dep->fid.vnode = targetscp->fid.vnode;
-        dep->fid.unique = targetscp->fid.unique;
+        {
+            int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
+            dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
+            cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
+        }
+
+        if (afs_ioctl) {
+            cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, scp->fid.vnode, 0);
+            dep->fid.vnode = scp->fid.vnode;
+            dep->fid.unique = 0;
+            curPatchp->flags |= SMB_DIRLISTPATCH_IOCTL;
+        } else {
+            cm_SetFid(&curPatchp->fid, targetScp->fid.cell, targetScp->fid.volume, targetScp->fid.vnode, targetScp->fid.unique);
+            dep->fid.vnode = targetScp->fid.vnode;
+            dep->fid.unique = targetScp->fid.unique;
+        }
+
         curPatchp->dep = dep;
-    }   
+    }
 
     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
         /* put out resume key */
@@ -4742,7 +5338,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     }
 
     /* apply the patches */
-    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->data, infoLevel, userp, &req);
+    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
 
     outp->parmsp[0] = 0;
     outp->parmsp[1] = 1;        /* number of names returned */
@@ -4769,8 +5365,9 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     if (dep)
         free(dep);
     if (scp)
-    cm_ReleaseSCache(scp);
-    cm_ReleaseSCache(targetscp);
+        cm_ReleaseSCache(scp);
+    if (targetScp)
+        cm_ReleaseSCache(targetScp);
     cm_ReleaseUser(userp);
 
     return code;
@@ -4784,7 +5381,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     long nextCookie;
     char *tp;
     long code = 0, code2 = 0;
-    char *pathp;
+    clientchar_t *pathp;
     cm_dirEntry_t *dep = 0;
     int maxCount;
     smb_dirListPatch_t *dirListPatchesp = 0;
@@ -4815,17 +5412,17 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     unsigned long maxReturnParms;              /* max # of return parms */
     long bytesInBuffer;                /* # data bytes in the output buffer */
     int starPattern;
-    char *maskp;                       /* mask part of path */
+    clientchar_t *maskp;                       /* mask part of path */
     int infoLevel;
     int searchFlags;
     int eos;
     smb_tran2Packet_t *outp;   /* response packet */
-    char *tidPathp;
+    clientchar_t *tidPathp;
     unsigned int align;
-    char shortName[13];                /* 8.3 name if needed */
+    clientchar_t shortName[13];                /* 8.3 name if needed */
     int NeedShortName;
     int foundInexact;
-    char *shortNameEnd;
+    clientchar_t *shortNameEnd;
     int fileType;
     cm_fid_t fid;
     cm_req_t req;
@@ -4833,7 +5430,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     char * s;
     smb_tran2Find_t * fp;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     eos = 0;
     if (p->opcode == 1) {
@@ -4844,10 +5441,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         searchFlags = p->parmsp[2];
         pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
         nextCookie = 0;
-        maskp = strrchr(pathp, '\\');
-        if (maskp == NULL) 
+        maskp = cm_ClientStrRChr(pathp,  '\\');
+        if (maskp == NULL)
             maskp = pathp;
-        else 
+        else
             maskp++;   /* skip over backslash */
 
         /* track if this is likely to match a lot of entries */
@@ -4856,7 +5453,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 #ifndef NOFINDFIRSTOPTIMIZE
         if (!starPattern) {
             /* if this is for a single directory or file, we let the
-               optimized routine handle it.  The only error it 
+               optimized routine handle it.  The only error it
               returns is CM_ERROR_NOSUCHFILE.  The  */
             code = smb_T2SearchDirSingle(vcp, p, opx);
 
@@ -4875,7 +5472,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
         dsp = smb_NewDirSearch(1);
         dsp->attribute = attribute;
-        strcpy(dsp->mask, maskp);      /* and save mask */
+        cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask),  maskp);       /* and save mask */
     }
     else {
         osi_assertx(p->opcode == 2, "invalid opcode");
@@ -4963,27 +5560,25 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     maxReturnData = p->maxReturnData;
     if (p->opcode == 1)        /* find first */
         maxReturnParms = 10;   /* bytes */
-    else    
+    else
         maxReturnParms = 8;    /* bytes */
 
-#ifndef CM_CONFIG_MULTITRAN2RESPONSES
-    if (maxReturnData > 6000) 
-        maxReturnData = 6000;
-#endif /* CM_CONFIG_MULTITRAN2RESPONSES */
-
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                       maxReturnData);
 
-    osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
-             maxCount, osi_LogSaveString(smb_logp, pathp));
-        
+    if (maxCount > 500)
+        maxCount = 500;
+
+    osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
+             maxCount, osi_LogSaveClientString(smb_logp, pathp));
+
     /* bail out if request looks bad */
     if (p->opcode == 1 && !pathp) {
         smb_ReleaseDirSearch(dsp);
         smb_FreeTran2Packet(outp);
         return CM_ERROR_BADSMB;
     }
-        
+
     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
              dsp->cookie, nextCookie, attribute);
 
@@ -5004,7 +5599,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         code = 0;
     } else {
         spacep = cm_GetSpace();
-        smb_StripLastComponent(spacep->data, NULL, pathp);
+        /* smb_StripLastComponent will strip "::$DATA" if present */
+        smb_StripLastComponent(spacep->wdata, NULL, pathp);
         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
         if (code) {
             cm_ReleaseUser(userp);
@@ -5016,10 +5612,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             return 0;
         }
 
-        strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
-        strcpy(dsp->relPath, spacep->data);
+        cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
+        cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
 
-        code = cm_NameI(cm_data.rootSCachep, spacep->data,
+        code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &scp);
         cm_FreeSpace(spacep);
@@ -5033,7 +5629,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 if ( WANTS_DFS_PATHNAMES(p) || pnc )
                     code = CM_ERROR_PATH_NOT_COVERED;
                 else
-                    code = CM_ERROR_BADSHARENAME;
+                    code = CM_ERROR_NOSUCHPATH;
                 smb_SendTran2Error(vcp, p, opx, code);
                 smb_FreeTran2Packet(outp);
                 lock_ReleaseMutex(&dsp->mx);
@@ -5051,14 +5647,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
              * and so we do another hold now.
              */
             cm_HoldSCache(scp);
-            lock_ObtainWrite(&scp->rw);
-            if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
-                 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
-                scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
-                dsp->flags |= SMB_DIRSEARCH_BULKST;
-            }
-            lock_ReleaseWrite(&scp->rw);
-        } 
+            dsp->flags |= SMB_DIRSEARCH_BULKST;
+        }
     }
     lock_ReleaseMutex(&dsp->mx);
     if (code) {
@@ -5098,6 +5688,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     returnedNames = 0;
     bytesInBuffer = 0;
     while (1) {
+        normchar_t normName[MAX_PATH]; /* Normalized name */
+        clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
+
         op = origOp;
         if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
             /* skip over resume key */
@@ -5120,10 +5713,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             /* we're in a later dir page */
             if (temp < 32) temp = 32;
         }
-               
+
         /* make sure the low order 5 bits are zero */
         temp &= ~(32-1);
-                
+
         /* now put temp bits back ito curOffset.LowPart */
         curOffset.LowPart &= ~(2048-1);
         curOffset.LowPart |= temp;
@@ -5146,6 +5739,22 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             break;
         }
 
+        /* when we have obtained as many entries as can be processed in
+         * a single Bulk Status call to the file server, apply the dir listing
+         * patches.
+         */
+        if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
+            lock_ReleaseWrite(&scp->rw);
+            code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
+                                               dsp->relPath, infoLevel, userp, &req);
+            lock_ObtainWrite(&scp->rw);
+        }
+        /* Then check to see if we have time left to process more entries */
+        if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
+            osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
+            break;
+        }
+
         /* see if we can use the bufferp we have now; compute in which
          * page the current offset would be, and check whether that's
          * the offset of the buffer we have.  If not, get the buffer.
@@ -5157,33 +5766,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             if (bufferp) {
                 buf_Release(bufferp);
                 bufferp = NULL;
-            }       
-            lock_ReleaseWrite(&scp->rw);
-            code = buf_Get(scp, &thyper, &bufferp);
-            lock_ObtainMutex(&dsp->mx);
-
-            /* now, if we're doing a star match, do bulk fetching
-             * of all of the status info for files in the dir.
-             */
-            if (starPattern) {
-                code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, infoLevel, userp, &req);
-                
-                lock_ObtainWrite(&scp->rw);
-                if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
-                    LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
-                    /* Don't bulk stat if risking timeout */
-                    DWORD now = GetTickCount();
-                    if (now - req.startTime > RDRtimeout * 1000) {
-                        scp->bulkStatProgress = thyper;
-                        scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
-                        dsp->flags &= ~SMB_DIRSEARCH_BULKST;
-                    } else
-                        code = cm_TryBulkStat(scp, &thyper, userp, &req);
-                }
-            } else {
-                lock_ObtainWrite(&scp->rw);
             }
-            lock_ReleaseMutex(&dsp->mx);
+            lock_ReleaseWrite(&scp->rw);
+            code = buf_Get(scp, &thyper, &req, &bufferp);
+            lock_ObtainWrite(&scp->rw);
             if (code) {
                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
                 break;
@@ -5201,19 +5787,19 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
                     break;
                 }
-                       
-               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
 
                 if (cm_HaveBuffer(scp, bufferp, 0)) {
                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
+                    cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
                     break;
                 }
 
                 /* otherwise, load the buffer and try again */
                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
                                     &req);
+               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
                 if (code) {
-                    osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
+                    osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
                               scp, bufferp, code);
                     break;
                 }
@@ -5224,7 +5810,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 break;
             }
         }      /* if (wrong buffer) ... */
-                
+
         /* now we have the buffer containing the entry we're interested
          * in; copy it out if it represents a non-deleted entry.
          */
@@ -5263,43 +5849,52 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
          * XXXX Probably should do more sanity checking.
          */
         numDirChunks = cm_NameEntries(dep->name, &onbytes);
-               
+
         /* compute offset of cookie representing next entry */
         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
 
-        if (dep->fid.vnode == 0) 
+        if (dep->fid.vnode == 0)
             goto nextEntry;             /* This entry is not in use */
 
+        if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
+            cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
+
+            osi_Log1(smb_logp, "Skipping entry [%s].  Can't convert or normalize FS String",
+                     osi_LogSaveString(smb_logp, dep->name));
+            goto nextEntry;
+        }
+
         /* Need 8.3 name? */
         NeedShortName = 0;
-        if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO && 
-             !cm_Is8Dot3(dep->name)) {
+        if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
+            !cm_Is8Dot3(cfileName)) {
             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
             NeedShortName = 1;
         }
 
-        osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
-                  dep->fid.vnode, dep->fid.unique, 
-                  osi_LogSaveString(smb_logp, dep->name),
-                  NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
+        osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
+                 dep->fid.vnode, dep->fid.unique,
+                 osi_LogSaveClientString(smb_logp, cfileName),
+                 NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
 
         /* When matching, we are using doing a case fold if we have a wildcard mask.
-         * If we get a non-wildcard match, it's a lookup for a specific file. 
+         * If we get a non-wildcard match, it's a lookup for a specific file.
          */
-        if (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
-             (NeedShortName && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD))) 
+        if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
+            (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
         {
             /* Eliminate entries that don't match requested attributes */
-            if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
-                 smb_IsDotFile(dep->name)) {
+            if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
+                smb_IsDotFile(cfileName)) {
                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
                 goto nextEntry; /* no hidden files */
             }
-        
+
             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
             {
                 /* We have already done the cm_TryBulkStat above */
-                cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
+                cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
+                          ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
                 fileType = cm_FindFileType(&fid);
                 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
                  * "has filetype %d", dep->name, fileType);
@@ -5314,7 +5909,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
             /* finally check if this name will fit */
             onbytes = 0;
-            smb_UnparseString(opx, NULL, dep->name, &onbytes, SMB_STRF_ANSIPATH);
+            smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
             orbytes = ohbytes + onbytes;
 
             /* now, we round up the record to a 4 byte alignment,
@@ -5330,9 +5925,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
             if (orbytes + bytesInBuffer + align > maxReturnData) {
                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
-                          maxReturnData);
-                break;      
-            }       
+                         maxReturnData);
+                break;
+            }
 
             /* this is one of the entries to use: it is not deleted
              * and it matches the star pattern we're looking for.
@@ -5342,7 +5937,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             memset(origOp, 0, orbytes);
 
             onbytes = 0;
-            smb_UnparseString(opx, origOp + ohbytes, dep->name, &onbytes, SMB_STRF_ANSIPATH);
+            smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
 
             switch (infoLevel) {
             case SMB_INFO_STANDARD:
@@ -5367,19 +5962,19 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 #ifdef SMB_UNICODE
                     int nchars;
 
-                    nchars = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
-                                                 shortName, -1,
-                                                 fp->u.FfileBothDirectoryInfo.shortName,
-                                                 sizeof(fp->u.FfileBothDirectoryInfo.shortName) / sizeof(wchar_t));
+                    nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
+                                                    fp->u.FfileBothDirectoryInfo.shortName,
+                                                    sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
                     if (nchars > 0)
-                        fp->u.FfileBothDirectoryInfo.shortNameLength = (nchars - 1)*sizeof(wchar_t);
+                        fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
                     else
                         fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
                     fp->u.FfileBothDirectoryInfo.reserved = 0;
 #else
-                    strcpy(fp->u.FfileBothDirectoryInfo.shortName,
-                           shortName);
-                    fp->u.FfileBothDirectoryInfo.shortNameLength = strlen(shortName);
+                    cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
+                                    lengthof(fp->u.FfileBothDirectoryInfo.shortName),
+                                    shortName);
+                    fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
 #endif
                 }
                 /* Fallthrough */
@@ -5429,7 +6024,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
                 curPatchp->dptr = attrp;
 
-                if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
+                if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
                 } else {
                     curPatchp->flags = 0;
@@ -5439,7 +6034,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
                 /* temp */
                 curPatchp->dep = dep;
-            }   
+            }
 
             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
                 /* put out resume key */
@@ -5456,8 +6051,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             }
         }      /* if we're including this name */
         else if (!starPattern &&
-                  !foundInexact &&
-                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
+                 !foundInexact &&
+                 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
             /* We were looking for exact matches, but here's an inexact one*/
             foundInexact = 1;
         }
@@ -5469,10 +6064,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         curOffset = LargeIntegerAdd(thyper, curOffset);
     } /* while copying data for dir listing */
 
-    /* If we didn't get a star pattern, we did an exact match during the first pass. 
+    /* If we didn't get a star pattern, we did an exact match during the first pass.
      * If there were no exact matches found, we fail over to inexact matches by
      * marking the query as a star pattern (matches all case permutations), and
-     * re-running the query. 
+     * re-running the query.
      */
     if (returnedNames == 0 && !starPattern && foundInexact) {
         osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
@@ -5487,14 +6082,14 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        bufferp = NULL;
     }
 
-    /* apply and free last set of patches; if not doing a star match, this
-     * will be empty, but better safe (and freeing everything) than sorry.
+    /*
+     * Finally, process whatever entries we have left.
      */
-    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, 
+    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
                                       dsp->relPath, infoLevel, userp, &req);
 
     /* now put out the final parameters */
-    if (returnedNames == 0) 
+    if (returnedNames == 0)
         eos = 1;
     if (p->opcode == 1) {
         /* find first */
@@ -5502,7 +6097,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         outp->parmsp[1] = returnedNames;
         outp->parmsp[2] = eos;
         outp->parmsp[3] = 0;           /* nothing wrong with EAS */
-        outp->parmsp[4] = 0;   
+        outp->parmsp[4] = 0;
         /* don't need last name to continue
          * search, cookie is enough.  Normally,
          * this is the offset of the file name
@@ -5517,7 +6112,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         outp->parmsp[2] = 0;   /* EAS error */
         outp->parmsp[3] = 0;   /* last name, as above */
         outp->totalParms = 8;  /* in bytes */
-    }   
+    }
 
     /* return # of bytes in the buffer */
     outp->totalData = bytesInBuffer;
@@ -5533,9 +6128,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
      * we're supposed to close the search if we're done, and we're done,
      * or if something went wrong, close the search.
      */
-    if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) || 
+    if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
        (returnedNames == 0) ||
-        ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) || 
+        ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
        code != 0)
         smb_DeleteDirSearch(dsp);
 
@@ -5558,18 +6153,18 @@ long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     smb_dirSearch_t *dsp;
 
     dirHandle = smb_GetSMBParm(inp, 0);
-       
+
     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
 
     dsp = smb_FindDirSearch(dirHandle);
-        
+
     if (!dsp)
         return CM_ERROR_BADFD;
-       
+
     /* otherwise, we have an FD to destroy */
     smb_DeleteDirSearch(dsp);
     smb_ReleaseDirSearch(dsp);
-        
+
     /* and return results */
     smb_SetSMBDataLength(outp, 0);
 
@@ -5587,7 +6182,7 @@ long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
 /* SMB_COM_OPEN_ANDX */
 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *pathp;
+    clientchar_t *pathp;
     long code = 0;
     cm_space_t *spacep;
     int excl;
@@ -5595,10 +6190,9 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_scache_t *dscp;         /* dir we're dealing with */
     cm_scache_t *scp;          /* file we're creating */
     cm_attr_t setAttr;
-    int initialModeBits;
     smb_fid_t *fidp;
     int attributes;
-    char *lastNamep;
+    clientchar_t *lastNamep;
     unsigned long dosTime;
     int openFun;
     int trunc;
@@ -5606,14 +6200,16 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     int extraInfo;
     int openAction;
     int parmSlot;                      /* which parm we're dealing with */
-    char *tidPathp;
+    clientchar_t *tidPathp;
     cm_req_t req;
     int created = 0;
+    BOOL is_rpc = FALSE;
+    BOOL is_ipc = FALSE;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     scp = NULL;
-        
+
     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
     openFun = smb_GetSMBParm(inp, 8); /* open function */
     excl = ((openFun & 3) == 0);
@@ -5624,35 +6220,54 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     attributes = smb_GetSMBParm(inp, 5);
     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
 
-                                /* compute initial mode bits based on read-only flag in attributes */
-    initialModeBits = 0666;
-    if (attributes & SMB_ATTR_READONLY) 
-       initialModeBits &= ~0222;
-        
     pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
                                 SMB_STRF_ANSIPATH);
+    if (!pathp)
+        return CM_ERROR_BADSMB;
+
+    code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
+    if (code) {
+       if (code == CM_ERROR_TIDIPC) {
+           is_ipc = TRUE;
+       } else {
+           return CM_ERROR_NOSUCHPATH;
+       }
+    }
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    /* smb_StripLastComponent will strip "::$DATA" if present */
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
+
+    if (lastNamep &&
 
-    if (lastNamep && 
-         (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
-           stricmp(lastNamep, "\\srvsvc") == 0 ||
-           stricmp(lastNamep, "\\wkssvc") == 0 ||
-           stricmp(lastNamep, "ipc$") == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
-#ifdef NOTSERVICE
-        osi_Log0(smb_logp, "IOCTL Open");
-#endif
+        (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
+
+        /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
+         (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
+
+       unsigned short file_type = 0;
+       unsigned short device_state = 0;
 
         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-        smb_SetupIoctlFid(fidp, spacep);
+       if (is_rpc) {
+           code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
+           osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
+           if (code) {
+               osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
+               smb_ReleaseFID(fidp);
+               return code;
+           }
+       } else {
+           smb_SetupIoctlFid(fidp, spacep);
+           osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
+       }
 
         /* set inp->fid so that later read calls in same msg can find fid */
         inp->fid = fidp->fid;
-        
+
         /* copy out remainder of the parms */
         parmSlot = 2;
         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
@@ -5663,9 +6278,9 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;     /* len */
             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
-            smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
-            smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
-        }   
+            smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
+            smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
+        }
         /* and the final "always present" stuff */
         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
         /* next write out the "unique" ID */
@@ -5679,6 +6294,28 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return 0;
     }
 
+#ifndef DFS_SUPPORT
+    if (is_ipc) {
+       osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
+       return CM_ERROR_BADFD;
+    }
+#endif
+
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
+#endif
+        return CM_ERROR_BADNTFILENAME;
+    }
+
 #ifdef DEBUG_VERBOSE
     {
        char *hexp, *asciip;
@@ -5691,12 +6328,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     userp = smb_GetUserFromVCP(vcp, inp);
 
     dscp = NULL;
-    code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
-    if (code) {
-        cm_ReleaseUser(userp);
-        return CM_ERROR_NOSUCHPATH;
-    }
-    code = cm_NameI(cm_data.rootSCachep, pathp,
+    code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                     userp, tidPathp, &req, &scp);
 
@@ -5708,14 +6340,17 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
     if (code != 0) {
-        code = cm_NameI(cm_data.rootSCachep, spacep->data,
-                        CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                        userp, tidPathp, &req, &dscp);
+        if (code == CM_ERROR_NOSUCHFILE ||
+            code == CM_ERROR_NOSUCHPATH ||
+            code == CM_ERROR_BPLUS_NOMATCH)
+            code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
+                            CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                            userp, tidPathp, &req, &dscp);
         if (code) {
             cm_ReleaseUser(userp);
             return code;
@@ -5723,22 +6358,23 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
 #ifdef DFS_SUPPORT
         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+                                                      spacep->wdata);
             cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
         /* otherwise, scp points to the parent directory.  Do a lookup,
          * and truncate the file if we find it, otherwise we create the
          * file.
          */
-        if (!lastNamep) 
+        if (!lastNamep)
             lastNamep = pathp;
-        else 
+        else
             lastNamep++;
         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
                           &req, &scp);
@@ -5748,7 +6384,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             return code;
         }
     }
-        
+
     /* if we get here, if code is 0, the file exists and is represented by
      * scp.  Otherwise, we have to create it.  The dir may be represented
      * by dscp, or we may have found the file directly.  If code is non-zero,
@@ -5765,7 +6401,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         if (excl) {
             /* oops, file shouldn't be there */
-            if (dscp) 
+            if (dscp)
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -5789,11 +6425,13 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
     else {
         osi_assertx(dscp != NULL, "null cm_scache_t");
-        osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
-                 osi_LogSaveString(smb_logp, lastNamep));
+        osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
+                 osi_LogSaveClientString(smb_logp, lastNamep));
         openAction = 2;        /* created file */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
+        smb_SetInitialModeBitsForFile(attributes, &setAttr);
+
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                          &req);
         if (code == 0) {
@@ -5817,23 +6455,23 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                     setAttr.length.LowPart = 0;
                     setAttr.length.HighPart = 0;
                     code = cm_SetAttr(scp, &setAttr, userp, &req);
-                }   
+                }
             }  /* lookup succeeded */
         }
     }
-        
+
     /* we don't need this any longer */
-    if (dscp) 
+    if (dscp)
         cm_ReleaseSCache(dscp);
 
     if (code) {
         /* something went wrong creating or truncating the file */
-        if (scp) 
+        if (scp)
             cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         return code;
     }
-        
+
     /* make sure we're about to open a file */
     if (scp->fileType != CM_SCACHETYPE_FILE) {
         cm_ReleaseSCache(scp);
@@ -5844,7 +6482,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* now all we have to do is open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
     osi_assertx(fidp, "null smb_fid_t");
-       
+
     cm_HoldUser(userp);
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
@@ -5855,9 +6493,9 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
     /* also the user */
     fidp->userp = userp;
-        
+
     /* compute open mode */
-    if (openMode != 1) 
+    if (openMode != 1)
         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     if (openMode == 1 || openMode == 2)
         fidp->flags |= SMB_FID_OPENWRITE;
@@ -5868,12 +6506,12 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     lock_ReleaseMutex(&fidp->mx);
     smb_ReleaseFID(fidp);
-        
+
     cm_Open(scp, 0, userp);
 
     /* set inp->fid so that later read calls in same msg can find fid */
     inp->fid = fidp->fid;
-        
+
     /* copy out remainder of the parms */
     parmSlot = 2;
     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
@@ -5903,12 +6541,12 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_ReleaseUser(userp);
     /* leave scp held since we put it in fidp->scp */
     return 0;
-}       
+}
 
-static void smb_GetLockParams(unsigned char LockType, 
-                              char ** buf, 
-                              unsigned int * ppid, 
-                              LARGE_INTEGER * pOffset, 
+static void smb_GetLockParams(unsigned char LockType,
+                              char ** buf,
+                              unsigned int * ppid,
+                              LARGE_INTEGER * pOffset,
                               LARGE_INTEGER * pLength)
 {
     if (LockType & LOCKING_ANDX_LARGE_FILES) {
@@ -5951,23 +6589,27 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     int i;
     cm_key_t key;
     unsigned int pid;
+    afs_uint32 smb_vc_hold_required = 0;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = smb_GetSMBParm(inp, 2);
     fid = smb_ChainFID(fid, inp);
 
     fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
        return CM_ERROR_BADFD;
-    
+    }
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
-    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
        lock_ReleaseMutex(&fidp->mx);
@@ -5983,7 +6625,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     inp->fid = fid;
 
     userp = smb_GetUserFromVCP(vcp, inp);
-
+    smb_HoldVC(vcp);
 
     lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
@@ -6010,7 +6652,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
         /* AFS does not support atomic changes of lock types from read or write and vice-versa */
-        osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]"); 
+        osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
         code = CM_ERROR_BADOP;
         goto done;
 
@@ -6031,7 +6673,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
             {
                 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
-                    if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) && 
+                    if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
                         LargeIntegerEqualTo(wl->LLength, LLength)) {
                         wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
                         goto found_lock_request;
@@ -6052,9 +6694,9 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
 
-        code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
+        code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
 
-        if (code) 
+        if (code)
             goto done;
     }
 
@@ -6068,14 +6710,14 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
                         userp, &req, &lockp);
 
-       if (code == CM_ERROR_NOACCESS && LockType == LockWrite && 
+       if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
            (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
        {
            code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
                            userp, &req, &lockp);
        }
 
-        if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
+        if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
             smb_waitingLock_t * wLock;
 
             /* Put on waiting list */
@@ -6090,7 +6732,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 osi_assertx(wlRequest != NULL, "null wlRequest");
 
                 wlRequest->vcp = vcp;
-                smb_HoldVC(vcp);
+                smb_vc_hold_required = 1;
                 wlRequest->scp = scp;
                osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
                 cm_HoldSCache(scp);
@@ -6174,8 +6816,8 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
 
-                ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
-                
+                ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
+
                 if(ul_code != 0) {
                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
                 } else {
@@ -6214,7 +6856,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_SetSMBDataLength(outp, 0);
     }
 
-  done:   
+  done:
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
 
   doneSync:
@@ -6222,6 +6864,8 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
+    if (!smb_vc_hold_required)
+        smb_HoldVC(vcp);
 
     return code;
 }
@@ -6238,22 +6882,25 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     cm_req_t req;
     int readlock = 0;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = smb_GetSMBParm(inp, 0);
     fid = smb_ChainFID(fid, inp);
-        
+
     fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
        return CM_ERROR_BADFD;
-    
+    }
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
-    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
        smb_ReleaseFID(fidp);
@@ -6263,26 +6910,27 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
-        
+
     userp = smb_GetUserFromVCP(vcp, inp);
-        
-        
+
+
     /* otherwise, stat the file */
     lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) 
+    if (code)
        goto done;
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
     lock_ConvertWToR(&scp->rw);
+    readlock = 1;
 
     /* decode times.  We need a search time, but the response to this
      * call provides the date first, not the time, as returned in the
      * searchTime variable.  So we take the high-order bits first.
      */
-    smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
+    cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);      /* ctime */
     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);      /* atime */
@@ -6298,13 +6946,13 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
     /* file attribute */
     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
-        
+
     /* and finalize stuff */
     smb_SetSMBDataLength(outp, 0);
     code = 0;
 
   done:
-    if (readlock) 
+    if (readlock)
         lock_ReleaseRead(&scp->rw);
     else
         lock_ReleaseWrite(&scp->rw);
@@ -6312,7 +6960,7 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
     return code;
-}       
+}
 
 /* SMB_COM_SET_INFORMATION2 */
 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
@@ -6327,22 +6975,25 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     cm_attr_t attrs;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = smb_GetSMBParm(inp, 0);
     fid = smb_ChainFID(fid, inp);
-        
+
     fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
        return CM_ERROR_BADFD;
-    
+    }
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
-    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
        smb_ReleaseFID(fidp);
@@ -6352,18 +7003,17 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
-        
+
     userp = smb_GetUserFromVCP(vcp, inp);
-        
-        
+
     /* now prepare to call cm_setattr.  This message only sets various times,
      * and AFS only implements mtime, and we'll set the mtime if that's
      * requested.  The others we'll ignore.
      */
     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
-        
+
     if (searchTime != 0) {
-        smb_UnixTimeFromSearchTime(&unixTime, searchTime);
+        cm_UnixTimeFromSearchTime(&unixTime, searchTime);
 
         if ( unixTime != -1 ) {
             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
@@ -6372,10 +7022,10 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
         } else {
-            osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
+            osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
         }
     }
-    else 
+    else
        code = 0;
 
     cm_ReleaseSCache(scp);
@@ -6394,6 +7044,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_fid_t *fidp;
     smb_t *smbp = (smb_t*) inp;
     long code = 0;
+    cm_scache_t *scp;
     cm_user_t *userp;
     char *op;
     int inDataBlockCount;
@@ -6406,17 +7057,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     if (*inp->wctp == 14) {
         /* we have a request with 64-bit file offsets */
-#ifdef AFS_LARGEFILES
         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
-#else
-        if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
-            /* uh oh */
-            osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
-            /* we shouldn't have received this op if we didn't specify
-               largefile support */
-            return CM_ERROR_BADOP;
-        }
-#endif
     }
 
     op = inp->data + smb_GetSMBParm(inp, 11);
@@ -6424,26 +7065,46 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
              fd, offset.HighPart, offset.LowPart, count);
-        
+
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
-    if (!fidp)
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
         return CM_ERROR_BADFD;
-        
+    }
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
-    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
        smb_ReleaseFID(fidp);
        return code;
     }
+
+    if (fidp->flags & SMB_FID_RPC) {
+       lock_ReleaseMutex(&fidp->mx);
+        code = smb_RPCV3Write(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       return code;
+    }
+
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_BADFDOP;
+    }
+
+    scp = fidp->scp;
+    cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
+
     userp = smb_GetUserFromVCP(vcp, inp);
 
     /* special case: 0 bytes transferred means there is no data
@@ -6455,7 +7116,6 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_key_t key;
         LARGE_INTEGER LOffset;
         LARGE_INTEGER LLength;
-        cm_scache_t * scp;
 
         pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
@@ -6465,7 +7125,6 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        scp = fidp->scp;
         lock_ObtainWrite(&scp->rw);
         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
         lock_ReleaseWrite(&scp->rw);
@@ -6486,8 +7145,10 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
      */
     lock_ObtainMutex(&fidp->mx);
     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
-        fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
-        fidp->scp->clientModTime = time(NULL);
+        lock_ObtainWrite(&fidp->scp->rw);
+        scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
+        scp->clientModTime = time(NULL);
+        lock_ReleaseWrite(&fidp->scp->rw);
     }
     lock_ReleaseMutex(&fidp->mx);
 
@@ -6513,6 +7174,8 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_SetSMBDataLength(outp, 0);
 
  done:
+
+    cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
 
@@ -6530,17 +7193,17 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_fid_t *fidp;
     smb_t *smbp = (smb_t*) inp;
     long code = 0;
+    cm_scache_t *scp;
     cm_user_t *userp;
     cm_key_t key;
     char *op;
-        
-    fd = smb_GetSMBParm(inp, 2);
-    count = smb_GetSMBParm(inp, 5);
+
+    fd = smb_GetSMBParm(inp, 2); /* File ID */
+    count = smb_GetSMBParm(inp, 5); /* MaxCount */
     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
 
     if (*inp->wctp == 12) {
         /* a request with 64-bit offsets */
-#ifdef AFS_LARGEFILES
         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
 
         if (LargeIntegerLessThanZero(offset)) {
@@ -6548,14 +7211,6 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                      offset.HighPart, offset.LowPart);
             return CM_ERROR_BADSMB;
         }
-#else
-        if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
-            osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit.  Dropping");
-            return CM_ERROR_BADSMB;
-        } else {
-            offset.HighPart = 0;
-        }
-#endif
     } else {
         offset.HighPart = 0;
     }
@@ -6566,31 +7221,62 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
     if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fd);
         return CM_ERROR_BADFD;
     }
 
+    lock_ObtainMutex(&fidp->mx);
+
+    if (fidp->flags & SMB_FID_IOCTL) {
+       lock_ReleaseMutex(&fidp->mx);
+       inp->fid = fd;
+        code = smb_IoctlV3Read(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       return code;
+    }
+
+    if (fidp->flags & SMB_FID_RPC) {
+       lock_ReleaseMutex(&fidp->mx);
+       inp->fid = fd;
+        code = smb_RPCV3Read(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       return code;
+    }
+
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
-    pid = smbp->pid;
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_BADFDOP;
+    }
+
+    scp = fidp->scp;
+    cm_HoldSCache(scp);
+
+    lock_ReleaseMutex(&fidp->mx);
+
+    pid = smbp->pid;
     key = cm_GenerateKey(vcp->vcID, pid, fd);
     {
         LARGE_INTEGER LOffset, LLength;
-        cm_scache_t *scp;
 
         LOffset.HighPart = offset.HighPart;
         LOffset.LowPart = offset.LowPart;
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        scp = fidp->scp;
         lock_ObtainWrite(&scp->rw);
         code = cm_LockCheckRead(scp, LOffset, LLength, key);
         lock_ReleaseWrite(&scp->rw);
     }
+    cm_ReleaseSCache(scp);
 
     if (code) {
         smb_ReleaseFID(fidp);
@@ -6600,15 +7286,6 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* set inp->fid so that later read calls in same msg can find fid */
     inp->fid = fd;
 
-    lock_ObtainMutex(&fidp->mx);
-    if (fidp->flags & SMB_FID_IOCTL) {
-       lock_ReleaseMutex(&fidp->mx);
-        code = smb_IoctlV3Read(fidp, vcp, inp, outp);
-       smb_ReleaseFID(fidp);
-       return code;
-    }
-    lock_ReleaseMutex(&fidp->mx);
-
     userp = smb_GetUserFromVCP(vcp, inp);
 
     /* 0 and 1 are reserved for request chaining, were setup by our caller,
@@ -6629,7 +7306,7 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
      * know where the data really is.
      */
     op = smb_GetSMBData(outp, NULL);
-        
+
     /* now fill in offset from start of SMB header to first data byte (to op) */
     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
 
@@ -6645,8 +7322,8 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
     return code;
-}   
-        
+}
+
 /*
  * Values for createDisp, copied from NTDDK.H
  */
@@ -6673,11 +7350,17 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #define FILE_RANDOM_ACCESS        0x0800
 #define FILE_DELETE_ON_CLOSE      0x1000
 #define FILE_OPEN_BY_FILE_ID      0x2000
+#define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
+#define FILE_NO_COMPRESSION                     0x00008000
+#define FILE_RESERVE_OPFILTER                   0x00100000
+#define FILE_OPEN_REPARSE_POINT                 0x00200000
+#define FILE_OPEN_NO_RECALL                     0x00400000
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
 
 /* SMB_COM_NT_CREATE_ANDX */
 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *pathp, *realPathp;
+    clientchar_t *pathp, *realPathp;
     long code = 0;
     cm_space_t *spacep;
     cm_user_t *userp;
@@ -6685,8 +7368,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_scache_t *scp;          /* file to create or open */
     cm_scache_t *targetScp;    /* if scp is a symlink */
     cm_attr_t setAttr;
-    char *lastNamep;
-    char *treeStartp;
+    clientchar_t *lastNamep;
+    clientchar_t *treeStartp;
     unsigned short nameLength;
     unsigned int flags;
     unsigned int requestOpLock;
@@ -6700,7 +7383,6 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     unsigned int createDisp;
     unsigned int createOptions;
     unsigned int shareAccess;
-    int initialModeBits;
     unsigned short baseFid;
     smb_fid_t *baseFidp;
     smb_fid_t *fidp;
@@ -6710,16 +7392,20 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     long fidflags;
     FILETIME ft;
     LARGE_INTEGER sz;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     BOOL foundscp;
     cm_req_t req;
     int created = 0;
+    int prefetch = 0;
+    int checkDoneRequired = 0;
     cm_lock_data_t *ldp = NULL;
+    BOOL is_rpc = FALSE;
+    BOOL is_ipc = FALSE;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     /* This code is very long and has a lot of if-then-else clauses
-     * scp and dscp get reused frequently and we need to ensure that 
+     * scp and dscp get reused frequently and we need to ensure that
      * we don't lose a reference.  Start by ensuring that they are NULL.
      */
     scp = NULL;
@@ -6763,43 +7449,66 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     else
         realDirFlag = -1;
 
-    /*
-     * compute initial mode bits based on read-only flag in
-     * extended attributes
-     */
-    initialModeBits = 0666;
-    if (extAttributes & SMB_ATTR_READONLY) 
-        initialModeBits &= ~0222;
-
-    if (nameLength == 0)
-        return CM_ERROR_INVAL;
-
     pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
                               NULL, SMB_STRF_ANSIPATH);
 
     /* Sometimes path is not null-terminated, so we make a copy. */
-    realPathp = malloc(nameLength+1);
-    memcpy(realPathp, pathp, nameLength);
-    realPathp[nameLength] = 0;
+    realPathp = malloc(nameLength+sizeof(clientchar_t));
+    memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
+    realPathp[nameLength/sizeof(clientchar_t)] = 0;
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
+    /* smb_StripLastComponent will strip "::$DATA" if present */
+    smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
 
-    osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
+    osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
-    osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
+    osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
+
+    if (baseFid == 0) {
+       baseFidp = NULL;
+        baseDirp = cm_RootSCachep(cm_rootUserp, &req);
+        code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
+        if (code == CM_ERROR_TIDIPC) {
+            /* Attempt to use a TID allocated for IPC.  The client
+             * is probably looking for DCE RPC end points which we
+             * don't support OR it could be looking to make a DFS
+             * referral request.
+             */
+            osi_Log0(smb_logp, "NTCreateX received IPC TID");
+           is_ipc = TRUE;
+        }
+    }
+
+    osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
+
+    if (lastNamep &&
+
+       ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
+
+        /* special case magic file name for receiving IOCTL requests
+         * (since IOCTL calls themselves aren't getting through).
+         */
+        cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0)) {
+
+       unsigned short file_type = 0;
+       unsigned short device_state = 0;
 
-       if (lastNamep && 
-             (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
-               stricmp(lastNamep, "\\srvsvc") == 0 ||
-               stricmp(lastNamep, "\\wkssvc") == 0 ||
-               stricmp(lastNamep, "ipc$") == 0)) {
-        /* special case magic file name for receiving IOCTL requests
-         * (since IOCTL calls themselves aren't getting through).
-         */
         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-        smb_SetupIoctlFid(fidp, spacep);
-        osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
+
+       if (is_rpc) {
+           code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
+           osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
+           if (code) {
+               osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
+               smb_ReleaseFID(fidp);
+               free(realPathp);
+               return code;
+           }
+       } else {
+           smb_SetupIoctlFid(fidp, spacep);
+           osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
+       }
 
         /* set inp->fid so that later read calls in same msg can find fid */
         inp->fid = fidp->fid;
@@ -6819,8 +7528,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         sz.HighPart = 0x7fff; sz.LowPart = 0;
         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
-        smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
-        smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* dev state */
+        smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++; /* filetype */
+        smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;      /* dev state */
         smb_SetSMBParmByte(outp, parmSlot, 0); /* is a dir? */
         smb_SetSMBDataLength(outp, 0);
 
@@ -6830,16 +7539,30 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return 0;
     }
 
-#ifdef DEBUG_VERBOSE
-    {
-       char *hexp, *asciip;
-       asciip = (lastNamep? lastNamep : realPathp);
-       hexp = osi_HexifyString( asciip );
-       DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
-       free(hexp);
+#ifndef DFS_SUPPORT
+    if (is_ipc) {
+       osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
+       free(realPathp);
+       return CM_ERROR_BADFD;
     }
 #endif
 
+    if (!cm_IsValidClientString(realPathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(realPathp, -1);
+        osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+           free(hexp);
+#else
+        osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
+#endif
+        free(realPathp);
+        return CM_ERROR_BADNTFILENAME;
+    }
+
     userp = smb_GetUserFromVCP(vcp, inp);
     if (!userp) {
        osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
@@ -6847,37 +7570,20 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        return CM_ERROR_INVAL;
     }
 
-    if (baseFid == 0) {
-       baseFidp = NULL;
-        baseDirp = cm_data.rootSCachep;
-        code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
-        if (code == CM_ERROR_TIDIPC) {
-            /* Attempt to use a TID allocated for IPC.  The client
-             * is probably looking for DCE RPC end points which we
-             * don't support OR it could be looking to make a DFS
-             * referral request. 
-             */
-            osi_Log0(smb_logp, "NTCreateX received IPC TID");
-#ifndef DFS_SUPPORT
-            free(realPathp);
-            cm_ReleaseUser(userp);
-            return CM_ERROR_NOSUCHFILE;
-#endif /* DFS_SUPPORT */
-        }
-    } else {
+    if (baseFidp != 0) {
         baseFidp = smb_FindFID(vcp, baseFid, 0);
         if (!baseFidp) {
             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
+           cm_ReleaseUser(userp);
             free(realPathp);
-            cm_ReleaseUser(userp);
             return CM_ERROR_INVAL;
-        }       
+        }
 
         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
             free(realPathp);
-            cm_ReleaseUser(userp);
            smb_CloseFID(vcp, baseFidp, NULL, 0);
             smb_ReleaseFID(baseFidp);
+           cm_ReleaseUser(userp);
             return CM_ERROR_NOSUCHPATH;
         }
 
@@ -6885,8 +7591,6 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         tidPathp = NULL;
     }
 
-    osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
-
     /* compute open mode */
     fidflags = 0;
     if (desiredAccess & DELETE)
@@ -6901,6 +7605,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        fidflags |= SMB_FID_SEQUENTIAL;
     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
        fidflags |= SMB_FID_RANDOM;
+    if (createOptions & FILE_OPEN_REPARSE_POINT)
+        osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
     if (smb_IsExecutableFileName(lastNamep))
         fidflags |= SMB_FID_EXECUTABLE;
 
@@ -6914,43 +7620,44 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     code = 0;
 
     /* For an exclusive create, we want to do a case sensitive match for the last component. */
-    if ( createDisp == FILE_CREATE || 
+    if ( createDisp == FILE_CREATE ||
          createDisp == FILE_OVERWRITE ||
          createDisp == FILE_OVERWRITE_IF) {
-        code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+        code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &dscp);
         if (code == 0) {
 #ifdef DFS_SUPPORT
             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+                                                          spacep->wdata);
                 cm_ReleaseSCache(dscp);
                 cm_ReleaseUser(userp);
                 free(realPathp);
-               if (baseFidp) 
+               if (baseFidp)
                    smb_ReleaseFID(baseFidp);
                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
-                    return CM_ERROR_BADSHARENAME;
+                    return CM_ERROR_NOSUCHPATH;
             }
 #endif /* DFS_SUPPORT */
             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
                              userp, &req, &scp);
             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
-                code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
+                code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
                 if (code == 0 && realDirFlag == 1) {
                     cm_ReleaseSCache(scp);
                     cm_ReleaseSCache(dscp);
                     cm_ReleaseUser(userp);
                     free(realPathp);
-                   if (baseFidp) 
+                   if (baseFidp)
                        smb_ReleaseFID(baseFidp);
                     return CM_ERROR_EXISTS;
                 }
             }
+            /* we have both scp and dscp */
         }
-        /* we have both scp and dscp */
     } else {
         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &scp);
@@ -6960,20 +7667,31 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
-           if (baseFidp) 
+           if (baseFidp)
                smb_ReleaseFID(baseFidp);
             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
         /* we might have scp but not dscp */
     }
 
+    if (code &&
+        code != CM_ERROR_NOSUCHFILE &&
+        code != CM_ERROR_NOSUCHPATH &&
+        code != CM_ERROR_BPLUS_NOMATCH) {
+        cm_ReleaseUser(userp);
+        free(realPathp);
+        if (baseFidp)
+            smb_ReleaseFID(baseFidp);
+        return code;
+    }
+
     if (scp)
         foundscp = TRUE;
-    
+
     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
         /* look up parent directory */
         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
@@ -6985,40 +7703,44 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         if (dscp == NULL) {
             do {
-                char *tp;
+                clientchar_t *tp;
 
-                code = cm_NameI(baseDirp, spacep->data,
-                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                             userp, tidPathp, &req, &dscp);
+                code = cm_NameI(baseDirp, spacep->wdata,
+                                CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                                userp, tidPathp, &req, &dscp);
 
 #ifdef DFS_SUPPORT
                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                    int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                    int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+                                                              spacep->wdata);
                     if (scp)
                         cm_ReleaseSCache(scp);
                     cm_ReleaseSCache(dscp);
                     cm_ReleaseUser(userp);
                     free(realPathp);
-                   if (baseFidp) 
+                   if (baseFidp)
                        smb_ReleaseFID(baseFidp);
                     if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                         return CM_ERROR_PATH_NOT_COVERED;
                     else
-                        return CM_ERROR_BADSHARENAME;
+                        return CM_ERROR_NOSUCHPATH;
                 }
 #endif /* DFS_SUPPORT */
 
-                if (code && 
-                     (tp = strrchr(spacep->data,'\\')) &&
-                     (createDisp == FILE_CREATE) &&
-                     (realDirFlag == 1)) {
+                if (code &&
+                    (code == CM_ERROR_NOSUCHFILE ||
+                     code == CM_ERROR_NOSUCHPATH ||
+                     code == CM_ERROR_BPLUS_NOMATCH) &&
+                    (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
+                    (createDisp == FILE_CREATE) &&
+                    (realDirFlag == 1)) {
                     *tp++ = 0;
                     treeCreate = TRUE;
-                    treeStartp = realPathp + (tp - spacep->data);
+                    treeStartp = realPathp + (tp - spacep->wdata);
 
                     if (*tp && !smb_IsLegalFilename(tp)) {
                         cm_ReleaseUser(userp);
-                        if (baseFidp) 
+                        if (baseFidp)
                             smb_ReleaseFID(baseFidp);
                         free(realPathp);
                         if (scp)
@@ -7057,9 +7779,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             return CM_ERROR_EXISTS;
         }
 
-        if (!lastNamep) 
+        if (!lastNamep)
             lastNamep = realPathp;
-        else 
+        else
             lastNamep++;
 
         if (!smb_IsLegalFilename(lastNamep)) {
@@ -7073,9 +7795,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         }
 
         if (!foundscp && !treeCreate) {
-            if ( createDisp == FILE_CREATE || 
+            if ( createDisp == FILE_CREATE ||
                  createDisp == FILE_OVERWRITE ||
-                 createDisp == FILE_OVERWRITE_IF) 
+                 createDisp == FILE_OVERWRITE_IF)
             {
                 code = cm_Lookup(dscp, lastNamep,
                                   CM_FLAG_FOLLOW, userp, &req, &scp);
@@ -7104,17 +7826,33 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
      * by dscp, or we may have found the file directly.  If code is non-zero,
      * scp is NULL.
      */
+
+    /*
+     * open the file itself
+     * allocate the fidp early so the smb fid can be used by cm_CheckNTOpen()
+     */
+    fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
+    osi_assertx(fidp, "null smb_fid_t");
+
+    /* save a reference to the user */
+    cm_HoldUser(userp);
+    fidp->userp = userp;
+
     if (code == 0 && !treeCreate) {
-        code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+        code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
         if (code) {
+            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
             if (scp)
                 cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
+           smb_CloseFID(vcp, fidp, NULL, 0);
+           smb_ReleaseFID(fidp);
             free(realPathp);
             return code;
         }
+        checkDoneRequired = 1;
 
        if (createDisp == FILE_CREATE) {
             /* oops, file shouldn't be there */
@@ -7124,11 +7862,13 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             if (scp)
                 cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
+           smb_CloseFID(vcp, fidp, NULL, 0);
+           smb_ReleaseFID(fidp);
             free(realPathp);
             return CM_ERROR_EXISTS;
         }
 
-        if ( createDisp == FILE_OVERWRITE || 
+        if ( createDisp == FILE_OVERWRITE ||
              createDisp == FILE_OVERWRITE_IF) {
 
             setAttr.mask = CM_ATTRMASK_LENGTH;
@@ -7150,13 +7890,16 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                     cm_ReleaseSCache(scp);
                     scp = targetScp;
-                   code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+                   code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
                    if (code) {
+                        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                        if (dscp)
                            cm_ReleaseSCache(dscp);
                        if (scp)
                            cm_ReleaseSCache(scp);
                        cm_ReleaseUser(userp);
+                        smb_CloseFID(vcp, fidp, NULL, 0);
+                        smb_ReleaseFID(fidp);
                        free(realPathp);
                        return code;
                    }
@@ -7165,7 +7908,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             code = cm_SetAttr(scp, &setAttr, userp, &req);
             openAction = 3;    /* truncated existing file */
         }
-        else 
+        else
             openAction = 1;    /* found existing file */
 
     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
@@ -7175,15 +7918,19 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         if (scp)
             cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
         free(realPathp);
         return CM_ERROR_NOSUCHFILE;
     } else if (realDirFlag == 0 || realDirFlag == -1) {
         osi_assertx(dscp != NULL, "null cm_scache_t");
-        osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
-                  osi_LogSaveString(smb_logp, lastNamep));
+        osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
+                  osi_LogSaveClientString(smb_logp, lastNamep));
         openAction = 2;                /* created file */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         setAttr.clientModTime = time(NULL);
+        smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
+
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
         if (code == 0) {
            created = 1;
@@ -7227,21 +7974,21 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             }  /* lookup succeeded */
         }
     } else {
-        char *tp, *pp;
-        char *cp; /* This component */
+        clientchar_t *tp, *pp;
+        clientchar_t *cp; /* This component */
         int clen = 0; /* length of component */
         cm_scache_t *tscp1, *tscp2;
         int isLast = 0;
 
         /* create directory */
-        if ( !treeCreate ) 
+        if ( !treeCreate )
             treeStartp = lastNamep;
         osi_assertx(dscp != NULL, "null cm_scache_t");
-        osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
-                  osi_LogSaveString(smb_logp, treeStartp));
+        osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
+                  osi_LogSaveClientString(smb_logp, treeStartp));
         openAction = 2;                /* created directory */
 
-       /* if the request is to create the root directory 
+       /* if the request is to create the root directory
         * it will appear as a directory name of the nul-string
         * and a code of CM_ERROR_NOSUCHFILE
         */
@@ -7250,38 +7997,40 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         setAttr.clientModTime = time(NULL);
+        smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
 
         pp = treeStartp;
-        cp = spacep->data;
+        cp = spacep->wdata;
         tscp1 = dscp;
         cm_HoldSCache(tscp1);
         tscp2 = NULL;
 
         while (pp && *pp) {
-            tp = strchr(pp, '\\');
+            tp = cm_ClientStrChr(pp, '\\');
             if (!tp) {
-                strcpy(cp,pp);
-                clen = (int)strlen(cp);
+                cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
+                clen = (int)cm_ClientStrLen(cp);
                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
             } else {
                 clen = (int)(tp - pp);
-                strncpy(cp,pp,clen);
+                cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
+                                 pp, clen);
                 *(cp + clen) = 0;
                 tp++;
             }
             pp = tp;
 
-            if (clen == 0) 
+            if (clen == 0)
                 continue; /* the supplied path can't have consecutive slashes either , but */
 
             /* cp is the next component to be created. */
-            code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
+            code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
                 smb_NotifyChange(FILE_ACTION_ADDED,
-                                  FILE_NOTIFY_CHANGE_DIR_NAME,
-                                  tscp1, cp, NULL, TRUE);
-            if (code == 0 || 
-                 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
+                                 FILE_NOTIFY_CHANGE_DIR_NAME,
+                                 tscp1, cp, NULL, TRUE);
+            if (code == 0 ||
+                (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
                 /* Not an exclusive create, and someone else tried
                  * creating it already, then we open it anyway.  We
                  * don't bother retrying after this, since if this next
@@ -7289,9 +8038,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                  * started this call.
                  */
                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
-                                  userp, &req, &tscp2);
-            }       
-            if (code) 
+                                 userp, &req, &tscp2);
+            }
+            if (code)
                 break;
 
             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
@@ -7307,7 +8056,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         if (scp)
             cm_ReleaseSCache(scp);
         scp = tscp2;
-        /* 
+        /*
          * if we get here and code == 0, then scp is the last directory created, and dscp is the
          * parent of scp.
          */
@@ -7315,13 +8064,15 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     if (code) {
         /* something went wrong creating or truncating the file */
-       if (ldp)
+       if (checkDoneRequired)
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
-        if (scp) 
+        if (scp)
             cm_ReleaseSCache(scp);
-        if (dscp) 
+        if (dscp)
             cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
         free(realPathp);
         return code;
     }
@@ -7339,20 +8090,24 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 * we'll just use the symlink anyway.
                 */
                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
-               if (ldp)
+               if (checkDoneRequired) {
                    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                    checkDoneRequired = 0;
+                }
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
         }
 
         if (scp->fileType != CM_SCACHETYPE_FILE) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
+           smb_CloseFID(vcp, fidp, NULL, 0);
+           smb_ReleaseFID(fidp);
             free(realPathp);
             return CM_ERROR_ISDIR;
         }
@@ -7360,24 +8115,18 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* (only applies to single component case) */
     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
-       if (ldp)
+       if (checkDoneRequired)
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         cm_ReleaseSCache(scp);
         if (dscp)
             cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
         free(realPathp);
         return CM_ERROR_NOTDIR;
     }
 
-    /* open the file itself */
-    fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assertx(fidp, "null smb_fid_t");
-
-    /* save a reference to the user */
-    cm_HoldUser(userp);
-    fidp->userp = userp;
-
     /* If we are restricting sharing, we should do so with a suitable
        share lock. */
     if (scp->fileType == CM_SCACHETYPE_FILE &&
@@ -7403,29 +8152,30 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         }
 
         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
-        
+
         lock_ObtainWrite(&scp->rw);
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
         lock_ReleaseWrite(&scp->rw);
 
         if (code) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
            cm_ReleaseUser(userp);
-           /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
            smb_CloseFID(vcp, fidp, NULL, 0);
            smb_ReleaseFID(fidp);
             free(realPathp);
-            return code;
+            return CM_ERROR_SHARING_VIOLATION;
         }
     }
 
     /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
-    if (ldp)
+    if (checkDoneRequired) {
        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+        checkDoneRequired = 0;
+    }
 
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
@@ -7447,7 +8197,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         fidp->flags |= SMB_FID_NTOPEN;
         fidp->NTopen_dscp = dscp;
        dscp = NULL;
-        fidp->NTopen_pathp = strdup(lastNamep);
+        fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
     }
     fidp->NTopen_wholepathp = realPathp;
     lock_ReleaseMutex(&fidp->mx);
@@ -7463,40 +8213,87 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* set inp->fid so that later read calls in same msg can find fid */
     inp->fid = fidp->fid;
 
-    /* out parms */
-    parmSlot = 2;
     lock_ObtainRead(&scp->rw);
-    smb_SetSMBParmByte(outp, parmSlot, 0);     /* oplock */
-    smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
-    smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
-    smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
-    smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
-    parmSlot += 2;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
-    smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
-    smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;     /* filetype */
-    smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;     /* dev state */
-    smb_SetSMBParmByte(outp, parmSlot,
-                        (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
-                        scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
-                        scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
-    smb_SetSMBDataLength(outp, 0);
 
-    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
-        LargeIntegerGreaterThanZero(fidp->scp->length) && 
+    /*
+     * Always send the standard response.  Sending the extended
+     * response results in the Explorer Shell being unable to
+     * access directories at random times.
+     */
+    if (1 /*!extendedRespRequired */) {
+        /* out parms */
+        parmSlot = 2;
+        smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
+        smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
+        smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
+        parmSlot += 2;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+        smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
+        smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
+        parmSlot++;    /* dev state */
+        smb_SetSMBParmByte(outp, parmSlot,
+                            (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+                              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                              scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
+        smb_SetSMBDataLength(outp, 0);
+    } else {
+        /* out parms */
+        parmSlot = 2;
+        smb_SetSMBParmByte(outp, parmSlot, 0); /* oplock */
+        smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
+        smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
+        smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
+        parmSlot += 2;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+        smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
+        smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* filetype */
+        smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
+        parmSlot++;    /* dev state */
+        smb_SetSMBParmByte(outp, parmSlot,
+                            (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+                              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                              scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
+        /* Setting the GUID results in a failure with cygwin */
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        /* Maxmimal access rights */
+        smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
+        /* Guest access rights */
+        smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
+        smb_SetSMBDataLength(outp, 0);
+    }
+
+    if ((fidp->flags & SMB_FID_EXECUTABLE) &&
+        LargeIntegerGreaterThanZero(scp->length) &&
         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
-        cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
-                           fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
-                           userp);
+        prefetch = 1;
     }
     lock_ReleaseRead(&scp->rw);
 
-    osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
-              osi_LogSaveString(smb_logp, realPathp));
+    if (prefetch)
+        cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
+                           scp->length.LowPart, scp->length.HighPart,
+                           userp, &req);
+
+
+    osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
+              osi_LogSaveClientString(smb_logp, realPathp));
 
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
@@ -7506,7 +8303,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* leave scp held since we put it in fidp->scp */
     return 0;
-}       
+}
 
 /*
  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
@@ -7516,7 +8313,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *pathp, *realPathp;
+    clientchar_t *pathp, *realPathp;
     long code = 0;
     cm_space_t *spacep;
     cm_user_t *userp;
@@ -7524,7 +8321,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     cm_scache_t *scp;          /* file to create or open */
     cm_scache_t *targetScp;     /* if scp is a symlink */
     cm_attr_t setAttr;
-    char *lastNamep;
+    clientchar_t *lastNamep;
     unsigned long nameLength;
     unsigned int flags;
     unsigned int requestOpLock;
@@ -7533,17 +8330,15 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     unsigned int extendedRespRequired;
     int realDirFlag;
     unsigned int desiredAccess;
-#ifdef DEBUG_VERBOSE    
     unsigned int allocSize;
-#endif
     unsigned int shareAccess;
     unsigned int extAttributes;
     unsigned int createDisp;
-#ifdef DEBUG_VERBOSE
     unsigned int sdLen;
-#endif
+    unsigned int eaLen;
+    unsigned int impLevel;
+    unsigned int secFlags;
     unsigned int createOptions;
-    int initialModeBits;
     unsigned short baseFid;
     smb_fid_t *baseFidp;
     smb_fid_t *fidp;
@@ -7552,7 +8347,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     int parmSlot;
     long fidflags;
     FILETIME ft;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     BOOL foundscp;
     int parmOffset, dataOffset;
     char *parmp;
@@ -7560,9 +8355,11 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     char *outData;
     cm_req_t req;
     int created = 0;
+    int prefetch = 0;
     cm_lock_data_t *ldp = NULL;
+    int checkDoneRequired = 0;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     foundscp = FALSE;
     scp = NULL;
@@ -7586,23 +8383,16 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         return CM_ERROR_INVAL;
     baseFid = (unsigned short)lparmp[1];
     desiredAccess = lparmp[2];
-#ifdef DEBUG_VERBOSE
     allocSize = lparmp[3];
-#endif /* DEBUG_VERSOSE */
     extAttributes = lparmp[5];
     shareAccess = lparmp[6];
     createDisp = lparmp[7];
     createOptions = lparmp[8];
-#ifdef DEBUG_VERBOSE
     sdLen = lparmp[9];
-#endif
-    nameLength = lparmp[11];
-
-#ifdef DEBUG_VERBOSE
-    osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
-    osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
-    osi_Log1(smb_logp,"... flags[%x]",flags);
-#endif
+    eaLen = lparmp[10];
+    nameLength = lparmp[11];    /* spec says chars but appears to be bytes */
+    impLevel = lparmp[12];
+    secFlags = lparmp[13];
 
     /* mustBeDir is never set; createOptions directory bit seems to be
      * more important
@@ -7614,72 +8404,93 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     else
         realDirFlag = -1;
 
-    /*
-     * compute initial mode bits based on read-only flag in
-     * extended attributes
-     */
-    initialModeBits = 0666;
-    if (extAttributes & SMB_ATTR_READONLY) 
-        initialModeBits &= ~0222;
-
-    pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
-    pathp = smb_ParseStringCch(inp, pathp, nameLength, NULL, SMB_STRF_ANSIPATH);
-    /* Sometimes path is not null-terminated, so we make a copy. */
-    realPathp = malloc(nameLength+1);
+    pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
+                               nameLength, NULL, SMB_STRF_ANSIPATH);
+    /* Sometimes path is not nul-terminated, so we make a copy. */
+    realPathp = malloc(nameLength+sizeof(clientchar_t));
     memcpy(realPathp, pathp, nameLength);
-    realPathp[nameLength] = 0;
+    realPathp[nameLength/sizeof(clientchar_t)] = 0;
     spacep = cm_GetSpace();
-    smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
+    /* smb_StripLastComponent will strip "::$DATA" if present */
+    smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
+
+    osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
+    osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
+    osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
+    osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
+
+    if ( realDirFlag == 1 &&
+         ( createDisp == FILE_SUPERSEDE ||
+           createDisp == FILE_OVERWRITE ||
+           createDisp == FILE_OVERWRITE_IF))
+    {
+        osi_Log0(smb_logp, "NTTranCreate rejecting invalid readDirFlag and createDisp combination");
+        cm_FreeSpace(spacep);
+        free(realPathp);
+        return CM_ERROR_INVAL;
+    }
 
     /*
      * Nothing here to handle SMB_IOCTL_FILENAME.
      * Will add it if necessary.
      */
 
-#ifdef DEBUG_VERBOSE
-    {
-        char *hexp, *asciip;
-        asciip = (lastNamep? lastNamep : realPathp);
-        hexp = osi_HexifyString( asciip );
-        DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
+    if (!cm_IsValidClientString(realPathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(realPathp, -1);
+        osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
         free(hexp);
-    }
+#else
+        osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
 #endif
+        cm_FreeSpace(spacep);
+        free(realPathp);
+        return CM_ERROR_BADNTFILENAME;
+    }
 
     userp = smb_GetUserFromVCP(vcp, inp);
     if (!userp) {
        osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
+        cm_FreeSpace(spacep);
        free(realPathp);
        return CM_ERROR_INVAL;
     }
 
     if (baseFid == 0) {
        baseFidp = NULL;
-        baseDirp = cm_data.rootSCachep;
+        baseDirp = cm_RootSCachep(cm_rootUserp, &req);
         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
         if (code == CM_ERROR_TIDIPC) {
             /* Attempt to use a TID allocated for IPC.  The client
              * is probably looking for DCE RPC end points which we
              * don't support OR it could be looking to make a DFS
-             * referral request. 
+             * referral request.
              */
             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
 #ifndef DFS_SUPPORT
+            cm_FreeSpace(spacep);
             free(realPathp);
             cm_ReleaseUser(userp);
             return CM_ERROR_NOSUCHPATH;
-#endif 
+#endif
         }
     } else {
         baseFidp = smb_FindFID(vcp, baseFid, 0);
         if (!baseFidp) {
-           osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
+            osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
+                      vcp, baseFid);
+            cm_FreeSpace(spacep);
             free(realPathp);
             cm_ReleaseUser(userp);
             return CM_ERROR_BADFD;
-        }       
+        }
 
         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+            cm_FreeSpace(spacep);
             free(realPathp);
             cm_ReleaseUser(userp);
            smb_CloseFID(vcp, baseFidp, NULL, 0);
@@ -7705,6 +8516,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
        fidflags |= SMB_FID_SEQUENTIAL;
     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
        fidflags |= SMB_FID_RANDOM;
+    if (createOptions & FILE_OPEN_REPARSE_POINT)
+        osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
     if (smb_IsExecutableFileName(lastNamep))
         fidflags |= SMB_FID_EXECUTABLE;
 
@@ -7716,94 +8529,70 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
     dscp = NULL;
     code = 0;
-    if ( createDisp == FILE_OPEN || 
-         createDisp == FILE_OVERWRITE ||
-         createDisp == FILE_OVERWRITE_IF) {
-        code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                        userp, tidPathp, &req, &dscp);
-        if (code == 0) {
-#ifdef DFS_SUPPORT
-            if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
-                cm_ReleaseSCache(dscp);
-                cm_ReleaseUser(userp);
-                free(realPathp);
-               if (baseFidp)
-                   smb_ReleaseFID(baseFidp);
-                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
-                    return CM_ERROR_PATH_NOT_COVERED;
-                else
-                    return CM_ERROR_BADSHARENAME;
-            }
-#endif /* DFS_SUPPORT */
-            code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
-                             userp, &req, &scp);
-            if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
-                code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
-                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
-                if (code == 0 && realDirFlag == 1) {
-                    cm_ReleaseSCache(scp);
-                    cm_ReleaseSCache(dscp);
-                    cm_ReleaseUser(userp);
-                    free(realPathp);
-                   if (baseFidp)
-                       smb_ReleaseFID(baseFidp);
-                    return CM_ERROR_EXISTS;
-                }
-            }
-        } else 
-            dscp = NULL;
-    } else {
-        code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                        userp, tidPathp, &req, &scp);
+
+    code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                    userp, tidPathp, &req, &dscp);
+    if (code == 0) {
 #ifdef DFS_SUPPORT
-        if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
-            int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
-            cm_ReleaseSCache(scp);
+        if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
+            cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
+            cm_FreeSpace(spacep);
             free(realPathp);
-           if (baseFidp)
-               smb_ReleaseFID(baseFidp);
+            if (baseFidp)
+                smb_ReleaseFID(baseFidp);
             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
-    }
-
-    if (code == 0) 
-        foundscp = TRUE;
-
-    if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
-        /* look up parent directory */
-        if ( !dscp ) {
-            code = cm_NameI(baseDirp, spacep->data,
-                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                             userp, tidPathp, &req, &dscp);
-#ifdef DFS_SUPPORT
-            if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+        code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
+                         userp, &req, &scp);
+        if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
+
+            code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
+                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
+            if (code == 0 && realDirFlag == 1 &&
+                (createDisp == FILE_OPEN ||
+                 createDisp == FILE_OVERWRITE ||
+                 createDisp == FILE_OVERWRITE_IF)) {
+                cm_ReleaseSCache(scp);
                 cm_ReleaseSCache(dscp);
                 cm_ReleaseUser(userp);
+                cm_FreeSpace(spacep);
                 free(realPathp);
-               if (baseFidp)
-                   smb_ReleaseFID(baseFidp);
-                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
-                    return CM_ERROR_PATH_NOT_COVERED;
-                else
-                    return CM_ERROR_BADSHARENAME;
+                if (baseFidp)
+                    smb_ReleaseFID(baseFidp);
+                return CM_ERROR_EXISTS;
             }
-#endif /* DFS_SUPPORT */
-        } else
-            code = 0;
-        
+        }
+    } else {
+        cm_ReleaseUser(userp);
+        if (baseFidp)
+            smb_ReleaseFID(baseFidp);
+        cm_FreeSpace(spacep);
+        free(realPathp);
+        return CM_ERROR_NOSUCHPATH;
+    }
+
+    if (code == 0)
+        foundscp = TRUE;
+
+    if (code == CM_ERROR_NOSUCHFILE ||
+        code == CM_ERROR_NOSUCHPATH ||
+        code == CM_ERROR_BPLUS_NOMATCH ||
+        (code == 0 && (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)))) {
+        code = 0;
+
         cm_FreeSpace(spacep);
 
         if (baseFidp)
             smb_ReleaseFID(baseFidp);
 
         if (code) {
+            cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
             free(realPathp);
             return code;
@@ -7811,14 +8600,18 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
         if (!lastNamep)
            lastNamep = realPathp;
-        else 
+        else
            lastNamep++;
 
-        if (!smb_IsLegalFilename(lastNamep))
+        if (!smb_IsLegalFilename(lastNamep)) {
+            cm_ReleaseSCache(dscp);
+            cm_ReleaseUser(userp);
+            free(realPathp);
             return CM_ERROR_BADNTFILENAME;
+        }
 
         if (!foundscp) {
-            if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
+            if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF || createDisp == FILE_OPEN_IF) {
                 code = cm_Lookup(dscp, lastNamep,
                                   CM_FLAG_FOLLOW, userp, &req, &scp);
             } else {
@@ -7845,21 +8638,21 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
      * scp is NULL.
      */
     if (code == 0) {
-        code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
-        if (code) {     
-            if (dscp) 
-                cm_ReleaseSCache(dscp);
+        code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
+        if (code) {
+            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+            cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
             return code;
         }
+        checkDoneRequired = 1;
 
         if (createDisp == FILE_CREATE) {
             /* oops, file shouldn't be there */
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
-            if (dscp) 
-                cm_ReleaseSCache(dscp);
+            cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
@@ -7887,10 +8680,10 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                     cm_ReleaseSCache(scp);
                     scp = targetScp;
-                   code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+                   code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
                    if (code) {
-                       if (dscp)
-                           cm_ReleaseSCache(dscp);
+                        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                        cm_ReleaseSCache(dscp);
                        if (scp)
                            cm_ReleaseSCache(scp);
                        cm_ReleaseUser(userp);
@@ -7906,19 +8699,20 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
         /* don't create if not found */
-        if (dscp) 
-            cm_ReleaseSCache(dscp);
+        cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         free(realPathp);
         return CM_ERROR_NOSUCHFILE;
     }
     else if (realDirFlag == 0 || realDirFlag == -1) {
-        osi_assertx(dscp != NULL, "null cm_scache_t");
-        osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
-                  osi_LogSaveString(smb_logp, lastNamep));
+        /* createDisp: FILE_SUPERSEDE, FILE_CREATE, FILE_OPEN_IF, FILE_OVERWRITE_IF */
+        osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
+                  osi_LogSaveClientString(smb_logp, lastNamep));
         openAction = 2;                /* created file */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         setAttr.clientModTime = time(NULL);
+        smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
+
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                           &req);
         if (code == 0) {
@@ -7959,19 +8753,20 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                         }
                     }
                     code = cm_SetAttr(scp, &setAttr, userp, &req);
-                }       
+                }
             }  /* lookup succeeded */
         }
     } else {
-        /* create directory */
-        osi_assertx(dscp != NULL, "null cm_scache_t");
+        /* create directory; createDisp: FILE_CREATE, FILE_OPEN_IF */
         osi_Log1(smb_logp,
-                  "smb_ReceiveNTTranCreate creating directory %s",
-                  osi_LogSaveString(smb_logp, lastNamep));
+                  "smb_ReceiveNTTranCreate creating directory %S",
+                  osi_LogSaveClientString(smb_logp, lastNamep));
         openAction = 2;                /* created directory */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         setAttr.clientModTime = time(NULL);
-        code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
+        smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
+
+        code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
             smb_NotifyChange(FILE_ACTION_ADDED,
                               FILE_NOTIFY_CHANGE_DIR_NAME,
@@ -7986,14 +8781,14 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
              */
             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
                               userp, &req, &scp);
-        }       
+        }
     }
 
     if (code) {
         /* something went wrong creating or truncating the file */
-       if (ldp)
+       if (checkDoneRequired)
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
-       if (scp) 
+       if (scp)
             cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         free(realPathp);
@@ -8014,15 +8809,17 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                 */
                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
                           scp, targetScp);
-               if (ldp)
+               if (checkDoneRequired) {
                    cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                    checkDoneRequired = 0;
+                }
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
         }
 
         if (scp->fileType != CM_SCACHETYPE_FILE) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -8032,7 +8829,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
 
     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
-       if (ldp)
+       if (checkDoneRequired)
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
@@ -8071,13 +8868,13 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         }
 
         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
-        
+
         lock_ObtainWrite(&scp->rw);
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
         lock_ReleaseWrite(&scp->rw);
 
         if (code) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -8090,8 +8887,10 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
 
     /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
-    if (ldp)
+    if (checkDoneRequired) {
        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+        checkDoneRequired = 0;
+    }
 
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
@@ -8113,13 +8912,13 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         fidp->NTopen_dscp = dscp;
        osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
        dscp = NULL;
-        fidp->NTopen_pathp = strdup(lastNamep);
+        fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
     }
     fidp->NTopen_wholepathp = realPathp;
     lock_ReleaseMutex(&fidp->mx);
 
     /* we don't need this any longer */
-    if (dscp) 
+    if (dscp)
         cm_ReleaseSCache(dscp);
 
     cm_Open(scp, 0, userp);
@@ -8163,7 +8962,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((USHORT *)outData) = fidp->fid; outData += 2;        /* fid */
         *((ULONG *)outData) = openAction; outData += 4;
         *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         *((FILETIME *)outData) = ft; outData += 8;     /* creation time */
         *((FILETIME *)outData) = ft; outData += 8;     /* last access time */
         *((FILETIME *)outData) = ft; outData += 8;     /* last write time */
@@ -8172,7 +8971,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
         *((USHORT *)outData) = 0; outData += 2;        /* filetype */
-        *((USHORT *)outData) = 0; outData += 2;        /* dev state */
+        *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
+        outData += 2;  /* dev state */
         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
                                scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
                                scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
@@ -8182,7 +8982,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         parmOffset = 8*4 + 39;
         parmOffset += 1;       /* pad to 4 */
         dataOffset = parmOffset + 104;
-        
+
         parmSlot = 1;
         outp->oddByte = 1;
         /* Total Parameter Count */
@@ -8203,7 +9003,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
         smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
         smb_SetSMBDataLength(outp, 105);
-        
+
         lock_ObtainRead(&scp->rw);
         outData = smb_GetSMBData(outp, NULL);
         outData++;                     /* round to get to parmOffset */
@@ -8212,7 +9012,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((USHORT *)outData) = fidp->fid; outData += 2;        /* fid */
         *((ULONG *)outData) = openAction; outData += 4;
         *((ULONG *)outData) = 0; outData += 4; /* EA error offset */
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
         *((FILETIME *)outData) = ft; outData += 8;     /* creation time */
         *((FILETIME *)outData) = ft; outData += 8;     /* last access time */
         *((FILETIME *)outData) = ft; outData += 8;     /* last write time */
@@ -8221,25 +9021,30 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
         *((USHORT *)outData) = 0; outData += 2;        /* filetype */
-        *((USHORT *)outData) = 0; outData += 2;        /* dev state */
+        *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
+        outData += 2;  /* dev state */
         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
                                scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
                                scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
         outData += 1;  /* is a dir? */
-        memset(outData,0,24); outData += 24; /* Volume ID and file ID */
+        /* Setting the GUID results in failures with cygwin */
+        memset(outData,0,24); outData += 24; /* GUID */
         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
     }
 
-    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
-         LargeIntegerGreaterThanZero(fidp->scp->length) && 
+    if ((fidp->flags & SMB_FID_EXECUTABLE) &&
+         LargeIntegerGreaterThanZero(scp->length) &&
          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
-        cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
-                           fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
-                           userp);
+        prefetch = 1;
     }
     lock_ReleaseRead(&scp->rw);
 
+    if (prefetch)
+        cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
+                           scp->length.LowPart, scp->length.HighPart,
+                           userp, &req);
+
     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
 
     cm_ReleaseUser(userp);
@@ -8255,11 +9060,11 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
        smb_packet_t *outp)
 {
     smb_packet_t *savedPacketp;
-    ULONG filter; 
+    ULONG filter;
     USHORT fid, watchtree;
     smb_fid_t *fidp;
     cm_scache_t *scp;
-        
+
     filter = smb_GetSMBParm(inp, 19) |
              (smb_GetSMBParm(inp, 20) << 16);
     fid = smb_GetSMBParm(inp, 21);
@@ -8267,24 +9072,32 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
 
     fidp = smb_FindFID(vcp, fid, 0);
     if (!fidp) {
-        osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
+        osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
         return CM_ERROR_BADFD;
     }
 
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
+    scp = fidp->scp;
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
 
     /* Create a copy of the Directory Watch Packet to use when sending the
      * notification if in the future a matching change is detected.
      */
     savedPacketp = smb_CopyPacket(inp);
-    smb_HoldVC(vcp);
-    if (savedPacketp->vcp)
-       smb_ReleaseVC(savedPacketp->vcp);
-    savedPacketp->vcp = vcp;
+    if (vcp != savedPacketp->vcp) {
+        smb_HoldVC(vcp);
+        if (savedPacketp->vcp)
+            smb_ReleaseVC(savedPacketp->vcp);
+        savedPacketp->vcp = vcp;
+    }
 
     /* Add the watch to the list of events to send notifications for */
     lock_ObtainMutex(&smb_Dir_Watch_Lock);
@@ -8292,9 +9105,8 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
     smb_Directory_Watches = savedPacketp;
     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
 
-    scp = fidp->scp;
-    osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"", 
-             fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
+    osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
+             fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
     osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
              filter, fid, watchtree);
     if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
@@ -8328,94 +9140,187 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
     else
         scp->flags |= CM_SCACHEFLAG_WATCHED;
     lock_ReleaseWrite(&scp->rw);
+    cm_ReleaseSCache(scp);
     smb_ReleaseFID(fidp);
 
     outp->flags |= SMB_PACKETFLAG_NOSEND;
     return 0;
 }
 
-unsigned char nullSecurityDesc[36] = {
+unsigned char nullSecurityDesc[] = {
     0x01,                              /* security descriptor revision */
     0x00,                              /* reserved, should be zero */
-    0x00, 0x80,                                /* security descriptor control;
-                                         * 0x8000 : self-relative format */
+    0x04, 0x80,                                /* security descriptor control;
+                                         * 0x0004 : null-DACL present - everyone has full access
+                                         * 0x8000 : relative format */
     0x14, 0x00, 0x00, 0x00,            /* offset of owner SID */
-    0x1c, 0x00, 0x00, 0x00,            /* offset of group SID */
+    0x20, 0x00, 0x00, 0x00,            /* offset of group SID */
     0x00, 0x00, 0x00, 0x00,            /* offset of DACL would go here */
     0x00, 0x00, 0x00, 0x00,            /* offset of SACL would go here */
-    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                        /* "null SID" owner SID */
-    0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-                                        /* "null SID" group SID */
-};      
+    0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
+    0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00,
+    0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
+    0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00
+};
 
 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int parmOffset, parmCount, dataOffset, dataCount;
+    int totalParmCount, totalDataCount;
     int parmSlot;
-    int maxData;
+    int maxData, maxParm;
+    int inTotalParm, inTotalData;
+    int inParm, inData;
+    int inParmOffset, inDataOffset;
     char *outData;
     char *parmp;
     USHORT *sparmp;
     ULONG *lparmp;
     USHORT fid;
     ULONG securityInformation;
+    smb_fid_t *fidp;
+    long code = 0;
+    DWORD dwLength;
 
-    parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
+    /*
+     * For details on the meanings of the various
+     * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
+     * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
+     */
+
+    inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
+        | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
+
+    inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
+        | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
+
+    maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
+        | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
+
+    maxData = smb_GetSMBOffsetParm(inp, 7, 1)
+        | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
+
+    inParm = smb_GetSMBOffsetParm(inp, 9, 1)
+        | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
+
+    inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
-    parmp = inp->data + parmOffset;
+
+    inData = smb_GetSMBOffsetParm(inp, 13, 1)
+        | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
+
+    inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
+        | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
+
+    parmp = inp->data + inParmOffset;
     sparmp = (USHORT *) parmp;
     lparmp = (ULONG *) parmp;
 
     fid = sparmp[0];
     securityInformation = lparmp[1];
 
-    maxData = smb_GetSMBOffsetParm(inp, 7, 1)
-        | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
+    fidp = smb_FindFID(vcp, fid, 0);
+    if (!fidp) {
+        osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
+                 vcp, fid);
+        return CM_ERROR_BADFD;
+    }
 
-    if (maxData < 36)
-        dataCount = 0;
-    else
-        dataCount = 36;
+    lock_ObtainMutex(&fidp->mx);
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+    lock_ReleaseMutex(&fidp->mx);
+
+    osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
+             fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
+              securityInformation);
+
+    smb_ReleaseFID(fidp);
+
+    if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
+    {
+        code = CM_ERROR_BAD_LEVEL;
+        goto done;
+    }
+
+    dwLength = sizeof( nullSecurityDesc);
+
+    totalDataCount = dwLength;
+    totalParmCount = 4;
+
+    if (maxData >= totalDataCount) {
+        dataCount = totalDataCount;
+        parmCount = min(totalParmCount, maxParm);
+    } else if (maxParm >= totalParmCount) {
+        totalDataCount = dataCount = 0;
+        parmCount = totalParmCount;
+    } else {
+        totalDataCount = dataCount = 0;
+        totalParmCount = parmCount = 0;
+    }
 
     /* out parms */
     parmOffset = 8*4 + 39;
     parmOffset += 1;   /* pad to 4 */
-    parmCount = 4;
+
     dataOffset = parmOffset + parmCount;
 
     parmSlot = 1;
     outp->oddByte = 1;
     /* Total Parameter Count */
-    smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
+    smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
     /* Total Data Count */
-    smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
+    smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
     /* Parameter Count */
     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
     /* Parameter Offset */
-    smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
+    smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
     /* Parameter Displacement */
     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
     /* Data Count */
     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
     /* Data Offset */
-    smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
+    smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
     /* Data Displacement */
     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
-    smb_SetSMBParmByte(outp, parmSlot, 0);     /* Setup Count */
-    smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
+    /* Setup Count */
+    smb_SetSMBParmByte(outp, parmSlot, 0);
 
-    outData = smb_GetSMBData(outp, NULL);
-    outData++;                 /* round to get to parmOffset */
-    *((ULONG *)outData) = 36; outData += 4;    /* length */
+    if (parmCount == totalParmCount && dwLength == dataCount) {
+        smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
 
-    if (maxData >= 36) {
-        memcpy(outData, nullSecurityDesc, 36);
-        outData += 36;
-        return 0;
-    } else
-        return CM_ERROR_BUFFERTOOSMALL;
+        /* Data */
+        outData = smb_GetSMBData(outp, NULL);
+        outData++;                     /* round to get to dataOffset */
+
+        *((ULONG *)outData) = dataCount; outData += 4; /* SD Length (4 bytes) */
+        memcpy(outData, nullSecurityDesc, dataCount);
+        outData += dataCount;
+
+        code = 0;
+    } else if (parmCount >= 4) {
+        smb_SetSMBDataLength(outp, 1 + parmCount);
+
+        /* Data */
+        outData = smb_GetSMBData(outp, NULL);
+        outData++;                     /* round to get to dataOffset */
+
+        *((ULONG *)outData) = dwLength; outData += 4;  /* SD Length (4 bytes) */
+        code = CM_ERROR_BUFFERTOOSMALL;
+    } else {
+        smb_SetSMBDataLength(outp, 0);
+        code = CM_ERROR_BUFFER_OVERFLOW;
+    }
+
+  done:
+    return code;
 }
 
 /* SMB_COM_NT_TRANSACT
@@ -8433,7 +9338,7 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* We can handle long names */
     if (vcp->flags & SMB_VCFLAG_USENT)
         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
-        
+
     switch (function) {
     case 1:                     /* NT_TRANSACT_CREATE */
         return smb_ReceiveNTTranCreate(vcp, inp, outp);
@@ -8457,7 +9362,7 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
         break;
     }
-    return CM_ERROR_INVAL;
+    return CM_ERROR_BADOP;
 }
 
 /*
@@ -8467,15 +9372,15 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  * If we don't know the file name (i.e. a callback break), filename is
  * NULL, and we return a zero-length list.
  *
- * At present there is not a single call to smb_NotifyChange that 
- * has the isDirectParent parameter set to FALSE.  
+ * At present there is not a single call to smb_NotifyChange that
+ * has the isDirectParent parameter set to FALSE.
  */
 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
-       cm_scache_t *dscp, char *filename, char *otherFilename,
+       cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
        BOOL isDirectParent)
 {
     smb_packet_t *watch, *lastWatch, *nextWatch;
-    ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
+    ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
     char *outData, *oldOutData;
     ULONG filter;
     USHORT fid, wtree;
@@ -8491,8 +9396,8 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
     }
 
-    osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
-             osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
+    osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
+             osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
     if (action == 0)
        osi_Log0(smb_logp,"      FILE_ACTION_NONE");
     if (action == FILE_ACTION_ADDED)
@@ -8529,24 +9434,23 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             lastWatch = watch;
             watch = watch->nextp;
             continue;
-        }      
+        }
 
         if (fidp->scp != dscp ||
             fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
             (filter & notifyFilter) == 0 ||
-            (!isDirectParent && !wtree)) 
+            (!isDirectParent && !wtree))
         {
             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
-            smb_ReleaseFID(fidp);
             lastWatch = watch;
             watch = watch->nextp;
+            smb_ReleaseFID(fidp);
             continue;
         }
-        smb_ReleaseFID(fidp);
 
         osi_Log4(smb_logp,
-                  "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
-                  fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
+                  "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
+                  fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
        if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
            osi_Log0(smb_logp, "      Notify Change File Name");
        if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
@@ -8571,7 +9475,7 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
            osi_Log0(smb_logp, "      Notify Change Stream Size");
        if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
            osi_Log0(smb_logp, "      Notify Change Stream Write");
-                    
+
        /* A watch can only be notified once.  Remove it from the list */
         nextWatch = watch->nextp;
         if (watch == smb_Directory_Watches)
@@ -8595,14 +9499,14 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
         ((smb_t *) watch)->wct = 0;
 
         /* out parms */
-        if (filename == NULL)
+        if (filename == NULL) {
             parmCount = 0;
-        else {
-            nameLen = (ULONG)strlen(filename);
+        } else {
+            nameLen = (ULONG)cm_ClientStrLen(filename);
             parmCount = 3*4 + nameLen*2;
             parmCount = (parmCount + 3) & ~3;  /* pad to 4 */
             if (twoEntries) {
-                otherNameLen = (ULONG)strlen(otherFilename);
+                otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
                 oldParmCount = parmCount;
                 parmCount += 3*4 + otherNameLen*2;
                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
@@ -8636,7 +9540,6 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
         smb_SetSMBDataLength(watch, parmCount + 1);
 
         if (parmCount != 0) {
-            char * p;
             outData = smb_GetSMBData(watch, NULL);
             outData++; /* round to get to parmOffset */
             oldOutData = outData;
@@ -8646,12 +9549,10 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             /* Action */
             *((DWORD *)outData) = nameLen*2; outData += 4;
             /* File Name Length */
-            p = strdup(filename);
-            if (smb_StoreAnsiFilenames)
-                CharToOem(p,p);
-            mbstowcs((WCHAR *)outData, p, nameLen);
-            free(p);
+
+            smb_UnparseString(watch, outData, filename, NULL, 0);
             /* File Name */
+
             if (twoEntries) {
                 outData = oldOutData + oldParmCount;
                 *((DWORD *)outData) = 0; outData += 4;
@@ -8660,13 +9561,9 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
                 /* Action */
                 *((DWORD *)outData) = otherNameLen*2;
                 outData += 4;  /* File Name Length */
-                p = strdup(otherFilename);
-                if (smb_StoreAnsiFilenames)
-                    CharToOem(p,p);
-                mbstowcs((WCHAR *)outData, p, otherNameLen);   /* File Name */
-                free(p);
-            }       
-        }       
+                smb_UnparseString(watch, outData, otherFilename, NULL, 0);
+            }
+        }
 
         /*
          * If filename is null, we don't know the cause of the
@@ -8686,10 +9583,12 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
 
         smb_SendPacket(watch->vcp, watch);
         smb_FreePacket(watch);
+
+        smb_ReleaseFID(fidp);
         watch = nextWatch;
     }
     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
-}       
+}
 
 /* SMB_COM_NT_CANCEL */
 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
@@ -8720,23 +9619,25 @@ long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
 
             if (vcp != watch->vcp)
-                osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x", 
+                osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
                           vcp, watch->vcp);
 
             fidp = smb_FindFID(vcp, fid, 0);
             if (fidp) {
-                osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
-                          fid, watchtree,
-                          osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
+                osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
+                         fid, watchtree,
+                         (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
 
                 scp = fidp->scp;
                osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
-                lock_ObtainWrite(&scp->rw);
-                if (watchtree)
-                    scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
-                else
-                    scp->flags &= ~CM_SCACHEFLAG_WATCHED;
-                lock_ReleaseWrite(&scp->rw);
+                if (scp) {
+                    lock_ObtainWrite(&scp->rw);
+                   if (watchtree)
+                        scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
+                    else
+                       scp->flags &= ~CM_SCACHEFLAG_WATCHED;
+                    lock_ReleaseWrite(&scp->rw);
+                }
                 smb_ReleaseFID(fidp);
             } else {
                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
@@ -8775,7 +9676,7 @@ long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *oldPathp, *newPathp;
+    clientchar_t *oldPathp, *newPathp;
     long code = 0;
     char * tp;
     int attrs;
@@ -8791,27 +9692,32 @@ long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     tp = smb_GetSMBData(inp, NULL);
     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
+    if (!oldPathp)
+        return CM_ERROR_BADSMB;
     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
+    if (!newPathp)
+        return CM_ERROR_BADSMB;
 
-    osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
-             osi_LogSaveString(smb_logp, oldPathp),
-             osi_LogSaveString(smb_logp, newPathp),
-             ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
+    osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
+             osi_LogSaveClientString(smb_logp, oldPathp),
+             osi_LogSaveClientString(smb_logp, newPathp),
+             ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
 
     if (rename_type == RENAME_FLAG_RENAME) {
         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
-    } else { /* RENAME_FLAG_HARD_LINK */
+    } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
         code = smb_Link(vcp,inp,oldPathp,newPathp);
-    }
+    } else
+        code = CM_ERROR_BADOP;
     return code;
 }
 
 void smb3_Init()
 {
-    lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
+    lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
 }
 
-cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
+cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
 {
     smb_username_t *unp;
     cm_user_t *     userp;
@@ -8821,9 +9727,9 @@ cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
         lock_ObtainMutex(&unp->mx);
         unp->userp = cm_NewUser();
         lock_ReleaseMutex(&unp->mx);
-        osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
+        osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
     }  else    {
-        osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
+        osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
     }
     userp = unp->userp;
     cm_HoldUser(userp);
@@ -8831,3 +9737,23 @@ cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
     return userp;
 }
 
+cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
+{
+    smb_username_t *unp;
+    cm_user_t *     userp;
+
+    unp = smb_FindUserByName(usern, machine, flags);
+    if (!unp->userp) {
+        lock_ObtainMutex(&unp->mx);
+        unp->flags |= SMB_USERNAMEFLAG_SID;
+        unp->userp = cm_NewUser();
+        lock_ReleaseMutex(&unp->mx);
+        osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
+    }  else    {
+        osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
+    }
+    userp = unp->userp;
+    cm_HoldUser(userp);
+    smb_ReleaseUsername(unp);
+    return userp;
+}