windows-afsd-fs-attr-info-20081226
[openafs.git] / src / WINNT / afsd / smb3.c
index 9ef2818..be166be 100644 (file)
 #include <afs/param.h>
 #include <afs/stds.h>
 
-#ifndef DJGPP
 #include <windows.h>
+#pragma warning(push)
+#pragma warning(disable: 4005)
 #include <ntstatus.h>
 #define SECURITY_WIN32
 #include <security.h>
 #include <lmaccess.h>
-#endif /* !DJGPP */
+#pragma warning(pop)
 #include <stdlib.h>
 #include <malloc.h>
 #include <string.h>
@@ -28,6 +29,7 @@
 #include <WINNT\afsreg.h>
 
 #include "smb.h"
+#include <strsafe.h>
 
 extern osi_hyper_t hzero;
 
@@ -41,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)
@@ -59,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
@@ -78,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.
@@ -98,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 == '>') 
@@ -108,46 +137,32 @@ 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));
+    cm_ClientStrCat(vbuffer, lengthof(vbuffer), _C("\n"));
+    OutputDebugStringW(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");
+                osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
+                StringCchCatA(buf, lengthof(buf), "\r\n");
                 OutputDebugString(buf);
             }
-            sprintf(buf,"%5x",i);
+            StringCchPrintfA(buf, lengthof(buf), "%5x", i);
             memset(buf+5,' ',80);
             buf[85] = 0;
         }
@@ -159,17 +174,13 @@ 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");
+        osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
+        StringCchCatA(buf, lengthof(buf), "\r\n");
         OutputDebugString(buf);
     }   
 }
@@ -188,7 +199,7 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
     *secBlob = NULL;
     *secBlobLength = 0;
 
-    OutputDebugF("Negotiating Extended Security");
+    OutputDebugF(_C("Negotiating Extended Security"));
 
     status = AcquireCredentialsHandle( NULL,
                                        SMB_EXT_SEC_PACKAGE_NAME,
@@ -202,7 +213,7 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
 
     if (status != SEC_E_OK) {
         /* Really bad. We return an empty security blob */
-        OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
+        OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
         goto nes_0;
     }
 
@@ -228,10 +239,10 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
                                     );
 
     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
-        OutputDebugF("Completing token...");
+        OutputDebugF(_C("Completing token..."));
         istatus = CompleteAuthToken(&ctx, &secOut);
         if ( istatus != SEC_E_OK )
-            OutputDebugF("Token completion failed: %x", istatus);
+            OutputDebugF(_C("Token completion failed: %x"), istatus);
     }
 
     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
@@ -242,7 +253,7 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
         }
     } else {
         if ( status != SEC_E_OK )
-            OutputDebugF("AcceptSecurityContext status != CONTINUE  %lX", status);
+            OutputDebugF(_C("AcceptSecurityContext status != CONTINUE  %lX"), status);
     }
 
     /* Discard partial security context */
@@ -264,7 +275,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;
@@ -280,7 +293,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;
@@ -294,12 +307,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;
 
@@ -321,7 +334,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;
         }
@@ -363,14 +376,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));
 
@@ -390,16 +403,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));
 
@@ -419,52 +432,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;
     }
@@ -506,7 +519,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;
@@ -517,11 +530,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;
     }
 
@@ -530,12 +543,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);
 
@@ -563,9 +576,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,
@@ -586,8 +604,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 */
@@ -604,13 +622,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]
@@ -619,7 +637,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;
@@ -632,18 +650,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;
 }
@@ -655,6 +673,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;
@@ -662,9 +681,9 @@ 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;
 
@@ -678,7 +697,7 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             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);
@@ -690,35 +709,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 */
@@ -726,20 +747,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 */
@@ -755,38 +778,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 */
@@ -800,9 +823,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"));
         }
     }
 
@@ -815,6 +838,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);
     }
 
@@ -826,7 +855,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
@@ -867,7 +896,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 */
@@ -890,40 +919,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);
         }
@@ -932,6 +966,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;
@@ -941,8 +976,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;
@@ -979,18 +1014,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;
         
@@ -998,23 +1035,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;
@@ -1034,24 +1071,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);
@@ -1066,24 +1114,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);
@@ -1105,7 +1151,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;
@@ -1135,18 +1181,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);
@@ -1194,14 +1244,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;
@@ -1299,6 +1379,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;
@@ -1317,9 +1399,7 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* We sometimes see 0 word count.  What to do? */
     if (*inp->wctp == 0) {
         osi_Log0(smb_logp, "Transaction2 word count = 0"); 
-#ifndef DJGPP
        LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
-#endif /* !DJGPP */
 
         smb_SetSMBDataLength(outp, 0);
         smb_SendPacket(vcp, outp);
@@ -1423,31 +1503,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
@@ -1458,18 +1539,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++;
@@ -1480,6 +1560,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;
@@ -1500,8 +1581,9 @@ 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;
     smb_rap_share_list_t rootShares;
     cm_req_t req;
@@ -1509,8 +1591,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];
 
@@ -1518,6 +1610,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);
@@ -1547,7 +1651,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);
 
@@ -1582,7 +1686,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++;
@@ -1590,11 +1695,14 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     }
 
     if (hkSubmount) {
-        for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
+        for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
             len = sizeof(thisShare);
-            rv = RegEnumValue(hkSubmount, i, 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++;
@@ -1610,9 +1718,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) {
@@ -1620,7 +1729,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;
@@ -1642,11 +1752,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;
@@ -1658,11 +1769,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++;
     
@@ -1677,9 +1808,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) {
@@ -1696,22 +1825,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,"ReceiveTran2GetDfsReferral 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;
@@ -1720,18 +1861,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;
@@ -1747,16 +1887,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)
 {
@@ -1772,8 +1915,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++;
 
@@ -1800,7 +1956,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);
@@ -1808,14 +1964,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 */
@@ -1823,7 +1980,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);
@@ -1839,18 +1997,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);
 
@@ -1872,8 +2034,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++;
 
@@ -1895,11 +2070,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 |
@@ -1908,11 +2083,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);
@@ -1927,6 +2102,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;
@@ -1940,13 +2116,12 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     int dataCount;
     int firstPacket;
     long code = 0;
+    DWORD oldTime, newTime;
 
     /* We sometimes see 0 word count.  What to do? */
     if (*inp->wctp == 0) {
         osi_Log0(smb_logp, "Transaction2 word count = 0"); 
-#ifndef DJGPP
        LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
-#endif /* !DJGPP */
 
         smb_SetSMBDataLength(outp, 0);
         smb_SendPacket(vcp, outp);
@@ -2014,6 +2189,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);
@@ -2033,6 +2210,39 @@ 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 && fidp->NTopen_pathp)
+                pathname = fidp->NTopen_pathp;
+            else if (inp->stringsp->wdata)
+                pathname = inp->stringsp->wdata;
+
+            if (fidp && fidp->scp)
+                afid = fidp->scp->fid;
+
+            afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)", 
+                      myCrt_2Dispatch(asp->opcode), newTime - oldTime,
+                      uidp ? uidp->unp->name : NULL,
+                      treepath,
+                      pathname, 
+                      afid.cell, afid.volume, afid.vnode, afid.unique);
+
+            if (uidp)
+                smb_ReleaseUID(uidp);
+            if (fidp)
+                smb_ReleaseFID(fidp);
+        }
+
         /* free the input tran 2 packet */
         smb_FreeTran2Packet(asp);
     }
@@ -2047,9 +2257,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;
@@ -2061,7 +2272,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;
@@ -2070,11 +2281,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;
         
@@ -2095,16 +2306,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).
          */
@@ -2147,6 +2361,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;
@@ -2185,7 +2415,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);
@@ -2198,10 +2428,12 @@ 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;
@@ -2218,7 +2450,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);
@@ -2227,10 +2459,11 @@ 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;
@@ -2279,13 +2512,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);
@@ -2295,7 +2528,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
            created = 1;
            if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
                smb_NotifyChange(FILE_ACTION_ADDED,
-                                FILE_NOTIFY_CHANGE_FILE_NAME,  
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
                                  dscp, lastNamep, NULL, TRUE);
        } else if (!excl && code == CM_ERROR_EXISTS) {
             /* not an exclusive create, and someone else tried
@@ -2358,18 +2591,23 @@ 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_ObtainWrite(&scp->rw);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseWrite(&scp->rw);
+    
     /* and the user */
     fidp->userp = userp;
         
     /* compute open mode */
     if (openMode != 1) 
-       fidp->flags |= SMB_FID_OPENREAD;
+       fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     if (openMode == 1 || openMode == 2)
         fidp->flags |= SMB_FID_OPENWRITE;
 
@@ -2386,7 +2624,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 +2646,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 */
 
@@ -2421,56 +2659,33 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     return 0;
 }   
 
-long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
-    osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
-    return CM_ERROR_BADOP;
-}
+    unsigned short fid;
+    unsigned short infolevel;
 
-long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
-{
-    osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
-    return CM_ERROR_BADOP;
+    infolevel = p->parmsp[0];
+    fid = p->parmsp[1];
+    osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
+    
+    return CM_ERROR_BAD_LEVEL;
 }
 
+/* TRANS2_QUERY_FS_INFORMATION */
 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
     smb_tran2Packet_t *outp;
     smb_tran2QFSInfo_t qi;
     int responseSize;
-    static char FSname[6] = {'A', 0, 'F', 0, 'S', 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_INVAL;
-    }
 
-    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 +2695,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", 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,28 +2734,57 @@ 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
          *        we can't handle long (non-8.3) names,
          *        despite our protestations to the contrary.
          */
-        qi.u.FSattributeInfo.attributes = 0x4013;
-        qi.u.FSattributeInfo.maxCompLength = 255;
-        qi.u.FSattributeInfo.FSnameLength = 6;
-        memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
+        qi.u.FSattributeInfo.attributes = 0x4003;
+        /* The maxCompLength is supposed to be in bytes */
+#ifdef SMB_UNICODE
+        qi.u.FSattributeInfo.attributes |= 0x04;
+
+        if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
+            qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
+        else {
+#endif
+        qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
+#ifdef SMB_UNICODE
+        }
+#endif
+        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 +2804,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 +2814,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 +2852,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 +2865,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 +2892,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,31 +2903,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;
-    smb_fid_t *fidp;
-    unsigned short fid;
+    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);
-
-    fid = p->parmsp[0];
-    fidp = smb_FindFID(vcp, fid, 0);
-    if (fidp) {
-       lock_ObtainMutex(&fidp->mx);
-       delonclose = fidp->flags & SMB_FID_DELONCLOSE;
-       lock_ReleaseMutex(&fidp->mx);
-       smb_ReleaseFID(fidp);
-       fidp = NULL;
-    }
+    smb_InitReq(&req);
 
     infoLevel = p->parmsp[0];
     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
@@ -2680,15 +2940,13 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     else {
         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         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);
 
@@ -2739,12 +2997,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,
@@ -2752,7 +3010,9 @@ 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;
@@ -2762,8 +3022,10 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                         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;
                     }
@@ -2796,9 +3058,10 @@ 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;
@@ -2808,11 +3071,20 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     }
 #endif /* DFS_SUPPORT */
 
-    lock_ObtainMutex(&scp->mx);
+    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.
      */
@@ -2820,20 +3092,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 * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len);
+        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 * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len);
+        smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
+       qpi.u.QPfileNameInfo.fileNameLength = len;
 
         goto done;
     }
@@ -2856,16 +3127,31 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         qpi.u.QPfileBasicInfo.changeTime = ft;
         extAttributes = smb_ExtAttributes(scp);
        qpi.u.QPfileBasicInfo.attributes = extAttributes;
+       qpi.u.QPfileBasicInfo.reserved = 0;
     }
     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
+       smb_fid_t * fidp;
+            
+        lock_ReleaseRead(&scp->rw);
+        scp_rw_held = 0;
+        fidp = smb_FindFIDByScache(vcp, scp);
+
         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
-        qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
         qpi.u.QPfileStandardInfo.directory = 
            ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
              scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
              scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
+        qpi.u.QPfileStandardInfo.reserved = 0;
+
+       if (fidp) {
+           lock_ObtainMutex(&fidp->mx);
+           delonclose = fidp->flags & SMB_FID_DELONCLOSE;
+           lock_ReleaseMutex(&fidp->mx);
+           smb_ReleaseFID(fidp);
+       }
+        qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
     }
     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
         qpi.u.QPfileEaInfo.eaSize = 0;
@@ -2896,14 +3182,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 * 2;
-        mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len);
+
+        smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
+       qpi.u.QPfileAllInfo.fileNameLength = len;
     }
 
     /* send and free the packets */
   done:
-    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) {
@@ -2917,6 +3211,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
@@ -2924,53 +3219,36 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     return CM_ERROR_BADOP;
 #else
     long code = 0;
-    unsigned short fid;
     smb_fid_t *fidp;
     unsigned short infoLevel;
+    clientchar_t * pathp;
     smb_tran2Packet_t *outp;
     smb_tran2QPathInfo_t *spi;
     cm_user_t *userp;
-    cm_scache_t *scp;
+    cm_scache_t *scp, *dscp;
     cm_req_t req;
+    cm_space_t *spacep;
+    clientchar_t *tidPathp;
+    clientchar_t *lastComp;
 
-    cm_InitReq(&req);
-
-    fid = p->parmsp[0];
-    fidp = smb_FindFID(vcp, fid, 0);
-
-    if (fidp == NULL) {
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
-        return 0;
-    }
+    smb_InitReq(&req);
 
-    infoLevel = p->parmsp[1];
-    osi_Log2(smb_logp,"ReceiveTran2SetPathInfo type 0x%x fid %d", infoLevel, fid);
+    infoLevel = p->parmsp[0];
+    osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
     if (infoLevel != SMB_INFO_STANDARD && 
        infoLevel != SMB_INFO_QUERY_EA_SIZE &&
        infoLevel != SMB_INFO_QUERY_ALL_EAS) {
         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
-        smb_ReleaseFID(fidp);
-        return 0;
-    }
-
-    lock_ObtainMutex(&fidp->mx);
-    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
-       lock_ReleaseMutex(&fidp->mx);
-        smb_ReleaseFID(fidp);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
+        smb_SendTran2Error(vcp, p, opx, 
+                           infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
         return 0;
     }
 
-    scp = fidp->scp;
-    cm_HoldSCache(scp);
-    lock_ReleaseMutex(&fidp->mx);
-
-    outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
+    pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
 
-    outp->totalParms = 2;
-    outp->totalData = 0;
+    osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
+              osi_LogSaveClientString(smb_logp, pathp));
 
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
@@ -2979,24 +3257,134 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        goto done;
     }   
 
-    spi = (smb_tran2QPathInfo_t *)p->datap;
-    if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
-        cm_attr_t attr;
-
-        /* 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);
+    code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+    if (code == CM_ERROR_TIDIPC) {
+        /* Attempt to use a TID allocated for IPC.  The client
+         * is probably looking for DCE RPC end points which we
+         * don't support OR it could be looking to make a DFS
+         * referral request. 
+         */
+        osi_Log0(smb_logp, "Tran2Open received IPC TID");
+        cm_ReleaseUser(userp);
+        return CM_ERROR_NOSUCHPATH;
+    }
+
+    /*
+    * XXX Strange hack XXX
+    *
+    * As of Patch 7 (13 January 98), we are having the following problem:
+    * In NT Explorer 4.0, whenever we click on a directory, AFS gets
+    * requests to look up "desktop.ini" in all the subdirectories.
+    * This can cause zillions of timeouts looking up non-existent cells
+    * and volumes, especially in the top-level directory.
+    *
+    * We have not found any way to avoid this or work around it except
+    * to explicitly ignore the requests for mount points that haven't
+    * yet been evaluated and for directories that haven't yet been
+    * fetched.
+    */
+    if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+        spacep = cm_GetSpace();
+        smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
+#ifndef SPECIAL_FOLDERS
+        /* Make sure that lastComp is not NULL */
+        if (lastComp) {
+            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,
+                                 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);
+                        if ( WANTS_DFS_PATHNAMES(p) || pnc )
+                            code = CM_ERROR_PATH_NOT_COVERED;
+                        else
+                            code = CM_ERROR_BADSHARENAME;
+                    } 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) {
+                            buf_Release(bp);
+                            bp = NULL;
+                        }
+                        else
+                            code = CM_ERROR_NOSUCHFILE;
+                    }
+                    cm_ReleaseSCache(dscp);
+                    if (code) {
+                        cm_FreeSpace(spacep);
+                        cm_ReleaseUser(userp);
+                        smb_SendTran2Error(vcp, p, opx, code);
+                        return 0;
+                    }
+                }
+            }
+        }
+#endif /* SPECIAL_FOLDERS */
+
+        cm_FreeSpace(spacep);
+    }
+
+    /* now do namei and stat, and copy out the info */
+    code = cm_NameI(cm_data.rootSCachep, pathp,
+                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
+    if (code) {
+        cm_ReleaseUser(userp);
+        smb_SendTran2Error(vcp, p, opx, code);
+        return 0;
+    }
+
+    fidp = smb_FindFIDByScache(vcp, scp);
+    if (!fidp) {
+        cm_ReleaseSCache(scp);
+        cm_ReleaseUser(userp);
+       smb_SendTran2Error(vcp, p, opx, code);
+        return 0;
+    }
+
+    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;
+    outp->totalData = 0;
+
+    spi = (smb_tran2QPathInfo_t *)p->datap;
+    if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
+        cm_attr_t attr;
+
+        /* lock the vnode with a callback; we need the current status
+         * to determine what the new status is, in some cases.
+         */
+        lock_ObtainWrite(&scp->rw);
         code = cm_SyncOp(scp, NULL, userp, &req, 0,
                           CM_SCACHESYNC_GETSTATUS
                          | CM_SCACHESYNC_NEEDCALLBACK);
-       lock_ReleaseMutex(&scp->mx);
         if (code) {
+           lock_ReleaseWrite(&scp->rw);
             goto done;
         }
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
+       lock_ReleaseWrite(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainRead(&scp->rw);
 
         /* prepare for setattr call */
         attr.mask = CM_ATTRMASK_LENGTH;
@@ -3023,7 +3411,7 @@ long smb_ReceiveTran2SetPathInfo(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 */
@@ -3034,7 +3422,7 @@ 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:
@@ -3051,6 +3439,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;
@@ -3065,9 +3454,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);
@@ -3077,6 +3467,13 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return 0;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return 0;
+    }
+
     infoLevel = p->parmsp[1];
     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
         responseSize = sizeof(qfi.u.QFbasicInfo);
@@ -3089,7 +3486,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     else {
         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         smb_ReleaseFID(fidp);
         return 0;
     }
@@ -3113,14 +3510,20 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     lock_ObtainMutex(&fidp->mx);
     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
     scp = fidp->scp;
+    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) 
         goto done;
 
+    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.
      */
@@ -3147,26 +3550,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*2) + 4; /* this is actually what we want to return */
-        qfi.u.QFfileNameInfo.fileNameLength = len * 2;
-        mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len);
+
+        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);
@@ -3181,6 +3587,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;
@@ -3188,11 +3596,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);
@@ -3202,18 +3610,28 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         return 0;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return 0;
+    }
+
     infoLevel = p->parmsp[1];
     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         smb_ReleaseFID(fidp);
         return 0;
     }
 
     lock_ObtainMutex(&fidp->mx);
-    if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
+    if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && 
+       !(fidp->flags & SMB_FID_OPENDELETE)) {
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
+                 fidp, fidp->scp, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
@@ -3222,6 +3640,8 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
         infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
          && !(fidp->flags & SMB_FID_OPENWRITE)) {
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
+                 fidp, fidp->scp, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
@@ -3229,6 +3649,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     }
 
     scp = fidp->scp;
+    osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
 
@@ -3255,16 +3676,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);
-       lock_ReleaseMutex(&scp->mx);
-        if (code)
+        if (code) {
+           lock_ReleaseWrite(&scp->rw);
             goto done;
+       }
 
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+       lock_ReleaseWrite(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainRead(&scp->rw);
 
         /* prepare for setattr call */
         attr.mask = 0;
@@ -3296,7 +3721,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 */
@@ -3306,6 +3731,9 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
             code = 0;
     }
     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
+       int delflag = *((char *)(p->datap));
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p", 
+                delflag, fidp, scp);
         if (*((char *)(p->datap))) {   /* File is Deleted */
             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
                                      &req);
@@ -3313,6 +3741,9 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                lock_ObtainMutex(&fidp->mx);
                 fidp->flags |= SMB_FID_DELONCLOSE;
                lock_ReleaseMutex(&fidp->mx);
+           } else {
+               osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x", 
+                        fidp, scp, code);
            }
        }               
         else {  
@@ -3322,7 +3753,8 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
            lock_ReleaseMutex(&fidp->mx);
         }
     }       
-    else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO) {
+    else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
+            infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
         cm_attr_t attr;
 
@@ -3331,14 +3763,6 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         attr.length.HighPart = size.HighPart;
         code = cm_SetAttr(scp, &attr, userp, &req);
     }       
-    else if (infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
-        unsigned short size = *((unsigned short *)(p->datap));
-        cm_attr_t attr;
-
-        attr.mask = CM_ATTRMASK_LENGTH;
-        attr.length.LowPart = size;
-        code = cm_SetAttr(scp, &attr, userp, &req);
-    }       
 
   done:
     cm_ReleaseSCache(scp);
@@ -3353,6 +3777,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)
 {
@@ -3360,6 +3785,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)
 {
@@ -3367,6 +3793,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)
 {
@@ -3374,6 +3801,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)
 {
@@ -3381,6 +3809,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)
 {
@@ -3388,6 +3817,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)
 {
@@ -3405,6 +3835,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)
 {
@@ -3420,79 +3851,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.  If we 
+             */
+            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) 
@@ -3505,10 +4038,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)
 {
@@ -3525,113 +4059,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;
-        
-    for(patchp = *dirPatchespp; patchp; patchp =
-         (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
-               code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
-        if (code) continue;
-        lock_ObtainMutex(&scp->mx);
-        code = cm_SyncOp(scp, NULL, userp, reqp, 0,
+    afs_uint32 rights;
+    afs_int32 mustFake = 0;
+    clientchar_t path[AFSPATHMAX];
+
+    code = cm_FindACLCache(dscp, userp, &rights);
+    if (code == -1) {
+        lock_ObtainWrite(&dscp->rw);
+        code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        if (code) { 
-            lock_ReleaseMutex(&scp->mx);
-            cm_ReleaseSCache(scp);
+        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)
+        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);
+    }
 
-            dptr = patchp->dptr;
+    for( patchp = *dirPatchespp; 
+         patchp; 
+         patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+        cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
+                            relPathp ? relPathp : _C(""), patchp->dep->name);
+        reqp->relPathp = path;
+        reqp->tidPathp = tidPathp;
+
+        code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
+        reqp->relPathp = reqp->tidPathp = NULL;
+        if (code) 
+            continue;
+
+        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;
         }
-                
+        
         /* 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,
@@ -3642,40 +4280,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
@@ -3688,49 +4318,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);
@@ -3741,11 +4345,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);
     }
         
@@ -3758,289 +4361,491 @@ 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) 
+/* smb_ReceiveTran2SearchDir implements both 
+ * Tran2_Find_First and Tran2_Find_Next
+ */
+#define TRAN2_FIND_FLAG_CLOSE_SEARCH           0x01
+#define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END    0x02
+#define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS     0x04
+#define TRAN2_FIND_FLAG_CONTINUE_SEARCH                0x08
+#define TRAN2_FIND_FLAG_BACKUP_INTENT          0x10
+
+/* this is an optimized handler for T2SearchDir that handles the case
+   where there are no wildcards in the search path.  I.e. an
+   application is using FindFirst(Ex) to get information about a
+   single file or directory.  It will attempt to do a single lookup.
+   If that fails, then smb_ReceiveTran2SearchDir() will fall back to
+   the usual mechanism. 
+   
+   This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
+
+   TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
+   */
+long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
-    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('?');    
-}
+    int attribute;
+    long nextCookie;
+    long code = 0, code2 = 0;
+    clientchar_t *pathp = 0;
+    int maxCount;
+    smb_dirListPatch_t *dirListPatchesp;
+    smb_dirListPatch_t *curPatchp;
+    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 */
+    unsigned long maxReturnData;       /* max # of return data */
+    long maxReturnParms;               /* max # of return parms */
+    long bytesInBuffer;                        /* # data bytes in the output buffer */
+    clientchar_t *maskp;                       /* mask part of path */
+    int infoLevel;
+    int searchFlags;
+    int eos;
+    smb_tran2Packet_t *outp;           /* response packet */
+    clientchar_t *tidPathp = 0;
+    int align;
+    clientchar_t shortName[13];                        /* 8.3 name if needed */
+    int NeedShortName;
+    clientchar_t *shortNameEnd;
+    cm_dirEntry_t * dep = NULL;
+    cm_req_t req;
+    char * s;
+    void * attrp = NULL;
+    smb_tran2Find_t * fp;
 
-// 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 */ 
+    smb_InitReq(&req);
+
+    eos = 0;
+    osi_assertx(p->opcode == 1, "invalid opcode");
+
+    /* find first; obtain basic parameters from request */
+
+    /* note that since we are going to failover to regular
+     * processing at smb_ReceiveTran2SearchDir(), we shouldn't
+     * modify any of the input parameters here. */
+    attribute = p->parmsp[0];
+    maxCount = p->parmsp[1];
+    infoLevel = p->parmsp[3];
+    searchFlags = p->parmsp[2];
+    pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
+    nextCookie = 0;
+    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_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;
 
-    /* if all we have left are wildcards, then we match */
-    for (;*pattern; pattern++) {
-       if (*pattern != '*' && *pattern != '?')
-           return FALSE;
+    default:
+       s = "unknownInfoLevel";
+        ohbytes = 0;
     }
-    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;
+    osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
 
-    /* make sure we only match 8.3 names, if requested */
-    if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
-        return 0;
+    osi_Log4(smb_logp,
+             "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
+             attribute, infoLevel, maxCount, searchFlags);
     
-    casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
+    if (ohbytes == 0) {
+        osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
+        return CM_ERROR_INVAL;
+    }
 
-    /* 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 (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.*/
+
+    outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
+                                      maxReturnData);
+
+    osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
+             maxCount, osi_LogSaveClientString(smb_logp, pathp));
+        
+    /* bail out if request looks bad */
+    if (!pathp) {
+        smb_FreeTran2Packet(outp);
+        return CM_ERROR_BADSMB;
     }
-    if ( star ) {
-        newmask[j++] = '*';
-    } else if ( qmark ) {
-        while ( qmark-- )
-            newmask[j++] = '?';
+        
+    userp = smb_GetTran2User(vcp, p);
+    if (!userp) {
+       osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
+       smb_FreeTran2Packet(outp);
+       return CM_ERROR_BADSMB;
     }
-    newmask[j++] = '\0';
 
-    retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
+    /* try to get the vnode for the path name next */
+    spacep = cm_GetSpace();
+    smb_StripLastComponent(spacep->wdata, NULL, pathp);
+    code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+    if (code) {
+        cm_ReleaseUser(userp);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
+        smb_FreeTran2Packet(outp);
+        return 0;
+    }
 
-    free(newmask);
-    return retval;
-}
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
+                    CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                    userp, tidPathp, &req, &scp);
+    cm_FreeSpace(spacep);
 
-#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)) 
+    if (code) {
+        cm_ReleaseUser(userp);
+       smb_SendTran2Error(vcp, p, opx, code);
+        smb_FreeTran2Packet(outp);
         return 0;
+    }
 
-    /* loop */
-    while (1) {
-        /* Next pattern character */
-        tcp1 = *maskp++;
+#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) || pnc )
+           code = CM_ERROR_PATH_NOT_COVERED;
+       else
+           code = CM_ERROR_BADSHARENAME;
+       smb_SendTran2Error(vcp, p, opx, code);
+       smb_FreeTran2Packet(outp);
+       return 0;
+    }
+#endif /* DFS_SUPPORT */
+    osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
+
+    /* now do a single case sensitive lookup for the file in question */
+    code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
+
+    /* if a case sensitive match failed, we try a case insensitive one
+       next. */
+    if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
+        code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
+    }
+
+    if (code == 0 && targetscp->fid.vnode == 0) {
+        cm_ReleaseSCache(targetscp);
+        code = CM_ERROR_NOSUCHFILE;
+    }
+
+    if (code) {
+        /* if we can't find the directory entry, this block will
+           return CM_ERROR_NOSUCHFILE, which we will pass on to
+           smb_ReceiveTran2SearchDir(). */
+        cm_ReleaseSCache(scp);
+        cm_ReleaseUser(userp);
+       if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
+           smb_SendTran2Error(vcp, p, opx, code);
+           code = 0;
+       }
+       smb_FreeTran2Packet(outp);
+        return code;
+    }
+
+    /* now that we have the target in sight, we proceed with filling
+       up the return data. */
+
+    op = origOp = outp->datap;
+    bytesInBuffer = 0;
+
+    if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
+        /* skip over resume key */
+        op += 4;
+    }
+
+    fp = (smb_tran2Find_t *) op;
+
+    if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
+        && targetscp->fid.vnode != 0
+        && !cm_Is8Dot3(maskp)) {
+
+        cm_dirFid_t dfid;
+        dfid.vnode = htonl(targetscp->fid.vnode);
+        dfid.unique = htonl(targetscp->fid.unique);
+
+        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_LogSaveClientString(smb_logp, pathp),
+             (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
 
-        /* Next name character */
-        tcn1 = *namep;
+    /* Eliminate entries that don't match requested attributes */
+    if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
+        smb_IsDotFile(maskp)) {
 
-        if (tcp1 == 0) {
-            /* 0 - end of pattern */
-            if (tcn1 == 0)
-                return 1;
+        code = CM_ERROR_NOSUCHFILE;
+        osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
+        goto skip_file;
+
+    }
+
+    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)) {
+
+        code = CM_ERROR_NOSUCHFILE;
+        osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
+        goto skip_file;
+
+    }
+
+    /* add header to name & term. null */
+    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
+     * (so we don't have to worry 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 + align > maxReturnData) {
+
+        /* even though this request is unlikely to succeed with a
+           failover, we do it anyway. */
+        code = CM_ERROR_NOSUCHFILE;
+        osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
+                 maxReturnData);
+        goto skip_file;
+    }
+
+    /* 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, orbytes);
+
+    onbytes = 0;
+    smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
+
+    switch (infoLevel) {
+    case SMB_INFO_STANDARD:
+        fp->u.FstandardInfo.fileNameLength = onbytes;
+        attrp = &fp->u.FstandardInfo.fileAttrs;
+        break;
+
+    case SMB_INFO_QUERY_EA_SIZE:
+        fp->u.FeaSizeInfo.fileNameLength = onbytes;
+        attrp = &fp->u.FeaSizeInfo.fileAttrs;
+        fp->u.FeaSizeInfo.eaSize = 0;
+        break;
+
+    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) {
+#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
-                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;
-            }
+                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;
+
+    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 = attrp;
+
+        if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
+            curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
+        } else {
+            curPatchp->flags = 0;
         }
-        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;
+
+        cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
+
+        /* temp */
+        {
+            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) {
+        /* put out resume key */
+        *((u_long *)origOp) = 0;
+    }
+
+    /* Adjust byte ptr and count */
+    origOp += orbytes; /* skip entire record */
+    bytesInBuffer += orbytes;
+
+    /* and pad the record out */
+    while (--align >= 0) {
+        *origOp++ = 0;
+        bytesInBuffer++;
     }
+
+    /* apply the patches */
+    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
+
+    outp->parmsp[0] = 0;
+    outp->parmsp[1] = 1;        /* number of names returned */
+    outp->parmsp[2] = 1;        /* end of search */
+    outp->parmsp[3] = 0;        /* nothing wrong with EAS */
+    outp->parmsp[4] = 0;
+
+    outp->totalParms = 10;      /* in bytes */
+
+    outp->totalData = bytesInBuffer;
+
+    osi_Log0(smb_logp, "T2SDSingle done.");
+
+    if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
+       if (code)
+           smb_SendTran2Error(vcp, p, opx, code);
+       else
+           smb_SendTran2Packet(vcp, outp, opx);
+       code = 0;
+    }
+
+ skip_file:
+    smb_FreeTran2Packet(outp);
+    if (dep)
+        free(dep);
+    if (scp)
+    cm_ReleaseSCache(scp);
+    cm_ReleaseSCache(targetscp);
+    cm_ReleaseUser(userp);
+
+    return code;
 }
-#endif /* USE_OLD_MATCHING */
 
+
+/* 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;
@@ -4058,27 +4863,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) {
@@ -4087,23 +4894,43 @@ 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];
-        dsp = smb_NewDirSearch(1);
-        dsp->attribute = attribute;
-        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 
             maskp++;   /* skip over backslash */
-        strcpy(dsp->mask, maskp);      /* and save mask */
+
         /* track if this is likely to match a lot of entries */
         starPattern = smb_V3IsStarMask(maskp);
+
+#ifndef NOFINDFIRSTOPTIMIZE
+        if (!starPattern) {
+            /* if this is for a single directory or file, we let the
+               optimized routine handle it.  The only error it 
+              returns is CM_ERROR_NOSUCHFILE.  The  */
+            code = smb_T2SearchDirSingle(vcp, p, opx);
+
+            /* 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  /* NOFINDFIRSTOPTIMIZE */
+        dir_enums++;
+
+        dsp = smb_NewDirSearch(1);
+        dsp->attribute = attribute;
+        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];
@@ -4124,27 +4951,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);
@@ -4156,8 +4998,17 @@ 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 (ohbytes == 0) {
+        osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
+        smb_ReleaseDirSearch(dsp);
+        return CM_ERROR_INVAL;
+    }
+
     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
-        searchFlags &= ~4;     /* no resume keys */
+        searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;    /* no resume keys */
+
+    if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
+        ohbytes += 4;
 
     dirListPatchesp = NULL;
 
@@ -4167,16 +5018,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) {
@@ -4200,11 +5049,12 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     lock_ObtainMutex(&dsp->mx);
     if (dsp->scp) {
         scp = dsp->scp;
+       osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
         cm_HoldSCache(scp);
         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);
@@ -4215,7 +5065,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);
@@ -4223,9 +5077,10 @@ 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;
@@ -4238,6 +5093,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             }
 #endif /* DFS_SUPPORT */
             dsp->scp = scp;
+           osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
             /* we need one hold for the entry we just stored into,
              * and one for our own processing.  When we're done
              * with this function, we'll drop the one for our own
@@ -4245,13 +5101,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);
@@ -4264,11 +5114,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);
@@ -4277,6 +5127,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return code;
     }
 
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
   startsearch:
     dirLength = scp->length;
     bufferp = NULL;
@@ -4290,11 +5142,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 & 4)
+        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,
@@ -4336,6 +5193,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.
@@ -4348,35 +5221,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);
+            lock_ReleaseWrite(&scp->rw);
             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 */
-                    int 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_ObtainWrite(&scp->rw);
             if (code) {
                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
                 break;
@@ -4394,15 +5241,17 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
                     break;
                 }
-                                
+                       
                 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);
@@ -4458,130 +5307,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 & 4) {
-                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
@@ -4596,29 +5473,24 @@ 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;
             }   
 
-            if (searchFlags & 4)
+            if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
                 /* put out resume key */
                 *((u_long *)origOp) = nextEntryCookie;
 
@@ -4627,19 +5499,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;
@@ -4653,22 +5524,24 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
      * re-running the query. 
      */
     if (returnedNames == 0 && !starPattern && foundInexact) {
-        osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
+        osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
         starPattern = 1;
         goto startsearch;
     }
 
     /* release the mutex */
-    lock_ReleaseMutex(&scp->mx);
-    if (bufferp) 
+    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;
@@ -4709,10 +5582,12 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
      * we're supposed to close the search if we're done, and we're done,
      * or if something went wrong, close the search.
      */
-    /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
-    if ((searchFlags & 1) || (returnedNames == 0) || 
-         ((searchFlags & 2) && eos) || code != 0)
+    if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) || 
+       (returnedNames == 0) ||
+        ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) || 
+       code != 0)
         smb_DeleteDirSearch(dsp);
+
     if (code)
         smb_SendTran2Error(vcp, p, opx, code);
     else
@@ -4725,6 +5600,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;
@@ -4749,15 +5625,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;
@@ -4768,19 +5647,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;
         
@@ -4799,14 +5678,17 @@ 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);
 
     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).
          */
@@ -4846,6 +5728,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;
@@ -4869,9 +5766,10 @@ 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;
@@ -4879,7 +5777,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #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) {
@@ -4889,9 +5787,11 @@ 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;
@@ -4907,7 +5807,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;
@@ -4953,9 +5853,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);
@@ -4965,7 +5865,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
            created = 1;
            if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
                smb_NotifyChange(FILE_ACTION_ADDED,
-                                FILE_NOTIFY_CHANGE_FILE_NAME,
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
                                 dscp, lastNamep, NULL, TRUE);
        } else if (!excl && code == CM_ERROR_EXISTS) {
             /* not an exclusive create, and someone else tried
@@ -5008,18 +5908,22 @@ 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_ObtainWrite(&scp->rw);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseWrite(&scp->rw);
+    osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
     /* also the user */
     fidp->userp = userp;
         
     /* compute open mode */
     if (openMode != 1) 
-        fidp->flags |= SMB_FID_OPENREAD;
+        fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     if (openMode == 1 || openMode == 2)
         fidp->flags |= SMB_FID_OPENWRITE;
 
@@ -5038,7 +5942,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);
@@ -5056,7 +5960,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);
@@ -5092,6 +5996,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;
@@ -5101,7 +6006,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;
@@ -5112,7 +6017,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);
@@ -5121,6 +6026,12 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
@@ -5129,6 +6040,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADFD;
     }
     scp = fidp->scp;
+    osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
 
@@ -5138,7 +6050,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
@@ -5153,18 +6065,17 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
     NumberOfLocks = smb_GetSMBParm(inp, 7);
 
-    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 (!(fidp->flags & SMB_FID_OPENWRITE) &&
+        !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
+        /* somebody wants exclusive locks on a file that they only
+           opened for reading.  We downgrade this to a shared lock. */
+        osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
+        LockType |= LOCKING_ANDX_SHARED_LOCK;
+    }
 
+    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;
 
@@ -5172,6 +6083,35 @@ 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);
 
@@ -5193,6 +6133,13 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
                         userp, &req, &lockp);
 
+       if (code == CM_ERROR_NOACCESS && LockType == LockWrite && 
+           (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
+       {
+           code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
+                           userp, &req, &lockp);
+       }
+
         if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
             smb_waitingLock_t * wLock;
 
@@ -5205,16 +6152,18 @@ 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);
                 wlRequest->scp = scp;
+               osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
                 cm_HoldSCache(scp);
                 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
@@ -5235,7 +6184,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;
@@ -5249,7 +6198,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;
@@ -5334,7 +6283,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);
@@ -5342,6 +6291,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;
@@ -5351,8 +6301,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);
@@ -5361,6 +6312,12 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -5368,6 +6325,7 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         return CM_ERROR_BADFD;
     }
     scp = fidp->scp;
+    osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
         
@@ -5375,12 +6333,17 @@ 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) 
        goto done;
 
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+    lock_ConvertWToR(&scp->rw);
+    readlock = 1;
+
     /* decode times.  We need a search time, but the response to this
      * call provides the date first, not the time, as returned in the
      * searchTime variable.  So we take the high-order bits first.
@@ -5407,13 +6370,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;
@@ -5426,7 +6393,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);
@@ -5435,6 +6402,12 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -5442,6 +6415,7 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         return CM_ERROR_BADFD;
     }
     scp = fidp->scp;
+    osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
         
@@ -5476,6 +6450,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;
@@ -5483,6 +6458,7 @@ 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_user_t *userp;
     char *op;
@@ -5520,6 +6496,12 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!fidp)
         return CM_ERROR_BADFD;
         
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -5539,8 +6521,9 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_key_t key;
         LARGE_INTEGER LOffset;
         LARGE_INTEGER LLength;
+        cm_scache_t * scp;
 
-        pid = ((smb_t *) inp)->pid;
+        pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
         LOffset.HighPart = offset.HighPart;
@@ -5548,9 +6531,10 @@ 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);
+        scp = fidp->scp;
+        lock_ObtainWrite(&scp->rw);
+        code = cm_LockCheckWrite(scp, LOffset, LLength, key);
+        lock_ReleaseWrite(&scp->rw);
 
         if (code)
             goto done;
@@ -5575,11 +6559,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     code = 0;
     while ( code == 0 && count > 0 ) {
-#ifndef DJGPP
        code = smb_WriteData(fidp, &offset, count, op, userp, &written);
-#else /* DJGPP */
-       code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
-#endif /* !DJGPP */
        if (code == 0 && written == 0)
             code = CM_ERROR_PARTIALWRITE;
 
@@ -5590,8 +6570,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);
@@ -5601,12 +6579,13 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_SetSMBDataLength(outp, 0);
 
  done:
-    smb_ReleaseFID(fidp);
     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;
@@ -5615,6 +6594,7 @@ 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_user_t *userp;
     cm_key_t key;
@@ -5655,19 +6635,27 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADFD;
     }
 
-    pid = ((smb_t *) inp)->pid;
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
+    pid = smbp->pid;
     key = cm_GenerateKey(vcp->vcID, pid, fd);
     {
         LARGE_INTEGER LOffset, LLength;
+        cm_scache_t *scp;
 
         LOffset.HighPart = offset.HighPart;
         LOffset.LowPart = offset.LowPart;
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainMutex(&fidp->scp->mx);
-        code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        scp = fidp->scp;
+        lock_ObtainWrite(&scp->rw);
+        code = cm_LockCheckRead(scp, LOffset, LLength, key);
+        lock_ReleaseWrite(&scp->rw);
     }
 
     if (code) {
@@ -5714,19 +6702,14 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* set the packet data length the count of the # of bytes */
     smb_SetSMBDataLength(outp, count);
 
-#ifndef DJGPP
     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
-#else /* DJGPP */
-    code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
-#endif /* !DJGPP */
 
     /* fix some things up */
     smb_SetSMBParm(outp, 5, finalCount);
     smb_SetSMBDataLength(outp, finalCount);
 
-    smb_ReleaseFID(fidp);
-
     cm_ReleaseUser(userp);
+    smb_ReleaseFID(fidp);
     return code;
 }   
         
@@ -5756,10 +6739,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;
@@ -5767,8 +6757,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;
@@ -5792,12 +6782,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 
@@ -5852,22 +6845,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).
          */
@@ -5904,15 +6901,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) {
@@ -5946,22 +6949,39 @@ 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)
-        fidflags |= SMB_FID_OPENREAD;
+    if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
+        fidflags |= SMB_FID_OPENREAD_LISTDIR;
     if (desiredAccess & AFS_ACCESS_WRITE)
         fidflags |= SMB_FID_OPENWRITE;
     if (createOptions & FILE_DELETE_ON_CLOSE)
         fidflags |= SMB_FID_DELONCLOSE;
+    if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
+       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)
@@ -5976,17 +6996,19 @@ 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;
@@ -5994,7 +7016,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #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) {
@@ -6014,12 +7036,13 @@ 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;
@@ -6042,14 +7065,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);
@@ -6057,25 +7082,25 @@ 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;
                 }
 #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);
                         if (baseFidp) 
                             smb_ReleaseFID(baseFidp);
-                        cm_ReleaseUser(userp);
                         free(realPathp);
                         if (scp)
                             cm_ReleaseSCache(scp);
@@ -6140,7 +7165,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);
@@ -6161,8 +7186,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
      * scp is NULL.
      */
     if (code == 0 && !treeCreate) {
-        code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
+        code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
         if (code) {
+            cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
             if (scp)
@@ -6171,9 +7197,11 @@ 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 */
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
             if (scp)
@@ -6193,7 +7221,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
@@ -6202,9 +7230,21 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                      */
                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
                               scp, targetScp);
+                   cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                     cm_ReleaseSCache(scp);
                     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)
+                           cm_ReleaseSCache(scp);
+                       cm_ReleaseUser(userp);
+                       free(realPathp);
+                       return code;
+                   }
+               }
             }
             code = cm_SetAttr(scp, &setAttr, userp, &req);
             openAction = 3;    /* truncated existing file */
@@ -6222,9 +7262,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);
@@ -6233,7 +7273,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
            created = 1;
            if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
                smb_NotifyChange(FILE_ACTION_ADDED,
-                                FILE_NOTIFY_CHANGE_FILE_NAME,
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
                                 dscp, lastNamep, NULL, TRUE);
        } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
             /* Not an exclusive create, and someone else tried
@@ -6271,8 +7311,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;
@@ -6280,36 +7320,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++;
             }
@@ -6319,13 +7360,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
@@ -6333,8 +7374,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;
 
@@ -6359,6 +7400,8 @@ 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 (checkDoneRequired)
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         if (scp) 
             cm_ReleaseSCache(scp);
         if (dscp) 
@@ -6381,12 +7424,18 @@ 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 (checkDoneRequired) {
+                   cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                    checkDoneRequired = 0;
+                }
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
         }
 
         if (scp->fileType != CM_SCACHETYPE_FILE) {
+           if (checkDoneRequired)
+               cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
@@ -6398,6 +7447,8 @@ 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 (checkDoneRequired)
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         cm_ReleaseSCache(scp);
         if (dscp)
             cm_ReleaseSCache(dscp);
@@ -6408,7 +7459,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);
@@ -6427,7 +7478,12 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
 
-        if (fidflags & SMB_FID_SHARE_READ) {
+        /* If we are not opening the file for writing, then we don't
+           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) ||
+            !(fidflags & SMB_FID_OPENWRITE)) {
             sLockType = LOCKING_ANDX_SHARED_LOCK;
         } else {
             sLockType = 0;
@@ -6435,28 +7491,38 @@ 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) {
-            /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
-           smb_CloseFID(vcp, fidp, NULL, 0);
-            smb_ReleaseFID(fidp);
-
+           if (checkDoneRequired)
+               cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             if (dscp)
                 cm_ReleaseSCache(dscp);
-            cm_ReleaseUser(userp);
+           cm_ReleaseUser(userp);
+           /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
+           smb_CloseFID(vcp, fidp, NULL, 0);
+           smb_ReleaseFID(fidp);
             free(realPathp);
-            
             return code;
         }
     }
 
+    /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
+    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_ObtainWrite(&scp->rw);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseWrite(&scp->rw);
+    osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
 
     fidp->flags = fidflags;
 
@@ -6466,10 +7532,11 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* save parent dir and pathname for delete or change notification */
     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
+       osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
         fidp->flags |= SMB_FID_NTOPEN;
         fidp->NTopen_dscp = dscp;
-        cm_HoldSCache(dscp);
-        fidp->NTopen_pathp = strdup(lastNamep);
+       dscp = NULL;
+        fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
     }
     fidp->NTopen_wholepathp = realPathp;
     lock_ReleaseMutex(&fidp->mx);
@@ -6487,7 +7554,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;
@@ -6506,15 +7573,26 @@ 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(fidp->scp->length) && 
+        !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+        prefetch = 1;
+    }
+    lock_ReleaseRead(&scp->rw);
+
+    if (prefetch)
+        cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
+                           fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
+                           userp);
 
-    smb_ReleaseFID(fidp);
+
+    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);
 
     /* Can't free realPathp if we get here since
        fidp->NTopen_wholepathp is pointing there */
@@ -6527,9 +7605,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;
@@ -6537,7 +7617,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;
@@ -6546,15 +7626,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;
@@ -6565,7 +7644,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;
@@ -6573,8 +7652,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;
@@ -6598,23 +7680,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
@@ -6634,31 +7709,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) {
@@ -6690,8 +7774,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;
     }
@@ -6700,12 +7793,20 @@ 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)
-        fidflags |= SMB_FID_OPENREAD;
+    if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
+        fidflags |= SMB_FID_OPENREAD_LISTDIR;
     if (desiredAccess & AFS_ACCESS_WRITE)
         fidflags |= SMB_FID_OPENWRITE;
     if (createOptions & FILE_DELETE_ON_CLOSE)
         fidflags |= SMB_FID_DELONCLOSE;
+    if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
+       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)
@@ -6718,17 +7819,18 @@ 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;
@@ -6736,7 +7838,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 #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) {
@@ -6756,12 +7858,13 @@ 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;
@@ -6775,17 +7878,18 @@ 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;
@@ -6822,7 +7926,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);
@@ -6841,9 +7945,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
      * scp is NULL.
      */
     if (code == 0) {
-        code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
-                               &req);
+        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);
@@ -6851,9 +7955,11 @@ 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 */
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             if (dscp) 
                 cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
@@ -6880,8 +7986,20 @@ 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);
+                   cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                     cm_ReleaseSCache(scp);
                     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)
+                           cm_ReleaseSCache(scp);
+                       cm_ReleaseUser(userp);
+                       free(realPathp);
+                       return code;
+                   }
                 }
             }
             code = cm_SetAttr(scp, &setAttr, userp, &req);
@@ -6898,9 +8016,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);
@@ -6910,7 +8028,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
            created = 1;
            if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
                smb_NotifyChange(FILE_ACTION_ADDED,
-                                FILE_NOTIFY_CHANGE_FILE_NAME,
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
                                 dscp, lastNamep, NULL, TRUE);
        } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
             /* Not an exclusive create, and someone else tried
@@ -6949,14 +8067,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,
@@ -6976,7 +8094,9 @@ 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 (scp) 
+       if (checkDoneRequired)
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+       if (scp) 
             cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         free(realPathp);
@@ -6997,12 +8117,18 @@ 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 (checkDoneRequired) {
+                   cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+                    checkDoneRequired = 0;
+                }
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
         }
 
         if (scp->fileType != CM_SCACHETYPE_FILE) {
+           if (checkDoneRequired)
+               cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
@@ -7011,6 +8137,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
 
     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
+       if (checkDoneRequired)
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         free(realPathp);
@@ -7019,7 +8147,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);
@@ -7038,7 +8166,10 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         LLength.HighPart = 0;
         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
 
-        if (fidflags & SMB_FID_SHARE_READ) {
+        /* Similar to what we do in handling NTCreateX.  We get a
+           shared lock if we are only opening the file for reading. */
+        if ((fidflags & SMB_FID_SHARE_READ) ||
+            !(fidflags & SMB_FID_OPENWRITE)) {
             sLockType = LOCKING_ANDX_SHARED_LOCK;
         } else {
             sLockType = 0;
@@ -7046,26 +8177,36 @@ 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) {
-            /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
-           smb_CloseFID(vcp, fidp, NULL, 0);
-            smb_ReleaseFID(fidp);
-
+           if (checkDoneRequired)
+               cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
-            free(realPathp);
-            
+           /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
+           smb_CloseFID(vcp, fidp, NULL, 0);
+           smb_ReleaseFID(fidp);
+           free(realPathp);
             return CM_ERROR_SHARING_VIOLATION;
         }
     }
 
+    /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
+    if (checkDoneRequired) {
+       cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+        checkDoneRequired = 0;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    lock_ObtainWrite(&scp->rw);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseWrite(&scp->rw);
+    osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
 
     fidp->flags = fidflags;
 
@@ -7077,8 +8218,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
         fidp->flags |= SMB_FID_NTOPEN;
         fidp->NTopen_dscp = dscp;
-        cm_HoldSCache(dscp);
-        fidp->NTopen_pathp = strdup(lastNamep);
+       osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
+       dscp = NULL;
+        fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
     }
     fidp->NTopen_wholepathp = realPathp;
     lock_ReleaseMutex(&fidp->mx);
@@ -7120,7 +8262,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 */
@@ -7142,7 +8284,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;
@@ -7170,7 +8311,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 */
@@ -7195,32 +8336,44 @@ 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);
     }
 
-    osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
+    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
+         LargeIntegerGreaterThanZero(fidp->scp->length) && 
+         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+        prefetch = 1;
+    }
+    lock_ReleaseRead(&scp->rw);
 
-    smb_ReleaseFID(fidp);
+    if (prefetch)
+        cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
+                           fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
+                           userp);
+
+    osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
 
     cm_ReleaseUser(userp);
+    smb_ReleaseFID(fidp);
 
     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
     /* leave scp held since we put it in fidp->scp */
     return 0;
 }
 
+/* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
        smb_packet_t *outp)
 {
     smb_packet_t *savedPacketp;
-    ULONG filter; USHORT fid, watchtree;
+    ULONG filter; 
+    USHORT fid, watchtree;
     smb_fid_t *fidp;
     cm_scache_t *scp;
         
     filter = smb_GetSMBParm(inp, 19) |
              (smb_GetSMBParm(inp, 20) << 16);
     fid = smb_GetSMBParm(inp, 21);
-    watchtree = smb_GetSMBParm(inp, 22) && 0xffff;  /* TODO: should this be 0xff ? */
+    watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
 
     fidp = smb_FindFID(vcp, fid, 0);
     if (!fidp) {
@@ -7228,26 +8381,65 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
         return CM_ERROR_BADFD;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
+    /* 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);
     savedPacketp->nextp = smb_Directory_Watches;
     smb_Directory_Watches = savedPacketp;
     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
 
-    osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
-             filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
-
     scp = fidp->scp;
-    lock_ObtainMutex(&scp->mx);
+    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)
+       osi_Log0(smb_logp, "      Notify Change File Name");
+    if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
+       osi_Log0(smb_logp, "      Notify Change Directory Name");
+    if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
+       osi_Log0(smb_logp, "      Notify Change Attributes");
+    if (filter & FILE_NOTIFY_CHANGE_SIZE)
+       osi_Log0(smb_logp, "      Notify Change Size");
+    if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
+       osi_Log0(smb_logp, "      Notify Change Last Write");
+    if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
+       osi_Log0(smb_logp, "      Notify Change Last Access");
+    if (filter & FILE_NOTIFY_CHANGE_CREATION)
+       osi_Log0(smb_logp, "      Notify Change Creation");
+    if (filter & FILE_NOTIFY_CHANGE_EA)
+       osi_Log0(smb_logp, "      Notify Change Extended Attributes");
+    if (filter & FILE_NOTIFY_CHANGE_SECURITY)
+       osi_Log0(smb_logp, "      Notify Change Security");
+    if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
+       osi_Log0(smb_logp, "      Notify Change Stream Name");
+    if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
+       osi_Log0(smb_logp, "      Notify Change Stream Size");
+    if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
+       osi_Log0(smb_logp, "      Notify Change Stream Write");
+
+    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);
     smb_ReleaseFID(fidp);
 
     outp->flags |= SMB_PACKETFLAG_NOSEND;
@@ -7269,6 +8461,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;
@@ -7337,6 +8530,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;
@@ -7350,21 +8547,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;
 }
@@ -7375,13 +8578,16 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
  *
  * If we don't know the file name (i.e. a callback break), filename is
  * NULL, and we return a zero-length list.
+ *
+ * At present there is not a single call to smb_NotifyChange that 
+ * has the isDirectParent parameter set to FALSE.  
  */
 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;
@@ -7397,8 +8603,20 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
     }
 
-    osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
-             osi_LogSaveString(smb_logp,filename),dscp);
+    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)
+       osi_Log0(smb_logp,"      FILE_ACTION_ADDED");
+    if (action == FILE_ACTION_REMOVED)
+       osi_Log0(smb_logp,"      FILE_ACTION_REMOVED");
+    if (action == FILE_ACTION_MODIFIED)
+       osi_Log0(smb_logp,"      FILE_ACTION_MODIFIED");
+    if (action == FILE_ACTION_RENAMED_OLD_NAME)
+       osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_OLD_NAME");
+    if (action == FILE_ACTION_RENAMED_NEW_NAME)
+       osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_NEW_NAME");
 
     lock_ObtainMutex(&smb_Dir_Watch_Lock);
     watch = smb_Directory_Watches;
@@ -7406,39 +8624,66 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
         filter = smb_GetSMBParm(watch, 19)
             | (smb_GetSMBParm(watch, 20) << 16);
         fid = smb_GetSMBParm(watch, 21);
-        wtree = smb_GetSMBParm(watch, 22) & 0xffff;  /* TODO: should this be 0xff ? */
+        wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
+
         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
 
         /*
-         * Strange hack - bug in NT Client and NT Server that we
-         * must emulate?
+         * Strange hack - bug in NT Client and NT Server that we must emulate?
          */
-        if (filter == 3 && wtree)
-            filter = 0x17;
+        if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
+            filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
 
         fidp = smb_FindFID(watch->vcp, fid, 0);
         if (!fidp) {
-            osi_Log1(smb_logp," no fidp for fid[%d]",fid);
+            osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
             lastWatch = watch;
             watch = watch->nextp;
             continue;
-        }       
-        if (fidp->scp != dscp
-             || (filter & notifyFilter) == 0
-             || (!isDirectParent && !wtree)) {
-            osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
-            smb_ReleaseFID(fidp);
+        }      
+
+        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);
             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)
+           osi_Log0(smb_logp, "      Notify Change Directory Name");
+       if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
+           osi_Log0(smb_logp, "      Notify Change Attributes");
+       if (filter & FILE_NOTIFY_CHANGE_SIZE)
+           osi_Log0(smb_logp, "      Notify Change Size");
+       if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
+           osi_Log0(smb_logp, "      Notify Change Last Write");
+       if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
+           osi_Log0(smb_logp, "      Notify Change Last Access");
+       if (filter & FILE_NOTIFY_CHANGE_CREATION)
+           osi_Log0(smb_logp, "      Notify Change Creation");
+       if (filter & FILE_NOTIFY_CHANGE_EA)
+           osi_Log0(smb_logp, "      Notify Change Extended Attributes");
+       if (filter & FILE_NOTIFY_CHANGE_SECURITY)
+           osi_Log0(smb_logp, "      Notify Change Security");
+       if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
+           osi_Log0(smb_logp, "      Notify Change Stream Name");
+       if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
+           osi_Log0(smb_logp, "      Notify Change Stream Size");
+       if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
+           osi_Log0(smb_logp, "      Notify Change Stream Write");
+                    
+       /* A watch can only be notified once.  Remove it from the list */
         nextWatch = watch->nextp;
         if (watch == smb_Directory_Watches)
             smb_Directory_Watches = nextWatch;
@@ -7446,26 +8691,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 */
@@ -7499,7 +8747,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;
@@ -7509,12 +8756,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;
@@ -7523,13 +8768,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
@@ -7549,11 +8790,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;
@@ -7587,17 +8831,18 @@ 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;
-                lock_ObtainMutex(&scp->mx);
+               osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
+                lock_ObtainWrite(&scp->rw);
                 if (watchtree)
                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
                 else
                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
-                lock_ReleaseMutex(&scp->mx);
+                lock_ReleaseWrite(&scp->rw);
                 smb_ReleaseFID(fidp);
             } else {
                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
@@ -7636,7 +8881,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;
@@ -7646,37 +8891,34 @@ long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     rename_type = smb_GetSMBParm(inp, 1);
 
     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
-        osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
+        osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
         return CM_ERROR_NOACCESS;
     }
 
     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);
+    newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
+
+    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;
@@ -7686,9 +8928,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);