Windows: Add cm_req_t parameter to buf_Get* functions
[openafs.git] / src / WINNT / afsd / smb3.c
index f720471..ade4503 100644 (file)
 #include <afs/stds.h>
 
 #include <windows.h>
+#pragma warning(push)
+#pragma warning(disable: 4005)
 #include <ntstatus.h>
 #define SECURITY_WIN32
 #include <security.h>
 #include <lmaccess.h>
+#pragma warning(pop)
 #include <stdlib.h>
 #include <malloc.h>
 #include <string.h>
@@ -26,6 +29,7 @@
 #include <WINNT\afsreg.h>
 
 #include "smb.h"
+#include <strsafe.h>
 
 extern osi_hyper_t hzero;
 
@@ -39,6 +43,8 @@ smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
 /* protected by the smb_globalLock */
 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
 
+const clientchar_t **smb_ExecutableExtensions = NULL;
+
 /* retrieve a held reference to a user structure corresponding to an incoming
  * request */
 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
@@ -57,6 +63,28 @@ 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 
+ * executable file.  For now .exe or .dll.
+ */
+afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
+{
+    int i, j, len;
+        
+    if ( smb_ExecutableExtensions == NULL || name == NULL)
+        return 0;
+
+    len = (int)cm_ClientStrLen(name);
+
+    for ( i=0; smb_ExecutableExtensions[i]; i++) {
+        j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
+        if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
+            return 1;
+    }
+
+    return 0;
+}
+
 /*
  * Return extended attributes.
  * Right now, we aren't using any of the "new" bits, so this looks exactly
@@ -76,8 +104,11 @@ 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.
@@ -96,9 +127,9 @@ 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 == '>') 
@@ -106,46 +137,28 @@ int smb_V3IsStarMask(char *maskp)
     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) {
-    int i,j,k,pcts=0;
+    int i,j,k;
     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_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
-                strcat(buf,"\n");
-                OutputDebugString(buf);
+                osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
             }
-            sprintf(buf,"%5x",i);
+            StringCchPrintfA(buf, lengthof(buf), "%5x", i);
             memset(buf+5,' ',80);
             buf[85] = 0;
         }
@@ -157,18 +170,12 @@ void OutputDebugHexDump(unsigned char * buffer, int len) {
         buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
 
         j = (i%16);
-        j = j + 56 + ((j>7)?1:0) + pcts;
+        j = j + 56 + ((j>7)?1:0);
 
         buf[j] = (k>32 && k<127)?k:'.';
-               if (k == '%') {
-                       buf[++j] = k;
-                       pcts++;
-               }
     }    
     if(i) {
-        osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
-        strcat(buf,"\n");
-        OutputDebugString(buf);
+        osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
     }   
 }
 
@@ -186,7 +193,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,
@@ -200,7 +207,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;
     }
 
@@ -226,10 +233,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) {
@@ -240,7 +247,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 */
@@ -262,7 +269,9 @@ struct smb_ext_context {
     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) {
     SECURITY_STATUS status, istatus;
     CredHandle creds;
     TimeStamp expiry;
@@ -278,7 +287,7 @@ 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;
@@ -292,12 +301,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;
 
@@ -319,7 +328,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;
         }
@@ -361,14 +370,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));
 
@@ -388,16 +397,16 @@ long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int
     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));
 
@@ -417,52 +426,52 @@ 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;
+        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());
+            OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
             code = CM_ERROR_BADPASSWORD; 
         }
     } 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;
     }
@@ -504,7 +513,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;
@@ -515,11 +524,11 @@ 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;
     }
 
@@ -528,12 +537,12 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDom
     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);
 
@@ -561,9 +570,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,
@@ -584,8 +598,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 */
@@ -602,13 +616,13 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDom
 }
 
 /* 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]
@@ -617,7 +631,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;
@@ -630,18 +644,18 @@ long smb_GetNormalizedUsername(char * usern, const char * accountName, const cha
         /* 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 
            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;
 }
@@ -653,6 +667,7 @@ long smb_GetNormalizedUsername(char * usern, const char * accountName, const cha
  * 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;
@@ -660,23 +675,51 @@ 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 = " ";
+    clientchar_t *s1 = _C(" ");
     long code = 0; 
-    char usern[SMB_MAX_USERNAME_LENGTH];
+    clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
     char *secBlobOut = NULL;
     int  secBlobOutLength = 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);
@@ -688,35 +731,37 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
 
             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;
+                    cb_data += 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;
+                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 */
@@ -724,20 +769,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 */
@@ -753,38 +800,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 */
@@ -798,9 +845,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"));
         }
     }
 
@@ -813,6 +860,12 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         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);
     }
 
@@ -824,7 +877,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         return code;
     }
 
-    OutputDebugF("Received username=[%s]", usern);
+    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
@@ -865,7 +918,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 */
@@ -888,40 +941,45 @@ 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;
+                cb_data +=  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;
+
+            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);
         }
@@ -930,6 +988,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     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;
@@ -939,8 +998,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;
@@ -977,18 +1036,20 @@ 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[256];
-    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;
         
@@ -996,23 +1057,23 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
 
     /* 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;
@@ -1032,24 +1093,35 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     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)
                smb_ReleaseUID(uidp);
-            smb_ReleaseTID(tidp);
+            smb_ReleaseTID(tidp, FALSE);
             return CM_ERROR_BADSHARENAME;
        }
 
        if (vcp->flags & SMB_VCFLAG_USENT)
         {
             int policy = smb_FindShareCSCPolicy(shareName);
+            HKEY parmKey;
+            DWORD code;
+            DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
+
+            code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
+                                 0, KEY_QUERY_VALUE, &parmKey);
+            if (code == ERROR_SUCCESS) {
+                code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
+                                       (BYTE *)&dwAdvertiseDFS, &dwSize);
+                if (code != ERROR_SUCCESS)
+                    dwAdvertiseDFS = 0;
+                RegCloseKey (parmKey);
+            }
             smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | 
-#ifdef DFS_SUPPORT
-                            SMB_SHARE_IS_IN_DFS |
-#endif
-                            (policy << 2));
+                           (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
+                           (policy << 2));
         }
     } else {
         smb_SetSMBParm(outp, 2, 0);
@@ -1064,24 +1136,22 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     if (ipc) 
         tidp->flags |= SMB_TIDFLAG_IPC;
     lock_ReleaseMutex(&tidp->mx);
-    smb_ReleaseTID(tidp);
+    smb_ReleaseTID(tidp, FALSE);
 
     ((smb_t *)outp)->tid = newTid;
     ((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);
@@ -1103,7 +1173,7 @@ 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;
@@ -1133,18 +1203,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);
@@ -1192,14 +1266,44 @@ void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
         if (t2p->datap)
             free(t2p->datap);
     }       
+    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;
@@ -1297,6 +1401,8 @@ void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp
     smb_SendPacket(vcp, tp);
 }   
 
+
+/* 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;
@@ -1419,31 +1525,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;
-    DWORD                              shi2_remark; /* char *shi2_remark; data offset */
-    unsigned short             shi2_permissions;
-    unsigned short             shi2_max_uses;
-    unsigned short             shi2_current_uses;
-    DWORD                              shi2_path;  /* char *shi2_path; data offset */
-    unsigned short             shi2_passwd[9];
-    unsigned short             shi2_pad2;
+    BYTE               shi2_netname[13];
+    BYTE               shi2_pad;
+    WORD               shi2_type;
+    DWORD                      shi2_remark; /* char *shi2_remark; data offset */
+    WORD               shi2_permissions;
+    WORD               shi2_max_uses;
+    WORD               shi2_current_uses;
+    DWORD                      shi2_path;  /* char *shi2_path; data offset */
+    WORD               shi2_passwd[9];
+    WORD               shi2_pad2;
 } smb_rap_share_info_2_t;
 
 #define SMB_RAP_MAX_SHARES 512
@@ -1454,18 +1561,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++;
@@ -1476,6 +1582,7 @@ int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp
         return 0;
 }       
 
+/* RAP NetShareEnumRequest */
 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     smb_tran2Packet_t *outp;
@@ -1496,7 +1603,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[256];
+    clientchar_t thisShare[AFSPATHMAX];
     int i,j;
     DWORD dw;
     int nonrootShares;
@@ -1506,8 +1613,18 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     osi_hyper_t thyper;
 
     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];
 
@@ -1515,6 +1632,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);
@@ -1544,7 +1673,7 @@ 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);
 
@@ -1579,7 +1708,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++;
@@ -1589,9 +1719,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++;
@@ -1607,9 +1740,10 @@ 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) {
@@ -1617,7 +1751,8 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
             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;
@@ -1639,11 +1774,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;
@@ -1655,11 +1791,31 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     DWORD allSubmount;
     LONG rv;
     long code = 0;
+    cm_scache_t *scp = NULL;
+    cm_user_t   *userp;
+    cm_req_t    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++;
     
@@ -1674,9 +1830,7 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     else
         return CM_ERROR_INVAL;
 
-    outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
-
-    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) {
@@ -1693,22 +1847,34 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
             shareFound = TRUE;
 
     } else {
-        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);
+        userp = smb_GetTran2User(vcp, p);
+        if (!userp) {
+            osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
+            return CM_ERROR_BADSMB;
+        }   
+        code = cm_NameI(cm_data.rootSCachep, shareName,
+                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
+                         userp, NULL, &req, &scp);
+        if (code == 0) {
+            cm_ReleaseSCache(scp);
+            shareFound = TRUE;
+        } else {
+            rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
+                              KEY_QUERY_VALUE, &hkSubmount);
             if (rv == ERROR_SUCCESS) {
-                shareFound = TRUE;
+                rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
+                if (rv == ERROR_SUCCESS) {
+                    shareFound = TRUE;
+                }
+                RegCloseKey(hkSubmount);
             }
-            RegCloseKey(hkSubmount);
         }
     }
 
-    if (!shareFound) {
-        smb_FreeTran2Packet(outp);
+    if (!shareFound)
         return CM_ERROR_BADSHARENAME;
-    }
 
+    outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
     memset(outp->datap, 0, totalData);
 
     outp->parmsp[0] = 0;
@@ -1717,18 +1883,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;
@@ -1744,16 +1909,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)
 {
@@ -1769,8 +1937,21 @@ 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 */
+
+    {
+        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++;
 
@@ -1797,7 +1978,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);
@@ -1805,14 +1986,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 */
@@ -1820,7 +2002,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);
@@ -1836,18 +2019,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);
 
@@ -1869,8 +2056,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++;
 
@@ -1892,11 +2092,11 @@ 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 = 
             SMB_SV_TYPE_SERVER |
@@ -1905,11 +2105,11 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
 
         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);
@@ -1924,6 +2124,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;
@@ -1937,6 +2138,7 @@ 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) {
@@ -2009,6 +2211,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);
@@ -2028,6 +2232,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);
     }
@@ -2042,9 +2286,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;
@@ -2056,7 +2301,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     int initialModeBits;
     smb_fid_t *fidp;
     int attributes;
-    char *lastNamep;
+    clientchar_t *lastNamep;
     afs_uint32 dosTime;
     int openFun;
     int trunc;
@@ -2065,11 +2310,11 @@ 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;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     scp = NULL;
         
@@ -2090,16 +2335,19 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     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);
 
     spacep = cm_GetSpace();
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
-    if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+    if (lastNamep && 
+        (cm_ClientStrCmpI(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
+         cm_ClientStrCmpI(lastNamep,  _C("\\srvsvc")) == 0 ||
+         cm_ClientStrCmpI(lastNamep,  _C("\\wkssvc")) == 0 ||
+         cm_ClientStrCmpI(lastNamep,  _C("\\ipc$")) == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
@@ -2142,6 +2390,22 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         return 0;
     }
 
+    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;
@@ -2180,7 +2444,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                      userp, tidPathp, &req, &scp);
     if (code != 0) {
-        code = cm_NameI(cm_data.rootSCachep, spacep->data,
+        code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &dscp);
         cm_FreeSpace(spacep);
@@ -2193,13 +2457,15 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         
 #ifdef DFS_SUPPORT
         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+            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) )
+            if ( WANTS_DFS_PATHNAMES(p) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
 
@@ -2213,7 +2479,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             lastNamep++;
         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
                          &req, &scp);
-        if (code && code != CM_ERROR_NOSUCHFILE) {
+        if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
             cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
             smb_FreeTran2Packet(outp);
@@ -2222,13 +2488,14 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     } else {
 #ifdef DFS_SUPPORT
         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             smb_FreeTran2Packet(outp);
-            if ( WANTS_DFS_PATHNAMES(p) )
+            if ( WANTS_DFS_PATHNAMES(p) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
 
@@ -2274,13 +2541,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         /* don't create if not found */
         if (dscp) 
             cm_ReleaseSCache(dscp);
-        osi_assert(scp == NULL);
+        osi_assertx(scp == NULL, "null cm_scache_t");
         cm_ReleaseUser(userp);
         smb_FreeTran2Packet(outp);
         return CM_ERROR_NOSUCHFILE;
     }
     else {
-        osi_assert(dscp != NULL && scp == NULL);
+        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);
@@ -2353,16 +2620,16 @@ 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_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
        
     cm_HoldUser(userp);
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
     fidp->scp = scp;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     
     /* and the user */
     fidp->userp = userp;
@@ -2386,7 +2653,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     /* copy out remainder of the parms */
     parmSlot = 0;
     outp->parmsp[parmSlot++] = fidp->fid;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainRead(&scp->rw);
     if (extraInfo) {
         outp->parmsp[parmSlot++] = smb_Attributes(scp);
         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
@@ -2408,7 +2675,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         outp->parmsp[parmSlot++] = 0; 
         outp->parmsp[parmSlot++] = 0; 
     }   
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseRead(&scp->rw);
     outp->totalData = 0;               /* total # of data bytes */
     outp->totalParms = parmSlot * 2;   /* shorts are two bytes */
 
@@ -2433,44 +2700,21 @@ long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     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};
+    size_t sz = 0;
         
     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
 
     switch (p->parmsp[0]) {
     case SMB_INFO_ALLOCATION: 
+        /* alloc info */
        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;
-    }
 
-    outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
-    switch (p->parmsp[0]) {
-    case SMB_INFO_ALLOCATION: 
-        /* alloc info */
         qi.u.allocInfo.FSID = 0;
         qi.u.allocInfo.sectorsPerAllocUnit = 1;
         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
@@ -2480,23 +2724,35 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
 
     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: 
         /* 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: 
         /* 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;
@@ -2507,15 +2763,19 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
 
     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: 
         /* 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
@@ -2523,12 +2783,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;
@@ -2548,9 +2826,9 @@ 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;
 };      
 
@@ -2558,27 +2836,37 @@ 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;
@@ -2586,10 +2874,11 @@ 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(spacep->wdata, &lastNamep, pathp);
 
-    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
-                     reqp, &dscp);
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+                    caseFold, userp, tidPathp,
+                    reqp, &dscp);
     cm_FreeSpace(spacep);
     if (code) 
         return code;
@@ -2598,6 +2887,9 @@ long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
     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 */
@@ -2622,6 +2914,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;
@@ -2632,20 +2925,20 @@ 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) 
@@ -2673,11 +2966,9 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return 0;
     }
 
-    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);
 
@@ -2728,12 +3019,12 @@ 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(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_data.rootSCachep, spacep->wdata,
                                  CM_FLAG_CASEFOLD
                                  | CM_FLAG_DIRSEARCH
                                  | CM_FLAG_FOLLOW,
@@ -2741,18 +3032,22 @@ 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) {
-                        if ( WANTS_DFS_PATHNAMES(p) )
+                        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+                                                                  spacep->wdata);
+                        if ( WANTS_DFS_PATHNAMES(p) || pnc )
                             code = CM_ERROR_PATH_NOT_COVERED;
                         else
-                            code = CM_ERROR_BADSHARENAME;
+                            code = CM_ERROR_NOSUCHPATH;
                     } else
 #endif /* DFS_SUPPORT */
                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
                         code = CM_ERROR_NOSUCHFILE;
                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
                         cm_buf_t *bp = buf_Find(dscp, &hzero);
-                        if (bp)
+                        if (bp) {
                             buf_Release(bp);
+                            bp = NULL;
+                        }
                         else
                             code = CM_ERROR_NOSUCHFILE;
                     }
@@ -2785,26 +3080,33 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
 #ifdef DFS_SUPPORT
     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
-        if ( WANTS_DFS_PATHNAMES(p) )
+        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;
     }
 #endif /* DFS_SUPPORT */
 
-    lock_ObtainMutex(&scp->mx);
-    scp_mx_held = 1;
+    lock_ObtainWrite(&scp->rw);
+    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.
      */
@@ -2812,20 +3114,19 @@ 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);
+        smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
+       qpi.u.QPfileAltNameInfo.fileNameLength = len;
 
         goto done;
     }
     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
-       len = strlen(lastComp);
-       qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
+        smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
+       qpi.u.QPfileNameInfo.fileNameLength = len;
 
         goto done;
     }
@@ -2851,7 +3152,11 @@ 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;
@@ -2863,8 +3168,6 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         qpi.u.QPfileStandardInfo.reserved = 0;
 
        if (fidp) {
-           lock_ReleaseMutex(&scp->mx);
-           scp_mx_held = 0;
            lock_ObtainMutex(&fidp->mx);
            delonclose = fidp->flags & SMB_FID_DELONCLOSE;
            lock_ReleaseMutex(&fidp->mx);
@@ -2901,15 +3204,22 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
        qpi.u.QPfileAllInfo.mode = 0;
        qpi.u.QPfileAllInfo.alignmentRequirement = 0;
-       len = 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;
     }
 
     /* send and free the packets */
   done:
-    if (scp_mx_held)
-       lock_ReleaseMutex(&scp->mx);
+    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) {
@@ -2923,6 +3233,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
@@ -2930,19 +3241,18 @@ 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);
@@ -2951,15 +3261,15 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        infoLevel != SMB_INFO_QUERY_ALL_EAS) {
         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
+        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) {
@@ -2996,12 +3306,12 @@ 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(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_data.rootSCachep, spacep->wdata,
                                  CM_FLAG_CASEFOLD
                                  | CM_FLAG_DIRSEARCH
                                  | CM_FLAG_FOLLOW,
@@ -3009,18 +3319,22 @@ 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) {
-                        if ( WANTS_DFS_PATHNAMES(p) )
+                        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
+                                                                  spacep->wdata);
+                        if ( WANTS_DFS_PATHNAMES(p) || pnc )
                             code = CM_ERROR_PATH_NOT_COVERED;
                         else
-                            code = CM_ERROR_BADSHARENAME;
+                            code = CM_ERROR_NOSUCHPATH;
                     } else
 #endif /* DFS_SUPPORT */
                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
                         code = CM_ERROR_NOSUCHFILE;
                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
                         cm_buf_t *bp = buf_Find(dscp, &hzero);
-                        if (bp)
+                        if (bp) {
                             buf_Release(bp);
+                            bp = NULL;
+                        }
                         else
                             code = CM_ERROR_NOSUCHFILE;
                     }
@@ -3048,25 +3362,6 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         return 0;
     }
 
-    fidp = smb_FindFIDByScache(vcp, scp);
-    if (!fidp) {
-        cm_ReleaseSCache(scp);
-        cm_ReleaseUser(userp);
-       smb_SendTran2Error(vcp, p, opx, code);
-        return 0;
-    }
-
-    lock_ObtainMutex(&fidp->mx);
-    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
-       lock_ReleaseMutex(&fidp->mx);
-        cm_ReleaseSCache(scp);
-        smb_ReleaseFID(fidp);
-        cm_ReleaseUser(userp);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
-        return 0;
-    }
-    lock_ReleaseMutex(&fidp->mx);
-
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
 
     outp->totalParms = 2;
@@ -3079,20 +3374,16 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         /* lock the vnode with a callback; we need the current status
          * to determine what the new status is, in some cases.
          */
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_SyncOp(scp, NULL, userp, &req, 0,
                           CM_SCACHESYNC_GETSTATUS
                          | CM_SCACHESYNC_NEEDCALLBACK);
         if (code) {
-           lock_ReleaseMutex(&scp->mx);
+           lock_ReleaseWrite(&scp->rw);
             goto done;
         }
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-       lock_ReleaseMutex(&scp->mx);
-       lock_ObtainMutex(&fidp->mx);
-       lock_ObtainMutex(&scp->mx);
-
         /* prepare for setattr call */
         attr.mask = CM_ATTRMASK_LENGTH;
         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
@@ -3101,7 +3392,6 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
            smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
-            fidp->flags |= SMB_FID_MTIMESETDONE;
         }
                
         if (spi->u.QPstandardInfo.attributes != 0) {
@@ -3118,8 +3408,7 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                 attr.unixModeBits = scp->unixModeBits | 0222;
             }
         }
-        lock_ReleaseMutex(&scp->mx);
-       lock_ReleaseMutex(&fidp->mx);
+        lock_ReleaseRead(&scp->rw);
 
         /* call setattr */
         if (attr.mask)
@@ -3129,13 +3418,12 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     }               
     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
        /* we don't support EAs */
-       code = CM_ERROR_INVAL;
+       code = CM_ERROR_EAS_NOT_SUPPORTED;
     }       
 
   done:
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
-    smb_ReleaseFID(fidp);
     if (code == 0) 
         smb_SendTran2Packet(vcp, outp, opx);
     else 
@@ -3146,6 +3434,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;
@@ -3160,9 +3449,10 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     cm_scache_t *scp;
     smb_tran2QFileInfo_t qfi;
     long code = 0;
+    int  readlock = 0;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = p->parmsp[0];
     fidp = smb_FindFID(vcp, fid, 0);
@@ -3172,6 +3462,16 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         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) 
         responseSize = sizeof(qfi.u.QFbasicInfo);
@@ -3211,7 +3511,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) 
@@ -3219,6 +3519,9 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
+    lock_ConvertWToR(&scp->rw);
+    readlock = 1;
+
     /* now we have the status in the cache entry, and everything is locked.
      * Marshall the output data.
      */
@@ -3245,26 +3548,29 @@ 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_ReleaseMutex(&scp->mx);
+       lock_ReleaseRead(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainRead(&scp->rw);
         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);
+        outp->totalData = len + 4;     /* this is actually what we want to return */
+        qfi.u.QFfileNameInfo.fileNameLength = len;
     }
 
     /* send and free the packets */
   done:
-    lock_ReleaseMutex(&scp->mx);
+    if (readlock)
+        lock_ReleaseRead(&scp->rw);
+    else
+        lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
@@ -3279,6 +3585,8 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return 0;
 }       
 
+
+/* TRANS2_SET_FILE_INFORMATION */
 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     long code = 0;
@@ -3286,11 +3594,11 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     smb_fid_t *fidp;
     unsigned short infoLevel;
     smb_tran2Packet_t *outp;
-    cm_user_t *userp;
-    cm_scache_t *scp;
+    cm_user_t *userp = NULL;
+    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);
@@ -3311,10 +3619,18 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     }
 
     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;
+    }
+
     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, scp, fidp->flags);
+                 fidp, fidp->scp, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
@@ -3324,7 +3640,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         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", 
-                 fidp, scp, fidp->flags);
+                 fidp, fidp->scp, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
@@ -3359,20 +3675,20 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        /* lock the vnode with a callback; we need the current status
          * to determine what the new status is, in some cases.
          */
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_SyncOp(scp, NULL, userp, &req, 0,
                           CM_SCACHESYNC_GETSTATUS
                          | CM_SCACHESYNC_NEEDCALLBACK);
         if (code) {
-           lock_ReleaseMutex(&scp->mx);
+           lock_ReleaseWrite(&scp->rw);
             goto done;
        }
 
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-       lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseWrite(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainRead(&scp->rw);
 
         /* prepare for setattr call */
         attr.mask = 0;
@@ -3404,7 +3720,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                 attr.unixModeBits = scp->unixModeBits | 0222;
             }
         }
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseRead(&scp->rw);
        lock_ReleaseMutex(&fidp->mx);
 
         /* call setattr */
@@ -3460,6 +3776,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     return 0;
 }
 
+/* TRANS2_FSCTL */
 long 
 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3467,6 +3784,7 @@ smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_IOCTL2 */
 long 
 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3474,6 +3792,7 @@ smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_FIND_NOTIFY_FIRST */
 long 
 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3481,6 +3800,7 @@ smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_FIND_NOTIFY_NEXT */
 long 
 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3488,6 +3808,7 @@ smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_CREATE_DIRECTORY */
 long 
 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3495,6 +3816,7 @@ smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     return CM_ERROR_BADOP;
 }
 
+/* TRANS2_SESSION_SETUP */
 long 
 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3512,6 +3834,7 @@ struct smb_v2_referral {
     USHORT NetworkAddressOffset;
 };
 
+/* TRANS2_GET_DFS_REFERRAL */
 long 
 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
@@ -3527,79 +3850,181 @@ 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] = "";
+    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;
+    cm_scache_t *dscp = 0;
     cm_req_t req;
     CPINFO CodePageInfo;
-    int i, nbnLen, reqLen;
+    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 = strlen(cm_NetbiosName);
-    reqLen = strlen(requestFileName);
+    nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
+    reqLen = (int)cm_ClientStrLen(requestFileName);
 
-    if (reqLen == nbnLen + 5 &&
-        requestFileName[0] == '\\' &&
-        !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
-        requestFileName[nbnLen+1] == '\\' &&
-        (!_strnicmp("all",&requestFileName[nbnLen+2],3) || 
-         !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
+    if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
+        !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
+        requestFileName[nbnLen+1] == '\\') 
     {
-        USHORT * sp;
-        struct smb_v2_referral * v2ref;
-        outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
-
-        sp = (USHORT *)outp->datap;
-        idx = 0;
-        sp[idx++] = reqLen;   /* path consumed */
-        sp[idx++] = 1;        /* number of referrals */
-        sp[idx++] = 0x03;     /* flags */
+        int found = 0;
+
+        if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
+            !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
+            found = 1;
+            cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
+            refLen = reqLen;
+        } else {
+            userp = smb_GetTran2User(vcp, p);
+            if (!userp) {
+                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 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.
+             */
+            code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
+                            CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
+                            userp, NULL, &req, &scp);
+            if (code == 0) {
+                /* Yes it is. */
+                found = 1;
+                cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
+                refLen = reqLen;
+            } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
+                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);
+
+                cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
+
+                do {
+                    if (dscp) {
+                        cm_ReleaseSCache(dscp);
+                        dscp = 0;
+                    }
+                    if (scp) {
+                        cm_ReleaseSCache(scp);
+                        scp = 0;
+                    }
+                    smb_StripLastComponent(pathName, &lastComponent, temp);
+
+                    code = cm_NameI(cm_data.rootSCachep, pathName,
+                                    CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                                    userp, NULL, &req, &dscp);
+                    if (code == 0) {
+                        code = cm_NameI(dscp, ++lastComponent,
+                                        CM_FLAG_CASEFOLD,
+                                        userp, NULL, &req, &scp);
+                        if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
+                            break;
+                    }
+                } while (code == CM_ERROR_PATH_NOT_COVERED);
+
+                /* 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 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
+
+                    cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
+                                              referralPath, lengthof(referralPath));
+                    refLen = (int)cm_ClientStrLen(referralPath);
+                    found = 1;
+                }
+            } else {
+                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++)
+                {
+                    *q = *p;
+                }
+                *q = '\0';
+                
+                if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
+                    code = cm_NameI(cm_data.rootSCachep, _C(""), 
+                                    CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                                    userp, p, &req, &scp);
+                    free(p);
+
+                    if (code == 0) {
+                        found = 1;
+                        cm_ClientStrCpy(referralPath, lengthof(referralPath),
+                                        requestFileName);
+                        refLen = reqLen;
+                    }
+                }
+            }
+        }
+        
+        if (found)
+        {
+            USHORT * sp;
+            struct smb_v2_referral * v2ref;
+            outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
+
+            sp = (USHORT *)outp->datap;
+            idx = 0;
+            sp[idx++] = reqLen;   /* path consumed */
+            sp[idx++] = 1;        /* number of referrals */
+            sp[idx++] = 0x03;     /* flags */
 #ifdef DFS_VERSION_1
-        sp[idx++] = 1;        /* Version Number */
-        sp[idx++] = reqLen + 4;  /* Referral Size */ 
-        sp[idx++] = 1;        /* Type = SMB Server */
-        sp[idx++] = 0;        /* Do not strip path consumed */
-        for ( i=0;i<=reqLen; i++ )
-            sp[i+idx] = requestFileName[i];
+            sp[idx++] = 1;        /* Version Number */
+            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++ )
+                sp[i+idx] = referralPath[i];
 #else /* DFS_VERSION_2 */
-        sp[idx++] = 2;      /* Version Number */
-        sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
-        idx += (sizeof(struct smb_v2_referral) / 2);
-        v2ref = (struct smb_v2_referral *) &sp[5];
-        v2ref->ServerType = 1;  /* SMB Server */
-        v2ref->ReferralFlags = 0x03;
-        v2ref->Proximity = 0;   /* closest */
-        v2ref->TimeToLive = 3600; /* seconds */
-        v2ref->DfsPathOffset = idx * 2;
-        v2ref->DfsAlternativePathOffset = idx * 2;
-        v2ref->NetworkAddressOffset = 0;
-        for ( i=0;i<=reqLen; i++ )
-            sp[i+idx] = requestFileName[i];
+            sp[idx++] = 2;      /* Version Number */
+            sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
+            idx += (sizeof(struct smb_v2_referral) / 2);
+            v2ref = (struct smb_v2_referral *) &sp[5];
+            v2ref->ServerType = 1;  /* SMB Server */
+            v2ref->ReferralFlags = 0x03;
+            v2ref->Proximity = 0;   /* closest */
+            v2ref->TimeToLive = 3600; /* seconds */
+            v2ref->DfsPathOffset = idx * 2;
+            v2ref->DfsAlternativePathOffset = idx * 2;
+            v2ref->NetworkAddressOffset = 0;
+            for ( i=0;i<=refLen; i++ )
+                sp[i+idx] = referralPath[i];
 #endif
+        } 
     } else {
-        userp = smb_GetTran2User(vcp, p);
-        if (!userp) {
-            osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
-            code = CM_ERROR_BADSMB;
-            goto done;
-        }   
-
-               /* not done yet */
         code = CM_ERROR_NOSUCHPATH;
     }
-
+         
   done:
+    if (dscp)
+        cm_ReleaseSCache(dscp);
+    if (scp)
+        cm_ReleaseSCache(scp);
     if (userp)
         cm_ReleaseUser(userp);
     if (code == 0) 
@@ -3612,10 +4037,11 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return 0;
 #else /* DFS_SUPPORT */
     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
-    return CM_ERROR_BADOP;
+    return CM_ERROR_NOSUCHDEVICE;
 #endif /* DFS_SUPPORT */
 }
 
+/* TRANS2_REPORT_DFS_INCONSISTENCY */
 long 
 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
@@ -3632,130 +4058,217 @@ smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_
     return CM_ERROR_BADOP;
 }
 
-long 
-smb_ApplyV3DirListPatches(cm_scache_t *dscp,
-       smb_dirListPatch_t **dirPatchespp, 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;
+    clientchar_t path[AFSPATHMAX];
 
     code = cm_FindACLCache(dscp, userp, &rights);
-    if (code == 0 && !(rights & PRSFS_READ))
-        code = CM_ERROR_NOACCESS;
-    else if (code == -1) {
-        lock_ObtainMutex(&dscp->mx);
+    if (code == -1) {
+        lock_ObtainWrite(&dscp->rw);
         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        lock_ReleaseMutex(&dscp->mx);
+        if (code == 0) 
+            cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&dscp->rw);
+        if (code == CM_ERROR_NOACCESS) {
+            mustFake = 1;
+            code = 0;
+        }
     }
     if (code)
-        return code;
+        goto cleanup;
+
+    if (!mustFake) {    /* Bulk Stat */
+        afs_uint32 count;
+        cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
+
+        memset(bsp, 0, sizeof(cm_bulkStat_t));
+
+        for (patchp = *dirPatchespp, count=0; 
+             patchp; 
+             patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+            cm_scache_t *tscp = NULL;
+            int i;
+            
+            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;
 
-    for(patchp = *dirPatchespp; patchp; patchp =
-         (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
+        reqp->relPathp = reqp->tidPathp = NULL;
         if (code) 
             continue;
 
-        lock_ObtainMutex(&scp->mx);
-        code = cm_SyncOp(scp, NULL, userp, reqp, 0,
-                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        if (code) { 
-            lock_ReleaseMutex(&scp->mx);
-            cm_ReleaseSCache(scp);
-
-            dptr = patchp->dptr;
+        lock_ObtainWrite(&scp->rw);
+        if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
+            lock_ReleaseWrite(&scp->rw);
 
             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
                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_INVALID:
+                    fa->extFileAttributes = SMB_ATTR_DIRECTORY;
+                    break;
+                case CM_SCACHETYPE_SYMLINK:
+                    if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+                        fa->extFileAttributes = SMB_ATTR_DIRECTORY;
+                    else
+                        fa->extFileAttributes = SMB_ATTR_NORMAL;
+                    break;
+                default:
+                    /* if we get here we either have a normal file
+                     * or we have a file for which we have never 
+                     * received status info.  In this case, we can
+                     * check the even/odd value of the entry's vnode.
+                     * odd means it is to be treated as a directory
+                     * and even means it is to be treated as a file.
+                     */
+                    if (mustFake && (scp->fid.vnode & 0x1))
+                        fa->extFileAttributes = SMB_ATTR_DIRECTORY;
+                    else
+                        fa->extFileAttributes = SMB_ATTR_NORMAL;
+                }
                 /* merge in hidden attribute */
                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
-                    *((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_INVALID:
+                    fa->attributes = SMB_ATTR_DIRECTORY;
+                    break;
+                case CM_SCACHETYPE_SYMLINK:
+                    if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+                        fa->attributes = SMB_ATTR_DIRECTORY;
+                    else
+                        fa->attributes = SMB_ATTR_NORMAL;
+                    break;
+                default:
+                    /* 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_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
+            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);
+            reqp->relPathp = reqp->tidPathp = NULL;
             if (code == 0) {
                 /* we have a more accurate file to use (the
                  * target of the symbolic link).  Otherwise,
@@ -3766,40 +4279,32 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
         }
 
-        dptr = patchp->dptr;
+        lock_ConvertWToR(&scp->rw);
 
         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+            smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
+
             /* 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;
-
-            /* copy to Last Write Time */
-            *((FILETIME *)dptr) = ft;
-            dptr += 8;
-
-            /* 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;
                 else
@@ -3812,49 +4317,23 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
                 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;
+            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);
@@ -3865,11 +4344,10 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
                 else
                     lattr |= SMB_ATTR_HIDDEN;
             }
-            *dptr++ = attr & 0xff;
-            *dptr++ = (attr >> 8) & 0xff;
+            fa->attributes = attr;
         }
 
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseRead(&scp->rw);
         cm_ReleaseSCache(scp);
     }
         
@@ -3882,273 +4360,10 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
     /* and mark the list as empty */
     *dirPatchespp = NULL;
 
+  cleanup:
     return code;
 }
 
-#ifndef USE_OLD_MATCHING
-// 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;
-}
-
-#else /* USE_OLD_MATCHING */
-/* 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)
-{
-    unsigned char tcp1, tcp2;  /* Pattern characters */
-    unsigned char tcn1;                /* Name characters */
-    int sawDot = 0, sawStar = 0, req8dot3 = 0;
-    char *starNamep, *starMaskp;
-    static char nullCharp[] = {0};
-    int casefold = flags & CM_FLAG_CASEFOLD;
-
-    /* make sure we only match 8.3 names, if requested */
-    req8dot3 = (flags & CM_FLAG_8DOT3);
-    if (req8dot3 && !cm_Is8Dot3(namep)) 
-        return 0;
-
-    /* loop */
-    while (1) {
-        /* Next pattern character */
-        tcp1 = *maskp++;
-
-        /* Next name character */
-        tcn1 = *namep;
-
-        if (tcp1 == 0) {
-            /* 0 - end of pattern */
-            if (tcn1 == 0)
-                return 1;
-            else
-                return 0;
-        }
-        else if (tcp1 == '.' || tcp1 == '"') {
-            if (sawDot) {
-                if (tcn1 == '.') {
-                    namep++;
-                    continue;
-                } else
-                    return 0;
-            }
-            else {
-                /*
-                 * first dot in pattern;
-                 * must match dot or end of name
-                 */
-                sawDot = 1;
-                if (tcn1 == 0)
-                    continue;
-                else if (tcn1 == '.') {
-                    sawStar = 0;
-                    namep++;
-                    continue;
-                }
-                else
-                    return 0;
-            }
-        }
-        else if (tcp1 == '?') {
-            if (tcn1 == 0 || tcn1 == '.')
-                return 0;
-            namep++;
-            continue;
-        }
-        else if (tcp1 == '>') {
-            if (tcn1 != 0 && tcn1 != '.')
-                namep++;
-            continue;
-        }
-        else if (tcp1 == '*' || tcp1 == '<') {
-            tcp2 = *maskp++;
-            if (tcp2 == 0)
-                return 1;
-            else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
-                while (req8dot3 && tcn1 != '.' && tcn1 != 0)
-                    tcn1 = *++namep;
-                if (tcn1 == 0) {
-                    if (sawDot)
-                        return 0;
-                    else
-                        continue;
-                }
-                else {
-                    namep++;
-                    continue;
-                }
-            }
-            else {
-                /*
-                 * pattern character after '*' is not null or
-                 * period.  If it is '?' or '>', we are not
-                 * going to understand it.  If it is '*' or
-                 * '<', we are going to skip over it.  None of
-                 * these are likely, I hope.
-                 */
-                /* skip over '*' and '<' */
-                while (tcp2 == '*' || tcp2 == '<')
-                    tcp2 = *maskp++;
-
-                /* skip over characters that don't match tcp2 */
-                while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
-                        ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
-                          (!casefold && tcn1 != tcp2)))
-                    tcn1 = *++namep;
-
-                /* No match */
-                if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
-                    return 0;
-
-                /* Remember where we are */
-                sawStar = 1;
-                starMaskp = maskp;
-                starNamep = namep;
-
-                namep++;
-                continue;
-            }
-        }
-        else {
-            /* tcp1 is not a wildcard */
-            if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
-                 (!casefold && tcn1 == tcp1)) {
-                /* they match */
-                namep++;
-                continue;
-            }
-            /* if trying to match a star pattern, go back */
-            if (sawStar) {
-                maskp = starMaskp - 2;
-                namep = starNamep + 1;
-                sawStar = 0;
-                continue;
-            }
-            /* that's all */
-            return 0;
-        }
-    }
-}
-#endif /* USE_OLD_MATCHING */
-
 /* smb_ReceiveTran2SearchDir implements both 
  * Tran2_Find_First and Tran2_Find_Next
  */
@@ -4166,45 +4381,50 @@ int smb_V3MatchMask(char *namep, char *maskp, int flags)
    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;
+    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_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;
+    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;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     eos = 0;
-    osi_assert(p->opcode == 1);
+    osi_assertx(p->opcode == 1, "invalid opcode");
 
     /* find first; obtain basic parameters from request */
 
@@ -4215,43 +4435,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, '\\');
+    maskp = cm_ClientStrRChr(pathp,  '\\');
     if (maskp == NULL) 
        maskp = pathp;
     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);
@@ -4260,7 +4495,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
              "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;
     }
@@ -4268,22 +4503,20 @@ 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) {
@@ -4293,14 +4526,14 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
         
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
-       osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
+       osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
        smb_FreeTran2Packet(outp);
        return CM_ERROR_BADSMB;
     }
 
     /* try to get the vnode for the path name next */
     spacep = cm_GetSpace();
-    smb_StripLastComponent(spacep->data, NULL, pathp);
+    smb_StripLastComponent(spacep->wdata, NULL, pathp);
     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
     if (code) {
         cm_ReleaseUser(userp);
@@ -4309,7 +4542,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_data.rootSCachep, spacep->wdata,
                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                     userp, tidPathp, &req, &scp);
     cm_FreeSpace(spacep);
@@ -4323,31 +4556,26 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
        cm_ReleaseSCache(scp);
        cm_ReleaseUser(userp);
-       if ( WANTS_DFS_PATHNAMES(p) )
+        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;
     }
 #endif /* DFS_SUPPORT */
-    osi_Log1(smb_logp,"smb_ReceiveTran2SearchDir scp 0x%p", scp);
-    lock_ObtainMutex(&scp->mx);
-    if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
-        LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
-       scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
-    }
-    lock_ReleaseMutex(&scp->mx);
+    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);
 
     /* if a case sensitive match failed, we try a case insensitive one
        next. */
-    if (code == CM_ERROR_NOSUCHFILE) {
+    if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
         code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
     }
 
@@ -4362,7 +4590,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
            smb_ReceiveTran2SearchDir(). */
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
-       if (code != CM_ERROR_NOSUCHFILE) {
+       if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
            smb_SendTran2Error(vcp, p, opx, code);
            code = 0;
        }
@@ -4381,6 +4609,8 @@ 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)) {
@@ -4389,17 +4619,17 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
         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)",
+             htonl(targetscp->fid.vnode),
+             htonl(targetscp->fid.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) &&
@@ -4413,6 +4643,7 @@ 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)) {
 
@@ -4422,29 +4653,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 = 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
@@ -4472,42 +4684,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);
 
-    /* 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
+            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;
@@ -4515,13 +4764,17 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
             curPatchp->flags = 0;
         }
 
-        curPatchp->fid.cell = targetscp->fid.cell;
-        curPatchp->fid.volume = targetscp->fid.volume;
-        curPatchp->fid.vnode = targetscp->fid.vnode;
-        curPatchp->fid.unique = targetscp->fid.unique;
+        cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
 
         /* temp */
-        curPatchp->dep = NULL;
+        {
+            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);
+        }
+        dep->fid.vnode = targetscp->fid.vnode;
+        dep->fid.unique = targetscp->fid.unique;
+        curPatchp->dep = dep;
     }   
 
     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
@@ -4540,7 +4793,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     }
 
     /* apply the patches */
-    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, 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 */
@@ -4554,7 +4807,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
     osi_Log0(smb_logp, "T2SDSingle done.");
 
-    if (code != CM_ERROR_NOSUCHFILE) {
+    if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
        if (code)
            smb_SendTran2Error(vcp, p, opx, code);
        else
@@ -4564,6 +4817,9 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
  skip_file:
     smb_FreeTran2Packet(outp);
+    if (dep)
+        free(dep);
+    if (scp)
     cm_ReleaseSCache(scp);
     cm_ReleaseSCache(targetscp);
     cm_ReleaseUser(userp);
@@ -4572,22 +4828,23 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 }
 
 
+/* 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;
-    cm_dirEntry_t *dep;
+    clientchar_t *pathp;
+    cm_dirEntry_t *dep = 0;
     int maxCount;
-    smb_dirListPatch_t *dirListPatchesp;
-    smb_dirListPatch_t *curPatchp;
+    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;
@@ -4605,27 +4862,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) {
@@ -4634,11 +4893,9 @@ 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, '\\');
+        maskp = cm_ClientStrRChr(pathp,  '\\');
         if (maskp == NULL) 
             maskp = pathp;
         else 
@@ -4656,17 +4913,23 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
             /* we only failover if we see a CM_ERROR_NOSUCHFILE */
             if (code != CM_ERROR_NOSUCHFILE) {
+#ifdef USE_BPLUS
+                /* unless we are using the BPlusTree */
+                if (code == CM_ERROR_BPLUS_NOMATCH)
+                    code = CM_ERROR_NOSUCHFILE;
+#endif /* USE_BPLUS */
                 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_assert(p->opcode == 2);
+        osi_assertx(p->opcode == 2, "invalid opcode");
         /* find next; obtain basic parameters from request or open dir file */
         dsp = smb_FindDirSearch(p->parmsp[0]);
         maxCount = p->parmsp[1];
@@ -4687,27 +4950,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);
@@ -4719,7 +4997,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;
@@ -4728,6 +5006,9 @@ 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;
@@ -4736,16 +5017,14 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     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) {
@@ -4774,7 +5053,7 @@ 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(spacep->wdata, NULL, pathp);
         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
         if (code) {
             cm_ReleaseUser(userp);
@@ -4785,7 +5064,11 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             smb_ReleaseDirSearch(dsp);
             return 0;
         }
-        code = cm_NameI(cm_data.rootSCachep, 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->wdata,
                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &scp);
         cm_FreeSpace(spacep);
@@ -4793,12 +5076,13 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         if (code == 0) {
 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+                int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
                 cm_ReleaseSCache(scp);
                 cm_ReleaseUser(userp);
-                if ( WANTS_DFS_PATHNAMES(p) )
+                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);
@@ -4816,13 +5100,7 @@ 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_ObtainMutex(&scp->mx);
-            if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
-                 LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
-                scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
-                dsp->flags |= SMB_DIRSEARCH_BULKST;
-            }
-            lock_ReleaseMutex(&scp->mx);
+            dsp->flags |= SMB_DIRSEARCH_BULKST;
         } 
     }
     lock_ReleaseMutex(&dsp->mx);
@@ -4835,11 +5113,11 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     }
 
     /* get the directory size */
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) {
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         smb_FreeTran2Packet(outp);
@@ -4863,11 +5141,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,
@@ -4909,6 +5192,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.
@@ -4921,35 +5220,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 buf_Release(bufferp);
                 bufferp = NULL;
             }       
-            lock_ReleaseMutex(&scp->mx);
-            lock_ObtainRead(&scp->bufCreateLock);
-            code = buf_Get(scp, &thyper, &bufferp);
-            lock_ReleaseRead(&scp->bufCreateLock);
-            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) {
-                smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
-                                           infoLevel, userp,
-                                           &req);
-                lock_ObtainMutex(&scp->mx);
-                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) {
-                        scp->bulkStatProgress = thyper;
-                        scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
-                        dsp->flags &= ~SMB_DIRSEARCH_BULKST;
-                    } else
-                        code = cm_TryBulkStat(scp, &thyper, userp, &req);
-                }
-            } else {
-                lock_ObtainMutex(&scp->mx);
-            }
-            lock_ReleaseMutex(&dsp->mx);
+            lock_ReleaseWrite(&scp->rw);
+            code = buf_Get(scp, &thyper, &req, &bufferp);
+            lock_ObtainWrite(&scp->rw);
             if (code) {
                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
                 break;
@@ -4968,16 +5241,16 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                     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", 
                               scp, bufferp, code);
@@ -5033,130 +5306,158 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         /* compute offset of cookie representing next entry */
         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
 
+        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
-             && dep->fid.vnode != 0
-             && !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 (dep->fid.vnode != 0 && 
-            (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)) {
+                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 */
-                fid.cell = scp->fid.cell;
-                fid.volume = scp->fid.volume;
-                fid.vnode = ntohl(dep->fid.vnode);
-                fid.unique = 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);*/
-                if (fileType == CM_SCACHETYPE_DIRECTORY ||
-                    fileType == CM_SCACHETYPE_DFSLINK ||
-                    fileType == CM_SCACHETYPE_INVALID)
+                /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
+                 * "has filetype %d", dep->name, fileType);
+                 */
+                if ( fileType == CM_SCACHETYPE_DIRECTORY ||
+                     fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                     fileType == CM_SCACHETYPE_DFSLINK ||
+                     fileType == CM_SCACHETYPE_INVALID)
                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
-                    goto nextEntry;
+                goto nextEntry;
             }
 
             /* 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
              * even the aligned version (so we don't have to worry
-             * about an * overflow when we pad things out below).
+             * about an overflow when we pad things out below).
              * That's the reason for the alignment arithmetic below.
              */
             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
                 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);
+
+            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;
 
-            /* Short name if requested and needed */
-            if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+            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
@@ -5171,23 +5472,18 @@ 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;
+                osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
+                curPatchp->dptr = attrp;
 
-                if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
+                if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
-                }       
-                else    
+                } else {
                     curPatchp->flags = 0;
+                }
 
-                curPatchp->fid.cell = scp->fid.cell;
-                curPatchp->fid.volume = scp->fid.volume;
-                curPatchp->fid.vnode = ntohl(dep->fid.vnode);
-                curPatchp->fid.unique = ntohl(dep->fid.unique);
+                cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
 
                 /* temp */
                 curPatchp->dep = dep;
@@ -5202,19 +5498,18 @@ 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 &&
-                 dep->fid.vnode != 0 &&
-                 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
+                 cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
             /* We were looking for exact matches, but here's an inexact one*/
             foundInexact = 1;
         }
-                
+
       nextEntry:
         /* and adjust curOffset to be where the new cookie is */
         thyper.HighPart = 0;
@@ -5234,18 +5529,18 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     }
 
     /* release the mutex */
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     if (bufferp) {
         buf_Release(bufferp);
        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, infoLevel, userp,
-                              &req);
-        
+    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
+                                      dsp->relPath, infoLevel, userp, &req);
+
     /* now put out the final parameters */
     if (returnedNames == 0) 
         eos = 1;
@@ -5304,6 +5599,7 @@ 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;
@@ -5328,15 +5624,18 @@ long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     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;
@@ -5347,19 +5646,19 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     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;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     scp = NULL;
         
@@ -5378,14 +5677,19 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     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;
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
-    if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+    if (lastNamep && 
+        (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
+         cm_ClientStrCmpIA(lastNamep,  _C("\\srvsvc")) == 0 ||
+         cm_ClientStrCmpIA(lastNamep,  _C("\\wkssvc")) == 0 ||
+         cm_ClientStrCmpIA(lastNamep,  _C("ipc$")) == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
@@ -5425,6 +5729,21 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return 0;
     }
 
+    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;
@@ -5448,17 +5767,18 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
 #ifdef DFS_SUPPORT
     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
-        if ( WANTS_DFS_PATHNAMES(inp) )
+        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,
+        code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &dscp);
         if (code) {
@@ -5468,12 +5788,14 @@ 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->wdata);
             cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
-            if ( WANTS_DFS_PATHNAMES(inp) )
+            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,
@@ -5486,7 +5808,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             lastNamep++;
         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
                           &req, &scp);
-        if (code && code != CM_ERROR_NOSUCHFILE) {
+        if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
             cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
             return code;
@@ -5532,9 +5854,9 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_NOSUCHFILE;
     }
     else {
-        osi_assert(dscp != NULL);
-        osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
-                 osi_LogSaveString(smb_logp, lastNamep));
+        osi_assertx(dscp != NULL, "null cm_scache_t");
+        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);
@@ -5587,15 +5909,15 @@ 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_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
        
     cm_HoldUser(userp);
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
     fidp->scp = scp;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
     /* also the user */
     fidp->userp = userp;
@@ -5621,7 +5943,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* copy out remainder of the parms */
     parmSlot = 2;
     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainRead(&scp->rw);
     if (extraInfo) {
         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
@@ -5639,7 +5961,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseRead(&scp->rw);
     smb_SetSMBDataLength(outp, 0);
 
     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
@@ -5675,6 +5997,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;
@@ -5684,7 +6007,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_scache_t *scp;
     unsigned char LockType;
     unsigned short NumberOfUnlocks, NumberOfLocks;
-    long Timeout;
+    afs_uint32 Timeout;
     char *op;
     char *op_locks;
     LARGE_INTEGER LOffset, LLength;
@@ -5695,7 +6018,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_key_t key;
     unsigned int pid;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = smb_GetSMBParm(inp, 2);
     fid = smb_ChainFID(fid, inp);
@@ -5705,6 +6028,13 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        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;
+    }
+
     if (fidp->flags & SMB_FID_IOCTL) {
         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
        lock_ReleaseMutex(&fidp->mx);
@@ -5721,8 +6051,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     userp = smb_GetUserFromVCP(vcp, inp);
 
-
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK
                         | CM_SCACHESYNC_GETSTATUS
@@ -5745,18 +6074,9 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LockType |= LOCKING_ANDX_SHARED_LOCK;
     }
 
-    if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
-        (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
-
-        /* We don't support these requests.  Apparently, we can safely
-           not deal with them too. */
-        osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
-                 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
-                  "LOCKING_ANDX_CANCEL_LOCK":
-                  "LOCKING_ANDX_CHANGE_LOCKTYPE")); 
-        /* No need to call osi_LogSaveString since these are string
-           constants.*/
-
+    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]"); 
         code = CM_ERROR_BADOP;
         goto done;
 
@@ -5764,12 +6084,41 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     op = smb_GetSMBData(inp, NULL);
 
+    if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
+        /* Cancel outstanding lock requests */
+        smb_waitingLock_t * wl;
+
+        for (i=0; i<NumberOfLocks; i++) {
+            smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
+
+            key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+            lock_ObtainWrite(&smb_globalLock);
+            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 (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) && 
+                        LargeIntegerEqualTo(wl->LLength, LLength)) {
+                        wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
+                        goto found_lock_request;
+                    }
+                }
+            }
+          found_lock_request:
+            lock_ReleaseWrite(&smb_globalLock);
+        }
+        code = 0;
+        smb_SetSMBDataLength(outp, 0);
+        goto done;
+    }
+
+
     for (i=0; i<NumberOfUnlocks; i++) {
         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
 
         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) 
             goto done;
@@ -5804,7 +6153,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
 
-                osi_assert(wlRequest != NULL);
+                osi_assertx(wlRequest != NULL, "null wlRequest");
 
                 wlRequest->vcp = vcp;
                 smb_HoldVC(vcp);
@@ -5814,7 +6163,8 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 wlRequest->inp = smb_CopyPacket(inp);
                 wlRequest->outp = smb_CopyPacket(outp);
                 wlRequest->lockType = LockType;
-                wlRequest->timeRemaining = Timeout;
+                wlRequest->msTimeout = Timeout;
+                wlRequest->start_t = osi_Time();
                 wlRequest->locks = NULL;
 
                 /* The waiting lock request needs to have enough
@@ -5835,7 +6185,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
                     wLock = malloc(sizeof(smb_waitingLock_t));
 
-                    osi_assert(wLock != NULL);
+                    osi_assertx(wLock != NULL, "null smb_waitingLock_t");
 
                     wLock->key = tkey;
                     wLock->LOffset = tOffset;
@@ -5849,7 +6199,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
             wLock = malloc(sizeof(smb_waitingLock_t));
 
-            osi_assert(wLock != NULL);
+            osi_assertx(wLock != NULL, "null smb_waitingLock_t");
 
             wLock->key = key;
             wLock->LOffset = LOffset;
@@ -5890,7 +6240,7 @@ 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);
@@ -5934,7 +6284,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
 
   doneSync:
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
@@ -5942,6 +6292,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return code;
 }
 
+/* SMB_COM_QUERY_INFORMATION2 */
 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -5951,8 +6302,9 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     afs_uint32 searchTime;
     cm_user_t *userp;
     cm_req_t req;
+    int readlock = 0;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = smb_GetSMBParm(inp, 0);
     fid = smb_ChainFID(fid, inp);
@@ -5962,6 +6314,13 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
        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;
+    }
+
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
        smb_ReleaseFID(fidp);
@@ -5976,7 +6335,7 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         
         
     /* otherwise, stat the file */
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) 
@@ -5984,6 +6343,9 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
     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.
@@ -6010,13 +6372,17 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     code = 0;
 
   done:
-    lock_ReleaseMutex(&scp->mx);
+    if (readlock) 
+        lock_ReleaseRead(&scp->rw);
+    else
+        lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
     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;
@@ -6029,7 +6395,7 @@ 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);
@@ -6039,6 +6405,13 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
        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;
+    }
+
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
        smb_ReleaseFID(fidp);
@@ -6051,7 +6424,6 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         
     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.
@@ -6080,6 +6452,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;
@@ -6087,7 +6460,9 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     unsigned short fd;
     unsigned pid;
     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;
@@ -6125,13 +6500,30 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         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;
+    }
+
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
         code = smb_IoctlV3Write(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
@@ -6144,7 +6536,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LARGE_INTEGER LOffset;
         LARGE_INTEGER LLength;
 
-        pid = ((smb_t *) inp)->pid;
+        pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
         LOffset.HighPart = offset.HighPart;
@@ -6152,9 +6544,9 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainMutex(&fidp->scp->mx);
-        code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&scp->rw);
+        code = cm_LockCheckWrite(scp, LOffset, LLength, key);
+        lock_ReleaseWrite(&scp->rw);
 
         if (code)
             goto done;
@@ -6172,8 +6564,8 @@ 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);
+        scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
+        scp->clientModTime = time(NULL);
     }
     lock_ReleaseMutex(&fidp->mx);
 
@@ -6190,8 +6582,6 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         written = 0;
     }
 
- done_writing:
-    
     /* slots 0 and 1 are reserved for request chaining and will be
        filled in when we return. */
     smb_SetSMBParm(outp, 2, total_written);
@@ -6201,12 +6591,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;
@@ -6215,7 +6608,9 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     unsigned short fd;
     unsigned pid;
     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;
@@ -6255,7 +6650,25 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADFD;
     }
 
-    pid = ((smb_t *) inp)->pid;
+    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;
+    }
+
+    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;
@@ -6265,10 +6678,11 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainMutex(&fidp->scp->mx);
-        code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&scp->rw);
+        code = cm_LockCheckRead(scp, LOffset, LLength, key);
+        lock_ReleaseWrite(&scp->rw);
     }
+    cm_ReleaseSCache(scp);
 
     if (code) {
         smb_ReleaseFID(fidp);
@@ -6351,10 +6765,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;
@@ -6362,8 +6783,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;
@@ -6387,13 +6808,15 @@ 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;
 
-    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 
@@ -6448,22 +6871,26 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (extAttributes & SMB_ATTR_READONLY) 
         initialModeBits &= ~0222;
 
-    pathp = smb_GetSMBData(inp, NULL);
+    pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
+                              NULL, SMB_STRF_ANSIPATH);
+
     /* Sometimes path is not null-terminated, so we make a copy. */
-    realPathp = malloc(nameLength+1);
-    memcpy(realPathp, pathp, nameLength);
-    realPathp[nameLength] = 0;
-    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(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 (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+       if (lastNamep && 
+            (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
+             cm_ClientStrCmpIA(lastNamep,  _C("\\srvsvc")) == 0 ||
+             cm_ClientStrCmpIA(lastNamep,  _C("\\wkssvc")) == 0 ||
+             cm_ClientStrCmpIA(lastNamep,  _C("ipc$")) == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
@@ -6500,15 +6927,21 @@ 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);
+    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) {
@@ -6542,17 +6975,26 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             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);
+            return CM_ERROR_NOSUCHPATH;
+        }
+
         baseDirp = baseFidp->scp;
         tidPathp = NULL;
     }
 
-    osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
+    osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
 
     /* compute open mode */
     fidflags = 0;
     if (desiredAccess & DELETE)
         fidflags |= SMB_FID_OPENDELETE;
-    if (desiredAccess & AFS_ACCESS_READ)
+    if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
         fidflags |= SMB_FID_OPENREAD_LISTDIR;
     if (desiredAccess & AFS_ACCESS_WRITE)
         fidflags |= SMB_FID_OPENWRITE;
@@ -6562,6 +7004,10 @@ 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;
 
     /* and the share mode */
     if (shareAccess & FILE_SHARE_READ)
@@ -6576,25 +7022,27 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     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->wdata);
                 cm_ReleaseSCache(dscp);
                 cm_ReleaseUser(userp);
                 free(realPathp);
                if (baseFidp) 
                    smb_ReleaseFID(baseFidp);
-                if ( WANTS_DFS_PATHNAMES(inp) )
+                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) {
+            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) {
@@ -6614,15 +7062,16 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                         userp, tidPathp, &req, &scp);
 #ifdef DFS_SUPPORT
         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
            if (baseFidp) 
                smb_ReleaseFID(baseFidp);
-            if ( WANTS_DFS_PATHNAMES(inp) )
+            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 */
@@ -6642,14 +7091,16 @@ 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->wdata);
                     if (scp)
                         cm_ReleaseSCache(scp);
                     cm_ReleaseSCache(dscp);
@@ -6657,20 +7108,20 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                     free(realPathp);
                    if (baseFidp) 
                        smb_ReleaseFID(baseFidp);
-                    if ( WANTS_DFS_PATHNAMES(inp) )
+                    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 &&
+                    (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);
@@ -6740,7 +7191,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                                  userp, &req, &scp);
             }
-            if (code && code != CM_ERROR_NOSUCHFILE) {
+            if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
                 if (dscp)
                     cm_ReleaseSCache(dscp);
                 cm_ReleaseUser(userp);
@@ -6763,6 +7214,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)
@@ -6771,6 +7223,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 */
@@ -6794,7 +7247,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             code = 0;
             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
                 targetScp = 0;
-                osi_assert(dscp != NULL);
+                osi_assertx(dscp != NULL, "null cm_scache_t");
                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
                 if (code == 0) {
                     /* we have a more accurate file to use (the
@@ -6808,6 +7261,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)
@@ -6834,9 +7288,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         free(realPathp);
         return CM_ERROR_NOSUCHFILE;
     } else if (realDirFlag == 0 || realDirFlag == -1) {
-        osi_assert(dscp != NULL);
-        osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
-                  osi_LogSaveString(smb_logp, lastNamep));
+        osi_assertx(dscp != NULL, "null cm_scache_t");
+        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);
@@ -6883,8 +7337,8 @@ 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;
@@ -6892,36 +7346,37 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         /* create directory */
         if ( !treeCreate ) 
             treeStartp = lastNamep;
-        osi_assert(dscp != NULL);
-        osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
-                  osi_LogSaveString(smb_logp, treeStartp));
+        osi_assertx(dscp != NULL, "null cm_scache_t");
+        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 
         * it will appear as a directory name of the nul-string
         * and a code of CM_ERROR_NOSUCHFILE
         */
-       if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
+       if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
            code = CM_ERROR_EXISTS;
 
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         setAttr.clientModTime = time(NULL);
 
         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++;
             }
@@ -6931,13 +7386,13 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 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
@@ -6945,8 +7400,8 @@ 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);
-            }       
+                                 userp, &req, &tscp2);
+            }
             if (code) 
                 break;
 
@@ -6971,7 +7426,7 @@ 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) 
             cm_ReleaseSCache(scp);
@@ -6995,15 +7450,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);
@@ -7016,7 +7473,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)
@@ -7028,7 +7485,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
 
     /* save a reference to the user */
     cm_HoldUser(userp);
@@ -7048,7 +7505,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
 
         /* If we are not opening the file for writing, then we don't
-           try to get an exclusive lock.  Noone else should be able to
+           try to get an exclusive lock.  No one else should be able to
            get an exclusive lock on the file anyway, although someone
            else can get a shared lock. */
         if ((fidflags & SMB_FID_SHARE_READ) ||
@@ -7060,12 +7517,12 @@ 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_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
 
         if (code) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             if (dscp)
@@ -7080,15 +7537,17 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 
     /* 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 */
     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
 
     fidp->flags = fidflags;
@@ -7103,7 +7562,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);
@@ -7121,7 +7580,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* out parms */
     parmSlot = 2;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainRead(&scp->rw);
     smb_SetSMBParmByte(outp, parmSlot, 0);     /* oplock */
     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
     smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
@@ -7140,11 +7599,23 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                         (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
                         scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
                         scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
-    lock_ReleaseMutex(&scp->mx);
     smb_SetSMBDataLength(outp, 0);
 
-    osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
-              osi_LogSaveString(smb_logp, realPathp));
+    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
+        LargeIntegerGreaterThanZero(scp->length) && 
+        !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+        prefetch = 1;
+    }
+    lock_ReleaseRead(&scp->rw);
+
+    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);
@@ -7160,9 +7631,11 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  * 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;
@@ -7170,7 +7643,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;
@@ -7179,15 +7652,14 @@ 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;
@@ -7198,7 +7670,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;
@@ -7206,9 +7678,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;
@@ -7232,23 +7706,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
@@ -7268,31 +7735,40 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     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(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);
 
     /*
      * 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
+        free(realPathp);
+        return CM_ERROR_BADNTFILENAME;
+    }
 
     userp = smb_GetUserFromVCP(vcp, inp);
     if (!userp) {
@@ -7324,8 +7800,17 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
            osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
             free(realPathp);
             cm_ReleaseUser(userp);
-            return CM_ERROR_INVAL;
+            return CM_ERROR_BADFD;
         }       
+
+        if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+            free(realPathp);
+            cm_ReleaseUser(userp);
+           smb_CloseFID(vcp, baseFidp, NULL, 0);
+            smb_ReleaseFID(baseFidp);
+            return CM_ERROR_NOSUCHPATH;
+        }
+
         baseDirp = baseFidp->scp;
         tidPathp = NULL;
     }
@@ -7334,7 +7819,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     fidflags = 0;
     if (desiredAccess & DELETE)
         fidflags |= SMB_FID_OPENDELETE;
-    if (desiredAccess & AFS_ACCESS_READ)
+    if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
         fidflags |= SMB_FID_OPENREAD_LISTDIR;
     if (desiredAccess & AFS_ACCESS_WRITE)
         fidflags |= SMB_FID_OPENWRITE;
@@ -7344,6 +7829,10 @@ 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;
 
     /* And the share mode */
     if (shareAccess & FILE_SHARE_READ)
@@ -7356,25 +7845,26 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     if ( createDisp == FILE_OPEN || 
          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->wdata);
                 cm_ReleaseSCache(dscp);
                 cm_ReleaseUser(userp);
                 free(realPathp);
                if (baseFidp)
                    smb_ReleaseFID(baseFidp);
-                if ( WANTS_DFS_PATHNAMES(inp) )
+                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) {
+            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) {
@@ -7394,15 +7884,16 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                         userp, tidPathp, &req, &scp);
 #ifdef DFS_SUPPORT
         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
            if (baseFidp)
                smb_ReleaseFID(baseFidp);
-            if ( WANTS_DFS_PATHNAMES(inp) )
+            if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
-                return CM_ERROR_BADSHARENAME;
+                return CM_ERROR_NOSUCHPATH;
         }
 #endif /* DFS_SUPPORT */
     }
@@ -7413,20 +7904,21 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
         /* look up parent directory */
         if ( !dscp ) {
-            code = cm_NameI(baseDirp, spacep->data,
+            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->wdata);
                 cm_ReleaseSCache(dscp);
                 cm_ReleaseUser(userp);
                 free(realPathp);
                if (baseFidp)
                    smb_ReleaseFID(baseFidp);
-                if ( WANTS_DFS_PATHNAMES(inp) )
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
-                    return CM_ERROR_BADSHARENAME;
+                    return CM_ERROR_NOSUCHPATH;
             }
 #endif /* DFS_SUPPORT */
         } else
@@ -7460,7 +7952,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                                  userp, &req, &scp);
             }
-            if (code && code != CM_ERROR_NOSUCHFILE) {
+            if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
                 cm_ReleaseSCache(dscp);
                 cm_ReleaseUser(userp);
                 free(realPathp);
@@ -7481,6 +7973,7 @@ 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) {     
+            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp) 
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
@@ -7488,6 +7981,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
             free(realPathp);
             return code;
         }
+        checkDoneRequired = 1;
 
         if (createDisp == FILE_CREATE) {
             /* oops, file shouldn't be there */
@@ -7523,6 +8017,7 @@ 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) {
+                        cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                        if (dscp)
                            cm_ReleaseSCache(dscp);
                        if (scp)
@@ -7547,9 +8042,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         return CM_ERROR_NOSUCHFILE;
     }
     else if (realDirFlag == 0 || realDirFlag == -1) {
-        osi_assert(dscp != NULL);
-        osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
-                  osi_LogSaveString(smb_logp, lastNamep));
+        osi_assertx(dscp != NULL, "null cm_scache_t");
+        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);
@@ -7598,14 +8093,14 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         }
     } else {
         /* create directory */
-        osi_assert(dscp != NULL);
+        osi_assertx(dscp != NULL, "null cm_scache_t");
         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);
+        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,
@@ -7625,7 +8120,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
     if (code) {
         /* something went wrong creating or truncating the file */
-       if (ldp)
+       if (checkDoneRequired)
            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
        if (scp) 
             cm_ReleaseSCache(scp);
@@ -7648,15 +8143,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);
@@ -7666,7 +8163,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);
@@ -7676,7 +8173,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
     /* open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
 
     /* save a reference to the user */
     cm_HoldUser(userp);
@@ -7706,12 +8203,12 @@ 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_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
 
         if (code) {
-           if (ldp)
+           if (checkDoneRequired)
                cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
@@ -7724,15 +8221,17 @@ 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 */
     fidp->scp = scp;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
 
     fidp->flags = fidflags;
@@ -7747,7 +8246,7 @@ 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);
@@ -7789,7 +8288,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
         smb_SetSMBDataLength(outp, 70);
 
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainRead(&scp->rw);
         outData = smb_GetSMBData(outp, NULL);
         outData++;                     /* round to get to parmOffset */
         *outData = 0; outData++;       /* oplock */
@@ -7811,7 +8310,6 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                                scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
                                scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
         outData += 2;  /* is a dir? */
-        lock_ReleaseMutex(&scp->mx);
     } else {
         /* out parms */
         parmOffset = 8*4 + 39;
@@ -7839,7 +8337,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
         smb_SetSMBDataLength(outp, 105);
         
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainRead(&scp->rw);
         outData = smb_GetSMBData(outp, NULL);
         outData++;                     /* round to get to parmOffset */
         *outData = 0; outData++;       /* oplock */
@@ -7864,9 +8362,20 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
-        lock_ReleaseMutex(&scp->mx);
     }
 
+    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
+         LargeIntegerGreaterThanZero(scp->length) && 
+         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+        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);
@@ -7877,6 +8386,7 @@ 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)
 {
@@ -7897,14 +8407,27 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
         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);
@@ -7912,9 +8435,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)
@@ -7942,12 +8464,13 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
     if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
        osi_Log0(smb_logp, "      Notify Change Stream Write");
 
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     if (watchtree)
         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
     else
         scp->flags |= CM_SCACHEFLAG_WATCHED;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
+    cm_ReleaseSCache(scp);
     smb_ReleaseFID(fidp);
 
     outp->flags |= SMB_PACKETFLAG_NOSEND;
@@ -7969,6 +8492,7 @@ unsigned char nullSecurityDesc[36] = {
                                         /* "null SID" group SID */
 };      
 
+/* 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;
@@ -8037,6 +8561,10 @@ long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_pa
         return CM_ERROR_BUFFERTOOSMALL;
 }
 
+/* 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;
@@ -8050,21 +8578,27 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         ((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");
+        break;
+    case 8:
+        osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
+        break;
     }
     return CM_ERROR_INVAL;
 }
@@ -8080,11 +8614,11 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  * 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;
@@ -8100,8 +8634,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)
@@ -8138,21 +8672,23 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             lastWatch = watch;
             watch = watch->nextp;
             continue;
-        }       
-        if (fidp->scp != dscp
-             || (filter & notifyFilter) == 0
-             || (!isDirectParent && !wtree)) {
+        }      
+
+        if (fidp->scp != dscp ||
+            fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
+            (filter & notifyFilter) == 0 ||
+            (!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)
@@ -8186,26 +8722,29 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             lastWatch->nextp = nextWatch;
 
         /* Turn off WATCHED flag in dscp */
-        lock_ObtainMutex(&dscp->mx);
+        lock_ObtainWrite(&dscp->rw);
         if (wtree)
             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
         else
             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
-        lock_ReleaseMutex(&dscp->mx);
+        lock_ReleaseWrite(&dscp->rw);
 
         /* Convert to response packet */
-        ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
+        ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
+#ifdef SEND_CANONICAL_PATHNAMES
+        ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
+#endif
         ((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 */
@@ -8239,7 +8778,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;
@@ -8249,12 +8787,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;
@@ -8263,13 +8799,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
@@ -8289,11 +8821,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;
@@ -8327,18 +8862,20 @@ long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
             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_ObtainMutex(&scp->mx);
-                if (watchtree)
-                    scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
-                else
-                    scp->flags &= ~CM_SCACHEFLAG_WATCHED;
-                lock_ReleaseMutex(&scp->mx);
+                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);
@@ -8377,7 +8914,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;
@@ -8392,32 +8929,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;
@@ -8427,9 +8965,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);