Windows: do not leak space allocation
[openafs.git] / src / WINNT / afsd / smb3.c
index 27c6e1a..2dcc708 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,39 +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;
 }
 
-unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
-{
-    if (chainpp) {
-        /* skip over null-terminated string */
-        *chainpp = inp + strlen(inp) + 1;
-    }
-    return inp;
-}   
-
-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) {
@@ -163,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;
         }
@@ -187,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"
@@ -209,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,
@@ -223,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;
     }
 
@@ -249,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) {
@@ -263,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 */
@@ -278,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;
@@ -301,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;
@@ -315,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;
 
@@ -342,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;
         }
@@ -384,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));
 
@@ -408,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));
 
@@ -440,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;
     }
@@ -514,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;
@@ -527,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;
@@ -538,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);
 
@@ -584,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,
@@ -607,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 */
@@ -621,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]
@@ -640,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;
@@ -651,31 +809,32 @@ 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
  * UID in subsequent packets.  Though in practice we get one anyway.
  */
+/* SMB_COM_SESSION_SETUP_ANDX */
 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *tp;
@@ -683,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);
             }
@@ -708,38 +897,40 @@ 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;
+
                 smb_SetSMBParm(outp, 2, 0);
                 smb_SetSMBParm(outp, 3, secBlobOutLength);
-                smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+
                 tp = smb_GetSMBData(outp, NULL);
                 if (secBlobOutLength) {
                     memcpy(tp, secBlobOut, secBlobOutLength);
                     free(secBlobOut);
                     tp += secBlobOutLength;
-                }      
-                memcpy(tp,smb_ServerOS,smb_ServerOSLength);
-                tp += smb_ServerOSLength;
-                memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
-                tp += smb_ServerLanManagerLength;
-                memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
-                tp += smb_ServerDomainNameLength;
+                    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);
+
+                smb_SetSMBDataLength(outp, cb_data);
             }
 
             /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
         } 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 */
@@ -747,20 +938,22 @@ 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;
             csPwd = tp;
             tp += csPwdLength;
 
-            accountName = smb_ParseString(tp, &tp);
-            primaryDomain = smb_ParseString(tp, NULL);
+            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 */
@@ -776,38 +969,38 @@ 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);
         ciPwd = tp;
         tp += ciPwdLength;
 
-        accountName = smb_ParseString(tp, &tp);
-        primaryDomain = smb_ParseString(tp, NULL);
+        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 */
@@ -821,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"));
         }
     }
 
@@ -835,7 +1028,13 @@ 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) {
+            vcp->flags |= SMB_VCFLAG_USEUNICODE;
+        }
+#endif
         lock_ReleaseMutex(&vcp->mx);
     }
 
@@ -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,13 @@ 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;
        lock_ReleaseMutex(&unp->mx);
 
         /* Create a new UID and cm_user_t structure */
@@ -888,7 +1100,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,48 +1123,56 @@ 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);
 
     if (vcp->flags & SMB_VCFLAG_USENT) {
         if (smb_authType == SMB_AUTH_EXTENDED) {
+            size_t cb_data = 0;
+
             smb_SetSMBParm(outp, 3, secBlobOutLength);
-            smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+
             tp = smb_GetSMBData(outp, NULL);
             if (secBlobOutLength) {
                 memcpy(tp, secBlobOut, secBlobOutLength);
                 free(secBlobOut);
                 tp += secBlobOutLength;
-            }  
-            memcpy(tp,smb_ServerOS,smb_ServerOSLength);
-            tp += smb_ServerOSLength;
-            memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
-            tp += smb_ServerLanManagerLength;
-            memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
-            tp += smb_ServerDomainNameLength;
+                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);
+
+            smb_SetSMBDataLength(outp, cb_data);
         } else {
             smb_SetSMBDataLength(outp, 0);
         }
     } else {
         if (smb_authType == SMB_AUTH_EXTENDED) {
-            smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
+            size_t cb_data = 0;
+
             tp = smb_GetSMBData(outp, NULL);
-            memcpy(tp,smb_ServerOS,smb_ServerOSLength);
-            tp += smb_ServerOSLength;
-            memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
-            tp += smb_ServerLanManagerLength;
-            memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
-            tp += smb_ServerDomainNameLength;
+
+            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);
+
+            smb_SetSMBDataLength(outp, cb_data);
         } else {
             smb_SetSMBDataLength(outp, 0);
         }
     }
 
+    if (secSidString)
+        LocalFree(secSidString);
     return 0;
 }
 
+/* SMB_COM_LOGOFF_ANDX */
 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_user_t *uidp;
@@ -962,8 +1182,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;
@@ -990,7 +1210,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);
@@ -1000,42 +1220,44 @@ long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 #define SMB_SUPPORT_SEARCH_BITS        0x0001
 #define SMB_SHARE_IS_IN_DFS            0x0002
 
+/* SMB_COM_TREE_CONNECT_ANDX */
 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     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 */
     tp = smb_GetSMBData(inp, NULL);
-    passwordp = smb_ParseString(tp, &tp);
-    pathp = smb_ParseString(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
-    servicep = smb_ParseString(tp, &tp);
-
-    tp = strrchr(pathp, '\\');
-    if (!tp) {
+    passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
+    pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
+
+    slashp = cm_ClientStrRChr(pathp, '\\');
+    if (!slashp) {
         return CM_ERROR_BADSMB;
     }
-    strcpy(shareName, tp+1);
+    cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
 
-    osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
-             osi_LogSaveString(smb_logp, pathp),
-             osi_LogSaveString(smb_logp, shareName));
+    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;
@@ -1051,12 +1273,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)
@@ -1081,9 +1303,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);
@@ -1095,7 +1317,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);
@@ -1104,18 +1326,16 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     ((smb_t *)inp)->tid = newTid;
     tp = smb_GetSMBData(outp, NULL);
     if (!ipc) {
-        /* XXX - why is this a drive letter? */
-        *tp++ = 'A';
-        *tp++ = ':';
-        *tp++ = 0;
-        *tp++ = 'A';
-        *tp++ = 'F';
-        *tp++ = 'S';
-        *tp++ = 0;
-        smb_SetSMBDataLength(outp, 7);
+        size_t 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 {
-        strcpy(tp, "IPC");
-        smb_SetSMBDataLength(outp, 4);
+        size_t cb_data = 0;
+
+        tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
+        smb_SetSMBDataLength(outp, cb_data);
     }
 
     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
@@ -1127,7 +1347,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)
@@ -1137,11 +1357,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));
@@ -1167,18 +1387,22 @@ smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
         tp->com = 0x32;
     }
     tp->flags |= SMB_TRAN2PFLAG_ALLOC;
+#ifdef SMB_UNICODE
+    if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
+        tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
+#endif
     return tp;
 }
 
 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);
@@ -1211,7 +1435,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)
@@ -1225,15 +1449,49 @@ 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;
+
+        ns = t2p->stringsp;
+        t2p->stringsp = ns->nextp;
+        cm_FreeSpace(ns);
+    }
     free(t2p);
 }
 
+clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
+                                    char ** chainpp, int flags)
+{
+    size_t cb;
+
+#ifdef SMB_UNICODE
+    if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    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;
+    }
+
+    return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
+                              inp, &cb, chainpp, flags);
+}
+
 /* called with a VC, an input packet to respond to, and an error code.
  * 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;
@@ -1251,7 +1509,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;
@@ -1271,10 +1529,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)
 {
@@ -1300,6 +1558,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);
+
+           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 */
@@ -1326,11 +1608,87 @@ 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 */
 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tran2Packet_t *asp;
@@ -1348,7 +1706,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);
@@ -1358,9 +1716,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);
@@ -1368,7 +1726,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;
@@ -1376,11 +1734,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);
@@ -1392,7 +1765,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 )
@@ -1408,27 +1781,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.
@@ -1453,31 +1890,32 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
-/* ANSI versions.  The unicode versions support arbitrary length
-   share names, but we don't support unicode yet. */
+/* ANSI versions. */
+
+#pragma pack(push, 1)
 
 typedef struct smb_rap_share_info_0 {
-    char        shi0_netname[13];
+    BYTE                shi0_netname[13];
 } smb_rap_share_info_0_t;
 
 typedef struct smb_rap_share_info_1 {
-    char                       shi1_netname[13];
-    char                       shi1_pad;
+    BYTE                shi1_netname[13];
+    BYTE                shi1_pad;
     WORD                       shi1_type;
     DWORD                      shi1_remark; /* char *shi1_remark; data offset */
 } smb_rap_share_info_1_t;
 
 typedef struct smb_rap_share_info_2 {
-    char                       shi2_netname[13];
-    char                       shi2_pad;
-    unsigned short             shi2_type;
+    BYTE               shi2_netname[13];
+    BYTE               shi2_pad;
+    WORD               shi2_type;
     DWORD                      shi2_remark; /* char *shi2_remark; data offset */
-    unsigned short             shi2_permissions;
-    unsigned short             shi2_max_uses;
-    unsigned short             shi2_current_uses;
+    WORD               shi2_permissions;
+    WORD               shi2_max_uses;
+    WORD               shi2_current_uses;
     DWORD                      shi2_path;  /* char *shi2_path; data offset */
-    unsigned short             shi2_passwd[9];
-    unsigned short             shi2_pad2;
+    WORD               shi2_passwd[9];
+    WORD               shi2_pad2;
 } smb_rap_share_info_2_t;
 
 #define SMB_RAP_MAX_SHARES 512
@@ -1488,18 +1926,17 @@ typedef struct smb_rap_share_list {
     smb_rap_share_info_0_t * shares;
 } smb_rap_share_list_t;
 
+#pragma pack(pop)
+
 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++;
@@ -1508,8 +1945,9 @@ 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)
 {
     smb_tran2Packet_t *outp;
@@ -1530,7 +1968,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;
@@ -1538,10 +1976,21 @@ 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) */
-    (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
-    (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
+
+    {
+        clientchar_t * cdescp;
+
+        cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+        if (cm_ClientStrCmp(cdescp,  _C("WrLeh")))
+            return CM_ERROR_INVAL;
+        cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+        if (cm_ClientStrCmp(cdescp,  _C("B13BWz")))
+            return CM_ERROR_INVAL;
+    }
+
     infoLevel = tp[0];
     bufsize = tp[1];
 
@@ -1549,6 +1998,18 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
         return CM_ERROR_INVAL;
     }
 
+    /* We are supposed to use the same ASCII data structure even if
+       Unicode is negotiated, which ultimately means that the share
+       names that we return must be at most 13 characters in length,
+       including the NULL terminator.
+
+       The RAP specification states that shares with names longer than
+       12 characters should not be included in the enumeration.
+       However, since we support prefix cell references and since many
+       cell names are going to exceed 12 characters, we lie and send
+       the first 12 characters.
+    */
+
     /* first figure out how many shares there are */
     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                       KEY_QUERY_VALUE, &hkParam);
@@ -1578,16 +2039,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);
 
@@ -1603,7 +2065,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 */
@@ -1613,7 +2075,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++;
@@ -1623,9 +2086,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);
-            if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
-                strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
+            rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
+            if (rv == ERROR_SUCCESS &&
+                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++;
@@ -1641,17 +2107,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;
@@ -1673,11 +2141,12 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     return code;
 }
 
+/* RAP NetShareGetInfo */
 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     smb_tran2Packet_t *outp;
     unsigned short * tp;
-    char * shareName;
+    clientchar_t * shareName;
     BOOL shareFound = FALSE;
     unsigned short infoLevel;
     unsigned short bufsize;
@@ -1693,15 +2162,30 @@ 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) */
-    (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
-    (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
-    shareName = smb_ParseString( (char *) tp, (char **) &tp);
+
+    {
+        clientchar_t * cdescp;
+
+        cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+        if (cm_ClientStrCmp(cdescp,  _C("zWrLh")))
+
+            return CM_ERROR_INVAL;
+
+        cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+        if (cm_ClientStrCmp(cdescp,  _C("B13")) &&
+            cm_ClientStrCmp(cdescp,  _C("B13BWz")) &&
+            cm_ClientStrCmp(cdescp,  _C("B13BWzWWWzB9B")))
+
+            return CM_ERROR_INVAL;
+    }
+    shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
+
     infoLevel = *tp++;
     bufsize = *tp++;
-    
+
     totalParam = 6;
 
     if (infoLevel == 0)
@@ -1713,7 +2197,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) {
@@ -1732,10 +2216,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) {
@@ -1745,7 +2229,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;
                 }
@@ -1766,18 +2250,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;
@@ -1793,16 +2276,19 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     return code;
 }
 
+#pragma pack(push, 1)
+
 typedef struct smb_rap_wksta_info_10 {
     DWORD      wki10_computername;     /*char *wki10_computername;*/
     DWORD      wki10_username; /* char *wki10_username; */
     DWORD      wki10_langroup; /* char *wki10_langroup;*/
-    unsigned char      wki10_ver_major;
-    unsigned char      wki10_ver_minor;
+    BYTE       wki10_ver_major;
+    BYTE       wki10_ver_minor;
     DWORD      wki10_logon_domain;     /*char *wki10_logon_domain;*/
     DWORD      wki10_oth_domains; /* char *wki10_oth_domains;*/
 } smb_rap_wksta_info_10_t;
 
+#pragma pack(pop)
 
 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
@@ -1818,17 +2304,30 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     smb_user_t *uidp;
 
     tp = p->parmsp + 1; /* Skip over function number */
-    (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
-    (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
-    infoLevel = *tp++;
-    bufsize = *tp++;
 
-    if (infoLevel != 10) {
-        return CM_ERROR_INVAL;
+    {
+        clientchar_t * cdescp;
+
+        cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+                                       SMB_STRF_FORCEASCII);
+        if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
+            return CM_ERROR_INVAL;
+
+        cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+                                       SMB_STRF_FORCEASCII);
+        if (cm_ClientStrCmp(cdescp,  _C("zzzBBzz")))
+            return CM_ERROR_INVAL;
+    }
+
+    infoLevel = *tp++;
+    bufsize = *tp++;
+
+    if (infoLevel != 10) {
+        return CM_ERROR_INVAL;
     }
 
     totalParams = 6;
-       
+
     /* infolevel 10 */
     totalData = sizeof(*info) +                /* info */
         MAX_COMPUTERNAME_LENGTH +      /* wki10_computername */
@@ -1846,7 +2345,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);
@@ -1854,14 +2353,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 */
@@ -1869,7 +2369,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);
@@ -1885,18 +2386,22 @@ long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     return code;
 }
 
+#pragma pack(push, 1)
+
 typedef struct smb_rap_server_info_0 {
-    char    sv0_name[16];
+    BYTE    sv0_name[16];
 } smb_rap_server_info_0_t;
 
 typedef struct smb_rap_server_info_1 {
-    char            sv1_name[16];
-    char            sv1_version_major;
-    char            sv1_version_minor;
-    unsigned long   sv1_type;
-    DWORD           *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
+    BYTE            sv1_name[16];
+    BYTE            sv1_version_major;
+    BYTE            sv1_version_minor;
+    DWORD           sv1_type;
+    DWORD           sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
 } smb_rap_server_info_1_t;
 
+#pragma pack(pop)
+
 char smb_ServerComment[] = "OpenAFS Client";
 int smb_ServerCommentLen = sizeof(smb_ServerComment);
 
@@ -1918,8 +2423,21 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
     char * cstrp;
 
     tp = p->parmsp + 1; /* Skip over function number */
-    (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
-    (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
+
+    {
+        clientchar_t * cdescp;
+
+        cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
+                                       SMB_STRF_FORCEASCII);
+        if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
+            return CM_ERROR_INVAL;
+        cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
+                                       SMB_STRF_FORCEASCII);
+        if (cm_ClientStrCmp(cdescp,  _C("B16")) ||
+            cm_ClientStrCmp(cdescp,  _C("B16BBDz")))
+            return CM_ERROR_INVAL;
+    }
+
     infoLevel = *tp++;
     bufsize = *tp++;
 
@@ -1929,7 +2447,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);
 
@@ -1941,24 +2459,24 @@ 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;
 
         info1->sv1_version_major = 5;
         info1->sv1_version_minor = 1;
-        info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
+        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);
@@ -1973,6 +2491,7 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
     return code;
 }
 
+/* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tran2Packet_t *asp;
@@ -1986,10 +2505,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);
@@ -1999,9 +2519,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);
@@ -2009,7 +2529,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;
@@ -2033,7 +2553,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 )
@@ -2058,6 +2578,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);
@@ -2077,6 +2599,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);
     }
@@ -2091,9 +2653,10 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
+/* 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;
@@ -2102,10 +2665,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;
@@ -2114,14 +2676,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 */
 
@@ -2133,31 +2697,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 = (char *) (&p->parmsp[14]);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
-    
+
+    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;
@@ -2165,13 +2749,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 */
@@ -2181,13 +2765,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 */
@@ -2195,6 +2779,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;
@@ -2202,7 +2810,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);
@@ -2213,29 +2821,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) {
@@ -2243,17 +2839,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 */
 
@@ -2261,9 +2858,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);
@@ -2274,6 +2871,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);
@@ -2283,21 +2883,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);
@@ -2307,7 +2904,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);
@@ -2321,13 +2918,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);
@@ -2338,14 +2935,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
@@ -2363,24 +2962,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;
@@ -2409,7 +3008,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 */
@@ -2418,12 +3017,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;
@@ -2435,7 +3034,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 */
@@ -2444,7 +3043,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);
@@ -2452,17 +3051,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 */
@@ -2474,7 +3073,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)
 {
@@ -2484,48 +3083,25 @@ 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;
 }
 
+/* TRANS2_QUERY_FS_INFORMATION */
 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     smb_tran2Packet_t *outp;
     smb_tran2QFSInfo_t qi;
     int responseSize;
-    static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
-        
-    osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
+    size_t sz = 0;
 
-    switch (p->parmsp[0]) {
-    case SMB_INFO_ALLOCATION: 
-       responseSize = sizeof(qi.u.allocInfo); 
-       break;
-    case SMB_INFO_VOLUME: 
-       responseSize = sizeof(qi.u.volumeInfo); 
-       break;
-    case SMB_QUERY_FS_VOLUME_INFO: 
-       responseSize = sizeof(qi.u.FSvolumeInfo); 
-       break;
-    case SMB_QUERY_FS_SIZE_INFO: 
-       responseSize = sizeof(qi.u.FSsizeInfo); 
-       break;
-    case SMB_QUERY_FS_DEVICE_INFO: 
-       responseSize = sizeof(qi.u.FSdeviceInfo); 
-       break;
-    case SMB_QUERY_FS_ATTRIBUTE_INFO: 
-       responseSize = sizeof(qi.u.FSattributeInfo); 
-       break;
-    case SMB_INFO_UNIX:        /* CIFS Unix Info */
-    case SMB_INFO_MACOS:       /* Mac FS Info */
-    default: 
-       return CM_ERROR_BADOP;
-    }
+    osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
 
-    outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
     switch (p->parmsp[0]) {
-    case SMB_INFO_ALLOCATION: 
+    case SMB_INFO_ALLOCATION:
         /* alloc info */
+       responseSize = sizeof(qi.u.allocInfo);
+
         qi.u.allocInfo.FSID = 0;
         qi.u.allocInfo.sectorsPerAllocUnit = 1;
         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
@@ -2533,25 +3109,37 @@ 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;
-        qi.u.volumeInfo.vnCount = 4;
+        qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
+        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));
-        memcpy(qi.u.volumeInfo.label, "AFS", 4);
+        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 */
-        memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
+       responseSize = sizeof(qi.u.FSvolumeInfo);
+
+        {
+            FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
+            memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
+        }
+
         qi.u.FSvolumeInfo.vsn = 1234;
-        qi.u.FSvolumeInfo.vnCount = 8;
-        memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
+        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);
+
         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
        qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
@@ -2560,17 +3148,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);
+
         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
@@ -2578,12 +3170,30 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
          *        despite our protestations to the contrary.
          */
         qi.u.FSattributeInfo.attributes = 0x4003;
-        qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
-        qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
-        memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
+        /* The maxCompLength is supposed to be in bytes */
+#ifdef SMB_UNICODE
+        qi.u.FSattributeInfo.attributes |= 0x04;
+#endif
+        qi.u.FSattributeInfo.maxCompLength = 255;
+        smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
+        qi.u.FSattributeInfo.FSnameLength = sz;
+
+       responseSize =
+            sizeof(qi.u.FSattributeInfo.attributes) +
+            sizeof(qi.u.FSattributeInfo.maxCompLength) +
+            sizeof(qi.u.FSattributeInfo.FSnameLength) +
+            sz;
+
         break;
-    }   
-        
+
+    case SMB_INFO_UNIX:        /* CIFS Unix Info */
+    case SMB_INFO_MACOS:       /* Mac FS Info */
+    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;
@@ -2603,37 +3213,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;
@@ -2641,19 +3261,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 */
@@ -2678,6 +3302,7 @@ long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
     return code;
 }
 
+/* TRANS2_QUERY_PATH_INFORMATION */
 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     smb_tran2Packet_t *outp;
@@ -2688,27 +3313,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];
-    unsigned int len;
+    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);
@@ -2716,24 +3341,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 = (char *)(&p->parmsp[3]);
-    if (smb_StoreAnsiFilenames)
-       OemToChar(pathp,pathp);
-    osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
-              osi_LogSaveString(smb_logp, pathp));
+    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_LogSaveClientString(smb_logp, pathp));
 
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
 
@@ -2741,8 +3367,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.
@@ -2751,8 +3376,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);
@@ -2762,12 +3387,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
      *
@@ -2784,12 +3413,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,
@@ -2797,11 +3427,12 @@ 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)
@@ -2831,9 +3462,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);
@@ -2850,7 +3486,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;
@@ -2858,14 +3494,18 @@ 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;
 
     /* now we have the status in the cache entry, and everything is locked.
      * Marshall the output data.
@@ -2874,25 +3514,22 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
         code = cm_GetShortName(pathp, userp, &req,
                                 tidPathp, scp->fid.vnode, shortName,
-                                (size_t *) &len);
+                               &len);
         if (code) {
             goto done;
         }
 
-       qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
-
-        goto done;
+        smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
+       qpi.u.QPfileAltNameInfo.fileNameLength = len;
+        responseSize = sizeof(unsigned long) + len;
     }
     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
-       len = (unsigned int)strlen(lastComp);
-       qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
-
-        goto done;
+        smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
+       qpi.u.QPfileNameInfo.fileNameLength = len;
+        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;
@@ -2903,7 +3540,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;
@@ -2913,20 +3550,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);
@@ -2938,7 +3577,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;
@@ -2949,29 +3594,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;
-       len = (unsigned int)strlen(lastComp);
-       qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
+
+        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) {
@@ -2985,6 +3670,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return 0;
 }
 
+/* TRANS2_SET_PATH_INFORMATION */
 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
 #if 0
@@ -2992,51 +3678,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 = (char *)(&p->parmsp[3]);
-    if (smb_StoreAnsiFilenames)
-       OemToChar(pathp,pathp);
-    osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
-              osi_LogSaveString(smb_logp, pathp));
+    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_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);
@@ -3059,12 +3743,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,
@@ -3072,11 +3757,12 @@ 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)
@@ -3105,33 +3791,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);
 
@@ -3155,29 +3828,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;
@@ -3185,26 +3853,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);
 
@@ -3212,6 +3878,7 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
 #endif
 }
 
+/* TRANS2_QUERY_FILE_INFORMATION */
 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     smb_tran2Packet_t *outp;
@@ -3229,40 +3896,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);
 
@@ -3270,14 +3945,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;
@@ -3288,7 +3962,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);
@@ -3300,7 +3974,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;
@@ -3313,7 +3987,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);
@@ -3322,8 +3996,8 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         qfi.u.QFeaInfo.eaSize = 0;
     }
     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
-        unsigned long len;
-        char *name;
+        size_t len = 0;
+        clientchar_t *name;
 
        lock_ReleaseRead(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
@@ -3331,13 +4005,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);
-        len = (unsigned long)strlen(name);
-        outp->totalData = ((len+1)*2) + 4;     /* this is actually what we want to return */
-        qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
-        mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
+
+        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:
@@ -3357,8 +4050,10 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     smb_FreeTran2Packet(outp);
 
     return 0;
-}       
+}
 
+
+/* TRANS2_SET_FILE_INFORMATION */
 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     long code = 0;
@@ -3370,27 +4065,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);
@@ -3398,19 +4088,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 && 
-       !(fidp->flags & SMB_FID_OPENDELETE)) {
-       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);
+    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",
+                 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);
@@ -3433,7 +4131,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;
@@ -3465,26 +4163,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;
@@ -3502,7 +4200,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,
@@ -3512,17 +4210,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));
@@ -3532,57 +4230,63 @@ 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);
 
     return 0;
 }
 
-long 
+/* TRANS2_FSCTL */
+long
 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
     return CM_ERROR_BADOP;
 }
 
-long 
+/* TRANS2_IOCTL2 */
+long
 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
     return CM_ERROR_BADOP;
 }
 
-long 
+/* TRANS2_FIND_NOTIFY_FIRST */
+long
 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
     return CM_ERROR_BADOP;
 }
 
-long 
+/* TRANS2_FIND_NOTIFY_NEXT */
+long
 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
     return CM_ERROR_BADOP;
 }
 
-long 
+/* TRANS2_CREATE_DIRECTORY */
+long
 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
     return CM_ERROR_BADOP;
 }
 
-long 
+/* TRANS2_SESSION_SETUP */
+long
 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
@@ -3599,7 +4303,8 @@ struct smb_v2_referral {
     USHORT NetworkAddressOffset;
 };
 
-long 
+/* TRANS2_GET_DFS_REFERRAL */
+long
 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     /* This is a UNICODE only request (bit15 of Flags2) */
@@ -3614,8 +4319,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;
@@ -3625,31 +4330,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);
@@ -3657,36 +4360,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) {
@@ -3697,9 +4406,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) {
@@ -3714,15 +4424,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++)
@@ -3730,22 +4441,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;
@@ -3759,7 +4471,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++ )
@@ -3779,11 +4491,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);
@@ -3791,28 +4505,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 */
 }
 
-long 
+/* TRANS2_REPORT_DFS_INCONSISTENCY */
+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.
      */
@@ -3821,34 +4536,31 @@ 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;
     cm_scache_t *targetScp;                    /* target if scp is a symlink */
-    char *dptr;
     afs_uint32 dosTime;
     FILETIME ft;
-    int shortTemp;
     unsigned short attr;
     unsigned long lattr;
     smb_dirListPatch_t *patchp;
     smb_dirListPatch_t *npatchp;
     afs_uint32 rights;
     afs_int32 mustFake = 0;
-    char path[AFSPATHMAX];
+    clientchar_t path[AFSPATHMAX];
 
     code = cm_FindACLCache(dscp, userp, &rights);
-    if (code == 0 && !(rights & PRSFS_READ))
-        mustFake = 1;
-    else if (code == -1) {
+    if (code == -1) {
         lock_ObtainWrite(&dscp->rw);
         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (code == 0)
+            cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         lock_ReleaseWrite(&dscp->rw);
         if (code == CM_ERROR_NOACCESS) {
             mustFake = 1;
@@ -3856,140 +4568,215 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
         }
     }
     if (code)
-        return code;
+        goto cleanup;
+
+    if (!mustFake) {    /* Bulk Stat */
+        afs_uint32 count;
+        cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
 
-    for(patchp = *dirPatchespp; patchp; patchp =
-         (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
-        snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
+        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;
+
+            /* 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, &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;
 
+        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, &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);
 
-            dptr = patchp->dptr;
-
             /* 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 */
-                *((FILETIME *)dptr) = ft;
-                dptr += 8;
-
-                /* copy to Last Access Time */
-                *((FILETIME *)dptr) = ft;
-                dptr += 8;
-
-                /* copy to Last Write Time */
-                *((FILETIME *)dptr) = ft;
-                dptr += 8;
-
-                /* copy to Change Time */
-                *((FILETIME *)dptr) = ft;
-                dptr += 24;
+                fa->creationTime = ft;
+                fa->lastAccessTime = ft;
+                fa->lastWriteTime = ft;
+                fa->lastChangeTime = ft;
 
                 switch (scp->fileType) {
                 case CM_SCACHETYPE_DIRECTORY:
                 case CM_SCACHETYPE_MOUNTPOINT:
-                case CM_SCACHETYPE_SYMLINK:
                 case CM_SCACHETYPE_INVALID:
-                    *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
+                    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))
-                        *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
+                        fa->extFileAttributes = SMB_ATTR_DIRECTORY;
                     else
-                        *((u_long *)dptr) = SMB_ATTR_NORMAL;
-                        
+                        fa->extFileAttributes = SMB_ATTR_NORMAL;
                 }
                 /* merge in hidden attribute */
                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
-                    *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
+                    fa->extFileAttributes |= SMB_ATTR_HIDDEN;
                 }
-                dptr += 4;
             } else {
+                smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+
                 /* 1969-12-31 23:59:58 +00*/
                 dosTime = 0xEBBFBF7D;
 
-                /* and copy out date */
-                shortTemp = (dosTime>>16) & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-
-                /* copy out creation time */
-                shortTemp = dosTime & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-
-                /* and copy out date */
-                shortTemp = (dosTime>>16) & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-                       
-                /* copy out access time */
-                shortTemp = dosTime & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-
-                /* and copy out date */
-                shortTemp = (dosTime>>16) & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 2;
-                       
-                /* copy out mod time */
-                shortTemp = dosTime & 0xffff;
-                *((u_short *)dptr) = shortTemp;
-                dptr += 10;
+                fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
+                fa->lastAccessDateTime = fa->creationDateTime;
+                fa->lastWriteDateTime = fa->creationDateTime;
 
                 /* set the attribute */
                 switch (scp->fileType) {
                 case CM_SCACHETYPE_DIRECTORY:
                 case CM_SCACHETYPE_MOUNTPOINT:
-                case CM_SCACHETYPE_SYMLINK:
                 case CM_SCACHETYPE_INVALID:
-                    attr = SMB_ATTR_DIRECTORY;
+                    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:
-                    attr = 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 ) {
-                    attr |= SMB_ATTR_HIDDEN;
-                }       
-                *dptr++ = attr & 0xff;
-                *dptr++ = (attr >> 8) & 0xff;
+                    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);
@@ -4009,37 +4796,26 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
 
         lock_ConvertWToR(&scp->rw);
 
-        dptr = patchp->dptr;
-
         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
-            /* get filetime */
-            smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
-
-            /* copy to Creation Time */
-            *((FILETIME *)dptr) = ft;
-            dptr += 8;
-
-            /* copy to Last Access Time */
-            *((FILETIME *)dptr) = ft;
-            dptr += 8;
+            smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
 
-            /* copy to Last Write Time */
-            *((FILETIME *)dptr) = ft;
-            dptr += 8;
+            /* get filetime */
+            cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
 
-            /* copy to Change Time */
-            *((FILETIME *)dptr) = ft;
-            dptr += 8;
+            fa->creationTime = ft;
+            fa->lastAccessTime = ft;
+            fa->lastWriteTime = ft;
+            fa->lastChangeTime = ft;
 
             /* Use length for both file length and alloc length */
-            *((LARGE_INTEGER *)dptr) = scp->length;
-            dptr += 8;
-            *((LARGE_INTEGER *)dptr) = scp->length;
-            dptr += 8;
+            fa->endOfFile = scp->length;
+            fa->allocationSize = scp->length;
 
             /* 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;
@@ -4053,49 +4829,23 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                 else
                     lattr |= SMB_ATTR_HIDDEN;
             }
-            *((u_long *)dptr) = lattr;
-            dptr += 4;
+
+            fa->extFileAttributes = lattr;
         } else {
+            smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
+
             /* get dos time */
-            smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
-
-            /* and copy out date */
-            shortTemp = (dosTime>>16) & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* copy out creation time */
-            shortTemp = dosTime & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* and copy out date */
-            shortTemp = (dosTime>>16) & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* copy out access time */
-            shortTemp = dosTime & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* and copy out date */
-            shortTemp = (dosTime>>16) & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
-
-            /* copy out mod time */
-            shortTemp = dosTime & 0xffff;
-            *((u_short *)dptr) = shortTemp;
-            dptr += 2;
+            cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+
+            fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
+            fa->lastAccessDateTime = fa->creationDateTime;
+            fa->lastWriteDateTime = fa->creationDateTime;
 
             /* copy out file length and alloc length,
              * using the same for both
              */
-            *((u_long *)dptr) = scp->length.LowPart;
-            dptr += 4;
-            *((u_long *)dptr) = scp->length.LowPart;
-            dptr += 4;
+            fa->dataSize = scp->length.LowPart;
+            fa->allocationSize = scp->length.LowPart;
 
             /* finally copy out attributes as short */
             attr = smb_Attributes(scp);
@@ -4106,151 +4856,27 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp,
                 else
                     lattr |= SMB_ATTR_HIDDEN;
             }
-            *dptr++ = attr & 0xff;
-            *dptr++ = (attr >> 8) & 0xff;
+            fa->attributes = attr;
         }
 
         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];
-
-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('?');    
-}
-
-// 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 
+/* smb_ReceiveTran2SearchDir implements both
  * Tran2_Find_First and Tran2_Find_Next
  */
 #define TRAN2_FIND_FLAG_CLOSE_SEARCH           0x01
@@ -4264,46 +4890,52 @@ int smb_V3MatchMask(char *namep, char *maskp, int flags)
    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. 
-   
+   the usual mechanism.
+
    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
+
+   TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
    */
 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     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;
-    long orbytes;                      /* # of bytes in this output record */
-    long ohbytes;                      /* # of bytes, except file name */
-    long onbytes;                      /* # of bytes in name, incl. term. null */
+    size_t orbytes;                    /* # of bytes in this output record */
+    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 */
     cm_space_t *spacep;                        /* for pathname buffer */
-    long maxReturnData;                        /* max # of return data */
+    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");
@@ -4317,43 +4949,58 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     maxCount = p->parmsp[1];
     infoLevel = p->parmsp[3];
     searchFlags = p->parmsp[2];
-    pathp = ((char *) p->parmsp) + 12; /* points to path */
+    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:
        s = "InfoStandard";
+        ohbytes = sizeof(fp->u.FstandardInfo);
        break;
+
     case SMB_INFO_QUERY_EA_SIZE:
+        ohbytes = sizeof(fp->u.FeaSizeInfo);
        s = "InfoQueryEaSize";
        break;
+
     case SMB_INFO_QUERY_EAS_FROM_LIST:
+        ohbytes = sizeof(fp->u.FeasFromListInfo);
        s = "InfoQueryEasFromList";
        break;
+
     case SMB_FIND_FILE_DIRECTORY_INFO:
        s = "FindFileDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileDirectoryInfo);
        break;
+
     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
        s = "FindFileFullDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
        break;
+
     case SMB_FIND_FILE_NAMES_INFO:
        s = "FindFileNamesInfo";
+        ohbytes = sizeof(fp->u.FfileNamesInfo);
        break;
+
     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
        s = "FindFileBothDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
        break;
+
     default:
        s = "unknownInfoLevel";
+        ohbytes = 0;
     }
 
     osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
@@ -4361,8 +5008,8 @@ 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 (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+
+    if (ohbytes == 0) {
         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
         return CM_ERROR_INVAL;
     }
@@ -4370,29 +5017,27 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;    /* no resume keys */
 
+    if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
+        ohbytes += 4;
+
     dirListPatchesp = NULL;
 
     maxReturnData = p->maxReturnData;
     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);
@@ -4402,7 +5047,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);
@@ -4411,7 +5057,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);
@@ -4431,7 +5077,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;
@@ -4439,32 +5085,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
@@ -4478,25 +5135,35 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
         op += 4;
     }
 
+    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) &&
@@ -4509,10 +5176,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");
@@ -4520,29 +5188,10 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
     }
 
-    /* Check if the name will fit */
-    if (infoLevel < 0x101)
-        ohbytes = 23;           /* pre-NT */
-    else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
-        ohbytes = 12;           /* NT names only */
-    else
-        ohbytes = 64;           /* NT */
-
-    if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
-        ohbytes += 26;          /* Short name & length */
-
-    if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
-        ohbytes += 4;           /* if resume key required */
-    }
-
-    if (infoLevel != SMB_INFO_STANDARD
-        && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
-        && infoLevel != SMB_FIND_FILE_NAMES_INFO)
-        ohbytes += 4;           /* EASIZE */
-
     /* add header to name & term. null */
-    onbytes = (int)strlen(maskp);
-    orbytes = ohbytes + onbytes + 1;
+    onbytes = 0;
+    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
      * sure that we have enough room here for even the aligned version
@@ -4570,42 +5219,79 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
      * preceded by its length.
      */
     /* First zero everything else */
-    memset(origOp, 0, ohbytes);
+    memset(origOp, 0, orbytes);
 
-    if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
-        *(origOp + ohbytes - 1) = (unsigned char) onbytes;
-    else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
-        *((u_long *)(op + 8)) = onbytes;
-    else
-        *((u_long *)(op + 60)) = onbytes;
-    strcpy(origOp+ohbytes, maskp);
-    if (smb_StoreAnsiFilenames)
-        CharToOem(origOp+ohbytes, origOp+ohbytes);
+    onbytes = 0;
+    smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
+
+    switch (infoLevel) {
+    case SMB_INFO_STANDARD:
+        fp->u.FstandardInfo.fileNameLength = onbytes;
+        attrp = &fp->u.FstandardInfo.fileAttrs;
+        break;
+
+    case SMB_INFO_QUERY_EA_SIZE:
+        fp->u.FeaSizeInfo.fileNameLength = onbytes;
+        attrp = &fp->u.FeaSizeInfo.fileAttrs;
+        fp->u.FeaSizeInfo.eaSize = 0;
+        break;
 
-    /* Short name if requested and needed */
-    if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+    case SMB_INFO_QUERY_EAS_FROM_LIST:
+        fp->u.FeasFromListInfo.fileNameLength = onbytes;
+        attrp = &fp->u.FeasFromListInfo.fileAttrs;
+        fp->u.FeasFromListInfo.eaSize = 0;
+        break;
+
+    case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
         if (NeedShortName) {
-            strcpy(op + 70, shortName);
-            if (smb_StoreAnsiFilenames)
-                CharToOem(op + 70, op + 70);
-            *(op + 68) = (char)(shortNameEnd - shortName);
-        }
+#ifdef SMB_UNICODE
+            int nchars;
+
+            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*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 = cm_ClientStrLen(shortName);
+#endif
     }
+        /* Fallthrough */
+
+    case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+        fp->u.FfileFullDirectoryInfo.eaSize = 0;
+        /* Fallthrough */
+
+    case SMB_FIND_FILE_DIRECTORY_INFO:
+        fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
+        fp->u.FfileDirectoryInfo.fileIndex = 0;
+        attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
+        fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
+        break;
+
+    case SMB_FIND_FILE_NAMES_INFO:
+        fp->u.FfileNamesInfo.nextEntryOffset = 0;
+        fp->u.FfileNamesInfo.fileIndex = 0;
+        fp->u.FfileNamesInfo.fileNameLength = onbytes;
+        break;
 
-    /* NextEntryOffset and FileIndex */
-    if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
-        int entryOffset = orbytes + align;
-        *((u_long *)op) = 0;
-        *((u_long *)(op+4)) = 0;
+    default:
+        /* we shouldn't hit this case */
+        osi_assertx(FALSE, "Unknown query type");
     }
 
     if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+        osi_assert(attrp != NULL);
+
         curPatchp = malloc(sizeof(*curPatchp));
         osi_QAdd((osi_queue_t **) &dirListPatchesp,
                  &curPatchp->q);
-        curPatchp->dptr = op;
-        if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
-            curPatchp->dptr += 8;
+        curPatchp->dptr = attrp;
 
         if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
             curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
@@ -4613,15 +5299,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 */
@@ -4639,7 +5336,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 */
@@ -4666,30 +5363,32 @@ 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;
 }
 
 
+/* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     int attribute;
     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;
     smb_dirListPatch_t *curPatchp = 0;
     cm_buf_t *bufferp;
     long temp;
-    long orbytes;                      /* # of bytes in this output record */
-    long ohbytes;                      /* # of bytes, except file name */
-    long onbytes;                      /* # of bytes in name, incl. term. null */
+    size_t orbytes;                    /* # of bytes in this output record */
+    size_t ohbytes;                    /* # of bytes, except file name */
+    size_t onbytes;                    /* # of bytes in name, incl. term. null */
     osi_hyper_t dirLength;
     osi_hyper_t bufferOffset;
     osi_hyper_t curOffset;
@@ -4707,27 +5406,29 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     char *op;                  /* output data ptr */
     char *origOp;                      /* original value of op */
     cm_space_t *spacep;                /* for pathname buffer */
-    long maxReturnData;                /* max # of return data */
-    long maxReturnParms;               /* max # of return parms */
+    unsigned long maxReturnData;               /* max # of return data */
+    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;
-    int align;
-    char shortName[13];                /* 8.3 name if needed */
+    clientchar_t *tidPathp;
+    unsigned int align;
+    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;
+    void * attrp;
     char * s;
+    smb_tran2Find_t * fp;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     eos = 0;
     if (p->opcode == 1) {
@@ -4736,14 +5437,12 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         maxCount = p->parmsp[1];
         infoLevel = p->parmsp[3];
         searchFlags = p->parmsp[2];
-        pathp = ((char *) p->parmsp) + 12;     /* points to path */
-        if (smb_StoreAnsiFilenames)
-            OemToChar(pathp,pathp);
+        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 */
@@ -4752,7 +5451,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);
 
@@ -4766,12 +5465,12 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 return code;
             }
         }
-#endif
+#endif  /* NOFINDFIRSTOPTIMIZE */
         dir_enums++;
 
         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");
@@ -4795,27 +5494,42 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     switch ( infoLevel ) {
     case SMB_INFO_STANDARD:
        s = "InfoStandard";
+        ohbytes = sizeof(fp->u.FstandardInfo);
        break;
+
     case SMB_INFO_QUERY_EA_SIZE:
+        ohbytes = sizeof(fp->u.FeaSizeInfo);
        s = "InfoQueryEaSize";
        break;
+
     case SMB_INFO_QUERY_EAS_FROM_LIST:
+        ohbytes = sizeof(fp->u.FeasFromListInfo);
        s = "InfoQueryEasFromList";
        break;
+
     case SMB_FIND_FILE_DIRECTORY_INFO:
        s = "FindFileDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileDirectoryInfo);
        break;
+
     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
        s = "FindFileFullDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
        break;
+
     case SMB_FIND_FILE_NAMES_INFO:
        s = "FindFileNamesInfo";
+        ohbytes = sizeof(fp->u.FfileNamesInfo);
        break;
+
     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
        s = "FindFileBothDirectoryInfo";
+        ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
        break;
+
     default:
        s = "unknownInfoLevel";
+        ohbytes = 0;
     }
 
     osi_Log1(smb_logp, "T2 search dir info level: %s", s);
@@ -4827,7 +5541,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
               p->opcode, dsp->cookie, nextCookie);
 
-    if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+    if (ohbytes == 0) {
         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
         smb_ReleaseDirSearch(dsp);
         return CM_ERROR_INVAL;
@@ -4836,32 +5550,33 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;    /* no resume keys */
 
+    if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
+        ohbytes += 4;
+
     dirListPatchesp = NULL;
 
     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);
 
@@ -4882,7 +5597,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);
@@ -4894,10 +5610,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);
@@ -4911,7 +5627,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);
@@ -4929,14 +5645,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) {
@@ -4976,11 +5686,16 @@ 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 */
             op += 4;
 
+        fp = (smb_tran2Find_t *) op;
+
         /* make sure that curOffset.LowPart doesn't point to the first
          * 32 bytes in the 2nd through last dir page, and that it doesn't
          * point at the first 13 32-byte chunks in the first dir page,
@@ -4996,10 +5711,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;
@@ -5022,6 +5737,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.
@@ -5033,33 +5764,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);
+            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;
@@ -5077,19 +5785,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;
                 }
@@ -5100,7 +5808,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.
          */
@@ -5139,43 +5847,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);
@@ -5189,29 +5906,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             }
 
             /* finally check if this name will fit */
-
-            /* standard dir entry stuff */
-            if (infoLevel < 0x101)
-                ohbytes = 23;  /* pre-NT */
-            else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
-                ohbytes = 12;  /* NT names only */
-            else
-                ohbytes = 64;  /* NT */
-
-            if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
-                ohbytes += 26; /* Short name & length */
-
-            if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
-                ohbytes += 4;  /* if resume key required */
-            }   
-
-            if ( infoLevel != SMB_INFO_STANDARD && 
-                 infoLevel != SMB_FIND_FILE_DIRECTORY_INFO &&
-                 infoLevel != SMB_FIND_FILE_NAMES_INFO)
-                ohbytes += 4;  /* EASIZE */
-
-            /* add header to name & term. null */
-            orbytes = onbytes + ohbytes + 1;
+            onbytes = 0;
+            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,
              * and we make sure that we have enough room here for
@@ -5223,49 +5920,89 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 align = (4 - (orbytes & 3)) & 3;
             else
                 align = 0;
+
             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.
              * Put out the name, preceded by its length.
              */
             /* First zero everything else */
-            memset(origOp, 0, ohbytes);
+            memset(origOp, 0, orbytes);
 
-            if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
-                *(origOp + ohbytes - 1) = (unsigned char) onbytes;
-            else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
-                *((u_long *)(op + 8)) = onbytes;
-            else
-                *((u_long *)(op + 60)) = onbytes;
-            strcpy(origOp+ohbytes, dep->name);
-            if (smb_StoreAnsiFilenames)
-                CharToOem(origOp+ohbytes, origOp+ohbytes);
+            onbytes = 0;
+            smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
 
-            /* Short name if requested and needed */
-            if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+            switch (infoLevel) {
+            case SMB_INFO_STANDARD:
+                fp->u.FstandardInfo.fileNameLength = onbytes;
+                attrp = &fp->u.FstandardInfo.fileAttrs;
+                break;
+
+            case SMB_INFO_QUERY_EA_SIZE:
+                fp->u.FeaSizeInfo.fileNameLength = onbytes;
+                attrp = &fp->u.FeaSizeInfo.fileAttrs;
+                fp->u.FeaSizeInfo.eaSize = 0;
+                break;
+
+            case SMB_INFO_QUERY_EAS_FROM_LIST:
+                fp->u.FeasFromListInfo.fileNameLength = onbytes;
+                attrp = &fp->u.FeasFromListInfo.fileAttrs;
+                fp->u.FeasFromListInfo.eaSize = 0;
+                break;
+
+            case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
                 if (NeedShortName) {
-                    strcpy(op + 70, shortName);
-                    if (smb_StoreAnsiFilenames)
-                        CharToOem(op + 70, op + 70);
-                    *(op + 68) = (char)(shortNameEnd - shortName);
+#ifdef SMB_UNICODE
+                    int nchars;
+
+                    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*sizeof(wchar_t);
+                    else
+                        fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
+                    fp->u.FfileBothDirectoryInfo.reserved = 0;
+#else
+                    cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
+                                    lengthof(fp->u.FfileBothDirectoryInfo.shortName),
+                                    shortName);
+                    fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
+#endif
                 }
+                /* Fallthrough */
+
+            case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+                fp->u.FfileFullDirectoryInfo.eaSize = 0;
+                /* Fallthrough */
+
+            case SMB_FIND_FILE_DIRECTORY_INFO:
+                fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
+                fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
+                attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
+                fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
+                break;
+
+            case SMB_FIND_FILE_NAMES_INFO:
+                fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
+                fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
+                fp->u.FfileNamesInfo.fileNameLength = onbytes;
+                attrp = NULL;
+                break;
+
+            default:
+                /* we shouldn't hit this case */
+                osi_assertx(FALSE, "Unknown query type");
             }
 
             /* now, adjust the # of entries copied */
             returnedNames++;
 
-            /* NextEntryOffset and FileIndex */
-            if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
-                int entryOffset = orbytes + align;
-                *((u_long *)op) = entryOffset;
-                *((u_long *)(op+4)) = nextEntryCookie;
-            }
-
             /* now we emit the attribute.  This is tricky, since
              * we need to really stat the file to find out what
              * type of entry we've got.  Right now, we're copying
@@ -5280,23 +6017,22 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
              * safe to unlock the directory.
              */
             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+                osi_assert(attrp != NULL);
                 curPatchp = malloc(sizeof(*curPatchp));
                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
-                curPatchp->dptr = op;
-                if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
-                    curPatchp->dptr += 8;
+                curPatchp->dptr = attrp;
 
-                if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
+                if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
-                }       
-                else    
+                } else {
                     curPatchp->flags = 0;
+                }
 
                 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
 
                 /* temp */
                 curPatchp->dep = dep;
-            }   
+            }
 
             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
                 /* put out resume key */
@@ -5307,14 +6043,14 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             bytesInBuffer += orbytes;
 
             /* and pad the record out */
-            while (--align >= 0) {
+            while (align-- > 0) {
                 *origOp++ = 0;
                 bytesInBuffer++;
             }
         }      /* 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;
         }
@@ -5326,10 +6062,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");
@@ -5344,14 +6080,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 */
@@ -5359,7 +6095,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
@@ -5374,7 +6110,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;
@@ -5390,9 +6126,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);
 
@@ -5408,39 +6144,43 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return 0;
 }
 
+/* SMB_COM_FIND_CLOSE2 */
 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int dirHandle;
     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);
 
     return 0;
 }
 
+
+/* SMB_COM_FIND_NOTIFY_CLOSE */
 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_SetSMBDataLength(outp, 0);
     return 0;
 }
 
+/* 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;
@@ -5448,25 +6188,26 @@ 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;
-    afs_uint32 dosTime;
+    clientchar_t *lastNamep;
+    unsigned long dosTime;
     int openFun;
     int trunc;
     int openMode;
     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);
@@ -5477,36 +6218,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_GetSMBData(inp, NULL);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    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++;
@@ -5517,9 +6276,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 */
@@ -5533,6 +6292,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;
@@ -5545,12 +6326,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);
 
@@ -5562,14 +6338,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;
@@ -5577,22 +6356,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);
@@ -5602,7 +6382,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,
@@ -5619,7 +6399,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);
@@ -5643,11 +6423,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) {
@@ -5671,23 +6453,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);
@@ -5698,7 +6480,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 */
@@ -5709,9 +6491,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;
@@ -5722,12 +6504,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++;
@@ -5757,12 +6539,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) {
@@ -5785,6 +6567,7 @@ static void smb_GetLockParams(unsigned char LockType,
     }
 }
 
+/* SMB_COM_LOCKING_ANDX */
 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     cm_req_t req;
@@ -5804,23 +6587,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);
@@ -5836,7 +6623,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,
@@ -5863,7 +6650,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;
 
@@ -5884,7 +6671,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;
@@ -5905,9 +6692,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;
     }
 
@@ -5921,14 +6708,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 */
@@ -5943,7 +6730,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);
@@ -6027,8 +6814,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 {
@@ -6067,7 +6854,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:
@@ -6075,10 +6862,13 @@ 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;
 }
 
+/* SMB_COM_QUERY_INFORMATION2 */
 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -6090,22 +6880,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);
@@ -6115,26 +6908,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 */
@@ -6150,13 +6944,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);
@@ -6164,8 +6958,9 @@ 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)
 {
     unsigned short fid;
@@ -6178,22 +6973,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);
@@ -6203,18 +7001,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;
@@ -6223,10 +7020,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);
@@ -6235,6 +7032,7 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     return code;
 }
 
+/* SMB_COM_WRITE_ANDX */
 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -6244,6 +7042,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;
@@ -6256,17 +7055,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);
@@ -6274,26 +7063,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
@@ -6305,7 +7114,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);
@@ -6315,7 +7123,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);
@@ -6336,8 +7143,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);
 
@@ -6363,12 +7172,15 @@ 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);
 
     return code;
 }
 
+/* SMB_COM_READ_ANDX */
 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -6379,17 +7191,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)) {
@@ -6397,14 +7209,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;
     }
@@ -6415,31 +7219,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;
     }
 
+    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);
@@ -6449,15 +7284,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,
@@ -6478,7 +7304,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)));
 
@@ -6494,8 +7320,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
  */
@@ -6522,10 +7348,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;
@@ -6533,8 +7366,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;
@@ -6548,7 +7381,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;
@@ -6558,16 +7390,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;
@@ -6611,40 +7447,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;
+    pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
+                              NULL, SMB_STRF_ANSIPATH);
 
-    pathp = smb_GetSMBData(inp, NULL);
     /* Sometimes path is not null-terminated, so we make a copy. */
-    realPathp = malloc(nameLength+1);
-    memcpy(realPathp, pathp, nameLength);
-    realPathp[nameLength] = 0;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(realPathp,realPathp);
+    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;
@@ -6664,8 +7526,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);
 
@@ -6675,16 +7537,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);
@@ -6692,37 +7568,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;
         }
 
@@ -6730,8 +7589,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)
@@ -6746,6 +7603,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;
 
@@ -6759,43 +7618,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);
@@ -6805,20 +7665,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*
@@ -6830,40 +7701,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)
@@ -6902,9 +7777,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)) {
@@ -6918,9 +7793,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);
@@ -6952,6 +7827,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (code == 0 && !treeCreate) {
         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
         if (code) {
+            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
             if (scp)
@@ -6960,6 +7836,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             free(realPathp);
             return code;
         }
+        checkDoneRequired = 1;
 
        if (createDisp == FILE_CREATE) {
             /* oops, file shouldn't be there */
@@ -6973,7 +7850,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             return CM_ERROR_EXISTS;
         }
 
-        if ( createDisp == FILE_OVERWRITE || 
+        if ( createDisp == FILE_OVERWRITE ||
              createDisp == FILE_OVERWRITE_IF) {
 
             setAttr.mask = CM_ATTRMASK_LENGTH;
@@ -6997,6 +7874,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                     scp = targetScp;
                    code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
                    if (code) {
+                        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                        if (dscp)
                            cm_ReleaseSCache(dscp);
                        if (scp)
@@ -7010,7 +7888,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) {
@@ -7024,11 +7902,13 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         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;
@@ -7072,21 +7952,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
         */
@@ -7095,38 +7975,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
@@ -7134,9 +8016,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 */
@@ -7152,7 +8034,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.
          */
@@ -7160,11 +8042,11 @@ 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);
         free(realPathp);
@@ -7184,15 +8066,17 @@ 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);
@@ -7205,7 +8089,7 @@ 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)
@@ -7248,13 +8132,13 @@ 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)
@@ -7264,13 +8148,15 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
            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 */
@@ -7292,7 +8178,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);
@@ -7308,40 +8194,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);
+
+
+    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);
@@ -7351,15 +8284,17 @@ 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.
  * Instead, ultimately, would like to use a subroutine for common code.
  */
+
+/* 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;
@@ -7367,7 +8302,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;
@@ -7376,17 +8311,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;
@@ -7395,7 +8328,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;
@@ -7403,9 +8336,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;
@@ -7429,23 +8364,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
@@ -7457,74 +8385,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);
-    /* 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;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(realPathp,realPathp);
-
+    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);
@@ -7550,6 +8497,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;
 
@@ -7561,94 +8510,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;
@@ -7656,14 +8581,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 {
@@ -7691,20 +8620,20 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
      */
     if (code == 0) {
         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
-        if (code) {     
-            if (dscp) 
-                cm_ReleaseSCache(dscp);
+        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);
@@ -7734,8 +8663,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                     scp = targetScp;
                    code = cm_CheckNTOpen(scp, desiredAccess, createDisp, 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);
@@ -7751,19 +8680,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) {
@@ -7804,19 +8734,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,
@@ -7831,14 +8762,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);
@@ -7859,15 +8790,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);
@@ -7877,7 +8810,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);
@@ -7916,13 +8849,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);
@@ -7935,8 +8868,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 */
@@ -7958,13 +8893,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);
@@ -8008,7 +8943,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 */
@@ -8017,7 +8952,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);
@@ -8027,7 +8963,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 */
@@ -8048,7 +8984,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 */
@@ -8057,7 +8993,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 */
@@ -8066,25 +9002,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);
+
     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
 
     cm_ReleaseUser(userp);
@@ -8095,15 +9036,16 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     return 0;
 }
 
+/* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
 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);
@@ -8111,24 +9053,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);
@@ -8136,9 +9086,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)
@@ -8172,95 +9121,193 @@ 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
+
+   SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
+ */
 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short function;
@@ -8272,22 +9319,22 @@ 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: 
+    case 1:                     /* NT_TRANSACT_CREATE */
         return smb_ReceiveNTTranCreate(vcp, inp, outp);
-    case 2:
+    case 2:                     /* NT_TRANSACT_IOCTL */
        osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
        break;
-    case 3:
+    case 3:                     /* NT_TRANSACT_SET_SECURITY_DESC */
        osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
        break;
-    case 4:
+    case 4:                     /* NT_TRANSACT_NOTIFY_CHANGE */
         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
-    case 5:
+    case 5:                     /* NT_TRANSACT_RENAME */
        osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
        break;
-    case 6:
+    case 6:                     /* NT_TRANSACT_QUERY_SECURITY_DESC */
         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
     case 7:
         osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
@@ -8296,7 +9343,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;
 }
 
 /*
@@ -8306,15 +9353,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;
@@ -8330,8 +9377,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)
@@ -8368,24 +9415,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)
@@ -8410,7 +9456,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)
@@ -8434,14 +9480,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 */
@@ -8475,7 +9521,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;
@@ -8485,12 +9530,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;
@@ -8499,13 +9542,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
@@ -8525,11 +9564,14 @@ 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)
 {
     unsigned char *replyWctp;
@@ -8558,23 +9600,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);
@@ -8613,7 +9657,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;
@@ -8628,32 +9672,33 @@ long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 
     tp = smb_GetSMBData(inp, NULL);
-    oldPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(oldPathp,oldPathp);
-    newPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(newPathp,newPathp);
-
-    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"));
+    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_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;
@@ -8663,9 +9708,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);
@@ -8673,3 +9718,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;
+}