DEVEL15-windows-freelance-improved-dfs-handling-20080127
[openafs.git] / src / WINNT / afsd / smb3.c
index ea89009..3523aca 100644 (file)
 
 #ifndef DJGPP
 #include <windows.h>
+#pragma warning(push)
+#pragma warning(disable: 4005)
+#include <ntstatus.h>
 #define SECURITY_WIN32
 #include <security.h>
 #include <lmaccess.h>
+#pragma warning(pop)
 #endif /* !DJGPP */
 #include <stdlib.h>
 #include <malloc.h>
 #include <string.h>
 #include <stdio.h>
 #include <time.h>
-
 #include <osi.h>
 
 #include "afsd.h"
+#include <WINNT\afsreg.h>
 
 #include "smb.h"
 
@@ -40,6 +44,8 @@ smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
 /* protected by the smb_globalLock */
 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
 
+const char **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)
@@ -48,20 +54,38 @@ cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
     cm_user_t *up = NULL;
         
     uidp = smb_FindUID(vcp, inp->uid, 0);
-    if (!uidp) return NULL;
+    if (!uidp) 
+       return NULL;
         
-    lock_ObtainMutex(&uidp->mx);
-    if (uidp->unp) {
-        up = uidp->unp->userp;
-        cm_HoldUser(up);
-    }
-    lock_ReleaseMutex(&uidp->mx);
+    up = smb_GetUserFromUID(uidp);
 
     smb_ReleaseUID(uidp);
 
     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 char *name)
+{
+    int i, j, len;
+        
+    if ( smb_ExecutableExtensions == NULL || name == NULL)
+        return 0;
+
+    len = strlen(name);
+
+    for ( i=0; smb_ExecutableExtensions[i]; i++) {
+        j = len - strlen(smb_ExecutableExtensions[i]);
+        if (_stricmp(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
@@ -72,19 +96,15 @@ unsigned long smb_ExtAttributes(cm_scache_t *scp)
     unsigned long attrs;
 
     if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
-        scp->fileType == CM_SCACHETYPE_MOUNTPOINT) 
+        scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+        scp->fileType == CM_SCACHETYPE_INVALID)
     {
         attrs = SMB_ATTR_DIRECTORY;
 #ifdef SPECIAL_FOLDERS
-#ifdef AFS_FREELANCE_CLIENT
-        if ( cm_freelanceEnabled &&
-             scp->fid.cell==AFS_FAKE_ROOT_CELL_ID && 
-             scp->fid.volume==AFS_FAKE_ROOT_VOL_ID &&
-             scp->fid.vnode==0x1 && scp->fid.unique==0x1) {
-            attrs |= SMB_ATTR_SYSTEM;          /* FILE_ATTRIBUTE_SYSTEM */
-        }
-#endif /* AFS_FREELANCE_CLIENT */
+        attrs |= SMB_ATTR_SYSTEM;              /* FILE_ATTRIBUTE_SYSTEM */
 #endif /* SPECIAL_FOLDERS */
+    } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+        attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
     } else
         attrs = 0;
     /*
@@ -93,9 +113,11 @@ unsigned long smb_ExtAttributes(cm_scache_t *scp)
      */
 #ifdef notdef
     if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
+        attrs |= SMB_ATTR_READONLY;            /* Read-only */
+#else
+    if ((scp->unixModeBits & 0222) == 0)
+        attrs |= SMB_ATTR_READONLY;            /* Read-only */
 #endif
-       if ((scp->unixModeBits & 0222) == 0)
-            attrs |= SMB_ATTR_READONLY;                /* Read-only */
 
     if (attrs == 0)
         attrs = SMB_ATTR_NORMAL;               /* FILE_ATTRIBUTE_NORMAL */
@@ -108,7 +130,7 @@ int smb_V3IsStarMask(char *maskp)
     char tc;
 
     while (tc = *maskp++)
-        if (tc == '?' || tc == '*') 
+        if (tc == '?' || tc == '*' || tc == '<' || tc == '>') 
             return 1;
     return 0;
 }
@@ -122,7 +144,6 @@ unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
     return inp;
 }   
 
-/*DEBUG do not checkin*/
 void OutputDebugF(char * format, ...) {
     va_list args;
     int len;
@@ -149,8 +170,8 @@ void OutputDebugHexDump(unsigned char * buffer, int 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));
+                strcat(buf,"\r\n");
                 OutputDebugString(buf);
             }
             sprintf(buf,"%5x",i);
@@ -170,14 +191,14 @@ void OutputDebugHexDump(unsigned char * buffer, int len) {
         buf[j] = (k>32 && k<127)?k:'.';
     }    
     if(i) {
-        osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
-        strcat(buf,"\n");
+        osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
+        strcat(buf,"\r\n");
         OutputDebugString(buf);
     }   
 }
-/**/
 
 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
+
 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
     SECURITY_STATUS status, istatus;
     CredHandle creds = {0,0};
@@ -202,7 +223,7 @@ void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
                                        &creds,
                                        &expiry);
 
-    if (status != SEC_E_OK) {       
+    if (status != SEC_E_OK) {
         /* Really bad. We return an empty security blob */
         OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
         goto nes_0;
@@ -533,19 +554,19 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDom
        
     lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
     mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
-    lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
+    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);
-    lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
+    lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
     lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
 
     lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
     lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
     size = MAX_COMPUTERNAME_LENGTH + 1;
     GetComputerNameW(lmAuth.workstationW, &size);
-    lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
+    lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
 
     memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
 
@@ -565,8 +586,8 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDom
     lmAuth.tgroups.Groups[0].Sid = NULL;
     lmAuth.tgroups.Groups[0].Attributes = 0;
 
-    lmAuth.tsource.SourceIdentifier.HighPart = 0;
-    lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
+    lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
+    lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
     strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
 
     nts = LsaLogonUser( smb_lsaHandle,
@@ -584,6 +605,10 @@ long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDom
                         &quotaLimits,
                         &ntsEx);
 
+    if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
+        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);
 
@@ -646,11 +671,12 @@ long smb_GetNormalizedUsername(char * usern, const char * accountName, const cha
     return 0;
 }
 
-/* When using SMB auth, all SMB sessions have to pass through here first to
- * authenticate the user. 
- * Caveat: If not use the SMB auth the protocol does not require sending a
- * session setup packet, which means that we can't rely on a UID in subsequent
- * packets.  Though in practice we get one anyway.
+/* When using SMB auth, all SMB sessions have to pass through here
+ * first to authenticate the user.  
+ *
+ * Caveat: If not using SMB auth, the protocol does not require
+ * sending a session setup packet, which means that we can't rely on a
+ * UID in subsequent packets.  Though in practice we get one anyway.
  */
 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
@@ -658,7 +684,6 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     smb_user_t *uidp;
     unsigned short newUid;
     unsigned long caps = 0;
-    cm_user_t *userp;
     smb_username_t *unp;
     char *s1 = " ";
     long code = 0; 
@@ -675,6 +700,8 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             /* extended authentication */
             char *secBlobIn;
             int secBlobInLength;
+
+            OutputDebugF("NT Session Setup: Extended");
         
             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
                 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
@@ -711,6 +738,11 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             char *primaryDomain;
             int  datalen;
 
+            if (smb_authType == SMB_AUTH_NTLM)
+                OutputDebugF("NT Session Setup: NTLM");
+            else
+                OutputDebugF("NT Session Setup: None");
+
             /* TODO: parse for extended auth as well */
             ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
             csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
@@ -727,6 +759,11 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
             accountName = smb_ParseString(tp, &tp);
             primaryDomain = smb_ParseString(tp, NULL);
 
+            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");
+
             if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
                 /* shouldn't happen */
                 code = CM_ERROR_BADSMB;
@@ -740,6 +777,10 @@ 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);
+                else
+                    OutputDebugF("LM authentication succeeded");
             }
         }
     }  else { /* V3 */
@@ -748,6 +789,16 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         char *accountName;
         char *primaryDomain;
 
+        switch ( smb_authType ) {
+        case SMB_AUTH_EXTENDED:
+            OutputDebugF("V3 Session Setup: Extended");
+            break;
+        case SMB_AUTH_NTLM:
+            OutputDebugF("V3 Session Setup: NTLM");
+            break;
+        default:
+            OutputDebugF("V3 Session Setup: None");
+        }
         ciPwdLength = smb_GetSMBParm(inp, 7);
         tp = smb_GetSMBData(inp, NULL);
         ciPwd = tp;
@@ -756,6 +807,10 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         accountName = smb_ParseString(tp, &tp);
         primaryDomain = smb_ParseString(tp, NULL);
 
+        OutputDebugF("Account Name: %s",accountName);
+        OutputDebugF("Primary Domain: %s", primaryDomain);
+        OutputDebugF("Case Insensitive Password: %s", ciPwd && ciPwd[0] ? "yes" : "no");
+
         if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
             /* shouldn't happen */
             code = CM_ERROR_BADSMB;
@@ -767,6 +822,10 @@ 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);
+            else
+                OutputDebugF("LM authentication succeeded");
         }
     }
 
@@ -804,21 +863,31 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     uidp = smb_FindUserByNameThisSession(vcp, usern);
     if (uidp) {   /* already there, so don't create a new one */
         unp = uidp->unp;
-        userp = unp->userp;
-        newUid = (unsigned short)uidp->userID;  /* For some reason these are different types!*/
-        osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
-        osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
+        newUid = uidp->userID;
+        osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
+                vcp->lana,vcp->lsn,newUid);
         smb_ReleaseUID(uidp);
     }
     else {
-      /* do a global search for the username/machine name pair */
+       cm_user_t *userp;
+
+       /* do a global search for the username/machine name pair */
         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
+       lock_ObtainMutex(&unp->mx);
+       if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
+           /* clear the afslogon flag so that the tickets can now 
+            * be freed when the refCount returns to zero.
+            */
+           unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
+       }
+       lock_ReleaseMutex(&unp->mx);
 
         /* Create a new UID and cm_user_t structure */
         userp = unp->userp;
         if (!userp)
             userp = cm_NewUser();
-        lock_ObtainMutex(&vcp->mx);
+       cm_HoldUserVCRef(userp);
+       lock_ObtainMutex(&vcp->mx);
         if (!vcp->uidCounter)
             vcp->uidCounter++; /* handle unlikely wraparounds */
         newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
@@ -830,12 +899,13 @@ long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         lock_ReleaseMutex(&unp->mx);
 
         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
-        lock_ObtainMutex(&uidp->mx);
-        uidp->unp = unp;
-        osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,osi_LogSaveString(smb_logp, usern));
-        osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
-        lock_ReleaseMutex(&uidp->mx);
-        smb_ReleaseUID(uidp);
+       if (uidp) {
+           lock_ObtainMutex(&uidp->mx);
+           uidp->unp = unp;
+           osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
+           lock_ReleaseMutex(&uidp->mx);
+           smb_ReleaseUID(uidp);
+       }
     }
 
     /* Return UID to the client */
@@ -889,30 +959,38 @@ long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 {
     smb_user_t *uidp;
 
-    /* don't get tokens from this VC */
-    vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-
-    inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
-
     /* find the tree and free it */
     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
-    /* TODO: smb_ReleaseUID() ? */
     if (uidp) {
-        char *s1 = NULL, *s2 = NULL;
-
-        if (s2 == NULL) s2 = " ";
-        if (s1 == NULL) {s1 = s2; s2 = " ";}
+       smb_username_t * unp;
 
-        osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
-                  osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
+        osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %s", uidp->userID,
+                  osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "));
 
         lock_ObtainMutex(&uidp->mx);
         uidp->flags |= SMB_USERFLAG_DELETE;
-        /*
+       /*
          * it doesn't get deleted right away
          * because the vcp points to it
          */
+       unp = uidp->unp;
         lock_ReleaseMutex(&uidp->mx);
+
+#ifdef COMMENT
+       /* we can't do this.  we get logoff messages prior to a session
+        * disconnect even though it doesn't mean the user is logging out.
+        * we need to create a new pioctl and EventLogoff handler to set
+        * SMB_USERNAMEFLAG_LOGOFF.
+        */
+       if (unp && smb_LogoffTokenTransfer) {
+           lock_ObtainMutex(&unp->mx);
+           unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
+           unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
+           lock_ReleaseMutex(&unp->mx);
+       }
+#endif
+
+       smb_ReleaseUID(uidp);
     }
     else    
         osi_Log0(smb_logp, "SMB3 user logoffX");
@@ -922,20 +1000,21 @@ 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
 
 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tid_t *tidp;
-    smb_user_t *uidp;
+    smb_user_t *uidp = NULL;
     unsigned short newTid;
-    char shareName[256];
+    char shareName[AFSPATHMAX];
     char *sharePath;
     int shareFound;
     char *tp;
     char *pathp;
     char *passwordp;
     char *servicep;
-    cm_user_t *userp;
+    cm_user_t *userp = NULL;
     int ipc = 0;
         
     osi_Log0(smb_logp, "SMB3 receive tree connect");
@@ -944,6 +1023,8 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     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, '\\');
@@ -965,7 +1046,9 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
 #endif
     }
 
-    userp = smb_GetUser(vcp, inp);
+    uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+    if (uidp)
+       userp = smb_GetUserFromUID(uidp);
 
     lock_ObtainMutex(&vcp->mx);
     newTid = vcp->tidCounter++;
@@ -973,12 +1056,13 @@ 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) {
-        uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+    if (!ipc) {
+       if (!strcmp(shareName, "*."))
+           strcpy(shareName, "all");
        shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
-        if (uidp)
-            smb_ReleaseUID(uidp);
        if (!shareFound) {
+           if (uidp)
+               smb_ReleaseUID(uidp);
             smb_ReleaseTID(tidp);
             return CM_ERROR_BADSHARENAME;
        }
@@ -986,17 +1070,35 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
        if (vcp->flags & SMB_VCFLAG_USENT)
         {
             int policy = smb_FindShareCSCPolicy(shareName);
-            smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
+            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 | 
+                           (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
+                            (policy << 2));
         }
     } else {
         smb_SetSMBParm(outp, 2, 0);
         sharePath = NULL;
     }
+    if (uidp)
+       smb_ReleaseUID(uidp);
 
     lock_ObtainMutex(&tidp->mx);
     tidp->userp = userp;
     tidp->pathname = sharePath;
-    if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
+    if (ipc) 
+        tidp->flags |= SMB_TIDFLAG_IPC;
     lock_ReleaseMutex(&tidp->mx);
     smb_ReleaseTID(tidp);
 
@@ -1004,10 +1106,15 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     ((smb_t *)inp)->tid = newTid;
     tp = smb_GetSMBData(outp, NULL);
     if (!ipc) {
+        /* XXX - why is this a drive letter? */
         *tp++ = 'A';
         *tp++ = ':';
         *tp++ = 0;
-        smb_SetSMBDataLength(outp, 3);
+        *tp++ = 'A';
+        *tp++ = 'F';
+        *tp++ = 'S';
+        *tp++ = 0;
+        smb_SetSMBDataLength(outp, 7);
     } else {
         strcpy(tp, "IPC");
         smb_SetSMBDataLength(outp, 4);
@@ -1076,7 +1183,8 @@ smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
         
     tp = malloc(sizeof(*tp));
     memset(tp, 0, sizeof(*tp));
-    tp->vcp = NULL;
+    smb_HoldVC(vcp);
+    tp->vcp = vcp;
     tp->curData = tp->curParms = 0;
     tp->totalData = totalData;
     tp->totalParms = totalParms;
@@ -1107,10 +1215,13 @@ smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
     return tp;
 }       
 
-/* free a tran2 packet; must be called with smb_globalLock held */
+/* free a tran2 packet */
 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
 {
-    if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
+    if (t2p->vcp) {
+        smb_ReleaseVC(t2p->vcp);
+       t2p->vcp = NULL;
+    }
     if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
         if (t2p->parmsp)
             free(t2p->parmsp);
@@ -1141,7 +1252,7 @@ void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
 
     /* We can handle long names */
     if (vcp->flags & SMB_VCFLAG_USENT)
-        smbp->flg2 |= 0x40;    /* IS_LONG_NAME */
+        smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
         
     /* now copy important fields from the tran 2 packet */
     smbp->com = t2p->com;
@@ -1155,7 +1266,7 @@ void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
         smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
         smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
         smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
-        smbp->flg2 |= 0x4000;
+        smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
     }
     else {
         smbp->rcls = errClass;
@@ -1181,7 +1292,7 @@ void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp
 
     /* We can handle long names */
     if (vcp->flags & SMB_VCFLAG_USENT)
-        smbp->flg2 |= 0x40;    /* IS_LONG_NAME */
+        smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
 
     /* now copy important fields from the tran 2 packet */
     smbp->com = t2p->com;
@@ -1210,7 +1321,7 @@ void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp
     smb_SetSMBParm(tp, 7, dataOffset); /* offset of data */
     smb_SetSMBParm(tp, 8, 0);          /* data displacement */
     smb_SetSMBParm(tp, 9, 0);          /* low: setup word count *
-    * high: resvd */
+                                         * high: resvd */
 
     datap = smb_GetSMBData(tp, NULL);
     *datap++ = 0;                              /* we rounded to even */
@@ -1239,19 +1350,9 @@ 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
-        HANDLE h;
-        char *ptbuf[1];
-
-        osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
-
-        h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
-        ptbuf[0] = "Transaction2 word count = 0";
-        ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
-                    1, inp->ncb_length, ptbuf, inp);
-        DeregisterEventSource(h);
-#else /* DJGPP */
-        osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
+       LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
 #endif /* !DJGPP */
 
         smb_SetSMBDataLength(outp, 0);
@@ -1324,13 +1425,12 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         rapOp = asp->parmsp[0];
 
         if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
-            osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
-            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
+            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
             code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
+            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return  code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
         }
         else {
-            osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
-            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
+            osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
             code = CM_ERROR_BADOP;
         }
 
@@ -1344,9 +1444,7 @@ long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         }
 
         /* free the input tran 2 packet */
-        lock_ObtainWrite(&smb_globalLock);
         smb_FreeTran2Packet(asp);
-        lock_ReleaseWrite(&smb_globalLock);
     }
     else if (firstPacket) {
         /* the first packet in a multi-packet request, we need to send an
@@ -1427,17 +1525,18 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     int outDataTotal;  /* total data bytes */
     int code = 0;
     DWORD rv;
-    DWORD allSubmount;
-    USHORT nShares;
-    DWORD nRegShares;
-    DWORD nSharesRet;
+    DWORD allSubmount = 0;
+    USHORT nShares = 0;
+    DWORD nRegShares = 0;
+    DWORD nSharesRet = 0;
     HKEY hkParam;
     HKEY hkSubmount = NULL;
     smb_rap_share_info_1_t * shares;
     USHORT cshare = 0;
     char * cstrp;
-    char thisShare[256];
+    char thisShare[AFSPATHMAX];
     int i,j;
+    DWORD dw;
     int nonrootShares;
     smb_rap_share_list_t rootShares;
     cm_req_t req;
@@ -1455,7 +1554,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     }
 
     /* first figure out how many shares there are */
-    rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
+    rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                       KEY_QUERY_VALUE, &hkParam);
     if (rv == ERROR_SUCCESS) {
         len = sizeof(allSubmount);
@@ -1467,7 +1566,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
         RegCloseKey (hkParam);
     }
 
-    rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
+    rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
                       0, KEY_QUERY_VALUE, &hkSubmount);
     if (rv == ERROR_SUCCESS) {
         rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
@@ -1490,13 +1589,13 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     thyper.HighPart = 0;
     thyper.LowPart = 0;
 
-    cm_HoldSCache(cm_rootSCachep);
-    cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
-    cm_ReleaseSCache(cm_rootSCachep);
+    cm_HoldSCache(cm_data.rootSCachep);
+    cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
+    cm_ReleaseSCache(cm_data.rootSCachep);
 
     cm_ReleaseUser(userp);
 
-    nShares = rootShares.cShare + nRegShares + allSubmount;
+    nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
 
 #define REMARK_LEN 1
     outParmsTotal = 8; /* 4 dwords */
@@ -1519,20 +1618,20 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
 
     if (allSubmount) {
         strcpy( shares[cshare].shi1_netname, "all" );
-        shares[cshare].shi1_remark = cstrp - outp->datap;
+        shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
         /* type and pad are zero already */
         cshare++;
         cstrp+=REMARK_LEN;
     }
 
     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);
+            rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
             if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
                 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
-                shares[cshare].shi1_remark = cstrp - outp->datap;
+                shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
                 cshare++;
                 cstrp+=REMARK_LEN;
             }
@@ -1557,7 +1656,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
         }
 
         strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
-        shares[cshare].shi1_remark = cstrp - outp->datap;
+        shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
         cshare++;
         cstrp+=REMARK_LEN;
     }
@@ -1567,7 +1666,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     outp->parmsp[2] = cshare;
     outp->parmsp[3] = nShares;
 
-    outp->totalData = cstrp - outp->datap;
+    outp->totalData = (int)(cstrp - outp->datap);
     outp->totalParms = outParmsTotal;
 
     smb_SendTran2Packet(vcp, outp, op);
@@ -1606,17 +1705,17 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
 
     if (infoLevel == 0)
         totalData = sizeof(smb_rap_share_info_0_t);
-    else if(infoLevel == 1)
+    else if(infoLevel == SMB_INFO_STANDARD)
         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
-    else if(infoLevel == 2)
+    else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
     else
         return CM_ERROR_INVAL;
 
     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
 
-    if(!stricmp(shareName,"all")) {
-        rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
+    if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
+        rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                           KEY_QUERY_VALUE, &hkParam);
         if (rv == ERROR_SUCCESS) {
             len = sizeof(allSubmount);
@@ -1632,7 +1731,7 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
             shareFound = TRUE;
 
     } else {
-        rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
+        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);
@@ -1658,20 +1757,20 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
         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;
-    } else if(infoLevel == 1) {
+    } 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);
         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
-        info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
+        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;
-        info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
+        info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
         info->shi2_permissions = ACCESS_ALL;
         info->shi2_max_uses = (unsigned short) -1;
-        info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
+        info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
     }
 
     outp->totalData = totalData;
@@ -1832,7 +1931,7 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
         info0 = (smb_rap_server_info_0_t *) outp->datap;
         cstrp = (char *) (info0 + 1);
         strcpy(info0->sv0_name, "AFS");
-    } else { /* infoLevel == 1 */
+    } else { /* infoLevel == SMB_INFO_STANDARD */
         info1 = (smb_rap_server_info_1_t *) outp->datap;
         cstrp = (char *) (info1 + 1);
         strcpy(info1->sv1_name, "AFS");
@@ -1851,7 +1950,7 @@ long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pac
         cstrp += smb_ServerCommentLen;
     }
 
-    totalData = cstrp - outp->datap;
+    totalData = (DWORD)(cstrp - outp->datap);
     outp->totalData = min(bufsize,totalData); /* actual data size */
     outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
     outp->parmsp[2] = totalData;
@@ -1879,19 +1978,9 @@ long smb_ReceiveV3Tran2A(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
-        HANDLE h;
-        char *ptbuf[1];
-
-        osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
-
-        h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
-        ptbuf[0] = "Transaction2 word count = 0";
-        ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
-                    1, inp->ncb_length, ptbuf, inp);
-        DeregisterEventSource(h);
-#else /* DJGPP */
-        osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
+       LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
 #endif /* !DJGPP */
 
         smb_SetSMBDataLength(outp, 0);
@@ -1962,13 +2051,11 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         /* now dispatch it */
         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
-            osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
-            osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
+            osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
         }
         else {
-            osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
-            osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
+            osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
             code = CM_ERROR_BADOP;
         }
 
@@ -1982,9 +2069,7 @@ long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         }
 
         /* free the input tran 2 packet */
-        lock_ObtainWrite(&smb_globalLock);
         smb_FreeTran2Packet(asp);
-        lock_ReleaseWrite(&smb_globalLock);
     }
     else if (firstPacket) {
         /* the first packet in a multi-packet request, we need to send an
@@ -2012,7 +2097,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     smb_fid_t *fidp;
     int attributes;
     char *lastNamep;
-    time_t dosTime;
+    afs_uint32 dosTime;
     int openFun;
     int trunc;
     int openMode;
@@ -2022,6 +2107,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     long returnEALength;
     char *tidPathp;
     cm_req_t req;
+    int created = 0;
 
     cm_InitReq(&req);
 
@@ -2041,10 +2127,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         
     /* compute initial mode bits based on read-only flag in attributes */
     initialModeBits = 0666;
-    if (attributes & 1) initialModeBits &= ~0222;
+    if (attributes & SMB_ATTR_READONLY) 
+        initialModeBits &= ~0222;
         
     pathp = (char *) (&p->parmsp[14]);
-        
+    if (smb_StoreAnsiFilenames)
+        OemToChar(pathp,pathp);
+    
     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
 
     spacep = cm_GetSpace();
@@ -2059,26 +2148,26 @@ 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; parmSlot++;
+        outp->parmsp[parmSlot++] = fidp->fid;
         if (extraInfo) {
-            outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
-            outp->parmsp[parmSlot] = 0; parmSlot++;    /* mod time */
-            outp->parmsp[parmSlot] = 0; parmSlot++;
-            outp->parmsp[parmSlot] = 0; parmSlot++;    /* len */
-            outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
-            outp->parmsp[parmSlot] = openMode; parmSlot++;
-            outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
-            outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
+            outp->parmsp[parmSlot++] = 0;       /* attrs */
+            outp->parmsp[parmSlot++] = 0;       /* mod time */
+            outp->parmsp[parmSlot++] = 0; 
+            outp->parmsp[parmSlot++] = 0;       /* len */
+            outp->parmsp[parmSlot++] = 0x7fff;
+            outp->parmsp[parmSlot++] = openMode;
+            outp->parmsp[parmSlot++] = 0;       /* file type 0 ==> normal file or dir */
+            outp->parmsp[parmSlot++] = 0;       /* IPC junk */
         }   
         /* and the final "always present" stuff */
-        outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
+        outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
         /* next write out the "unique" ID */
-        outp->parmsp[parmSlot] = 0x1234; parmSlot++;
-        outp->parmsp[parmSlot] = 0x5678; parmSlot++;
-        outp->parmsp[parmSlot] = 0; parmSlot++;
+        outp->parmsp[parmSlot++] = 0x1234;
+        outp->parmsp[parmSlot++] = 0x5678;
+        outp->parmsp[parmSlot++] = 0;
         if (returnEALength) {
-            outp->parmsp[parmSlot] = 0; parmSlot++;
-            outp->parmsp[parmSlot] = 0; parmSlot++;
+            outp->parmsp[parmSlot++] = 0;
+            outp->parmsp[parmSlot++] = 0;
         }       
                 
         outp->totalData = 0;
@@ -2113,21 +2202,25 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 
     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
     if (code == CM_ERROR_TIDIPC) {
-        /* Attempt to use TID allocated for IPC.  The client is
-           probably trying to locate DCE RPC end points, which
-           we don't support. */
+        /* Attempt to use a TID allocated for IPC.  The client
+         * is probably looking for DCE RPC end points which we
+         * don't support OR it could be looking to make a DFS
+         * referral request. 
+         */
         osi_Log0(smb_logp, "Tran2Open received IPC TID");
+#ifndef DFS_SUPPORT
         cm_ReleaseUser(userp);
         smb_FreeTran2Packet(outp);
         return CM_ERROR_NOSUCHPATH;
+#endif
     }
 
     dscp = NULL;
-    code = cm_NameI(cm_rootSCachep, pathp,
+    code = cm_NameI(cm_data.rootSCachep, pathp,
                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                      userp, tidPathp, &req, &scp);
     if (code != 0) {
-        code = cm_NameI(cm_rootSCachep, spacep->data,
+        code = cm_NameI(cm_data.rootSCachep, spacep->data,
                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                          userp, tidPathp, &req, &dscp);
         cm_FreeSpace(spacep);
@@ -2138,6 +2231,19 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             return code;
         }
         
+#ifdef DFS_SUPPORT
+        if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+            cm_ReleaseSCache(dscp);
+            cm_ReleaseUser(userp);
+            smb_FreeTran2Packet(outp);
+            if ( WANTS_DFS_PATHNAMES(p) || pnc )
+                return CM_ERROR_PATH_NOT_COVERED;
+            else
+                return CM_ERROR_BADSHARENAME;
+        }
+#endif /* DFS_SUPPORT */
+
         /* otherwise, scp points to the parent directory.  Do a lookup,
          * and truncate the file if we find it, otherwise we create the
          * file.
@@ -2148,14 +2254,27 @@ 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);
             return code;
         }
-    }
-    else {
+    } 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) || pnc )
+                return CM_ERROR_PATH_NOT_COVERED;
+            else
+                return CM_ERROR_BADSHARENAME;
+        }
+#endif /* DFS_SUPPORT */
+
+        /* macintosh is expensive to program for it */
         cm_FreeSpace(spacep);
     }
         
@@ -2165,7 +2284,8 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     if (code == 0) {
         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
         if (code) {
-            if (dscp) cm_ReleaseSCache(dscp);
+            if (dscp) 
+                cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             smb_FreeTran2Packet(outp);
@@ -2174,7 +2294,8 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 
         if (excl) {
             /* oops, file shouldn't be there */
-            if (dscp) cm_ReleaseSCache(dscp);
+            if (dscp) 
+                cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             smb_FreeTran2Packet(outp);
@@ -2191,26 +2312,29 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         else 
             openAction = 1;    /* found existing file */
     }
-    else if (!(openFun & SMB_ATTR_DIRECTORY)) {
+    else if (!(openFun & 0x10)) {
         /* don't create if not found */
-        if (dscp) cm_ReleaseSCache(dscp);
-        osi_assert(scp == NULL);
+        if (dscp) 
+            cm_ReleaseSCache(dscp);
+        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);
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                           &req);
-        if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-            smb_NotifyChange(FILE_ACTION_ADDED,
-                             FILE_NOTIFY_CHANGE_FILE_NAME,  
-                             dscp, lastNamep, NULL, TRUE);
-        if (!excl && code == CM_ERROR_EXISTS) {
+        if (code == 0) {
+           created = 1;
+           if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+               smb_NotifyChange(FILE_ACTION_ADDED,
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
+                                 dscp, lastNamep, NULL, TRUE);
+       } else if (!excl && code == CM_ERROR_EXISTS) {
             /* 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
@@ -2232,11 +2356,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     }
         
     /* we don't need this any longer */
-    if (dscp) cm_ReleaseSCache(dscp);
+    if (dscp) 
+        cm_ReleaseSCache(dscp);
 
     if (code) {
         /* something went wrong creating or truncating the file */
-        if (scp) cm_ReleaseSCache(scp);
+        if (scp) 
+            cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         smb_FreeTran2Packet(outp);
         return code;
@@ -2250,9 +2376,9 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
             if (code == 0) {
                 /* we have a more accurate file to use (the
-                * target of the symbolic link).  Otherwise,
-                * we'll just use the symlink anyway.
-                */
+                 * target of the symbolic link).  Otherwise,
+                 * we'll just use the symlink anyway.
+                 */
                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
                           scp, targetScp);
                 cm_ReleaseSCache(scp);
@@ -2269,46 +2395,60 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 
     /* now all we have to do is open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
        
+    cm_HoldUser(userp);
+    lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
+    osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
     fidp->scp = scp;
+    lock_ObtainMutex(&scp->mx);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseMutex(&scp->mx);
+    
+    /* and the user */
+    fidp->userp = userp;
         
     /* compute open mode */
-    if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
+    if (openMode != 1) 
+       fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     if (openMode == 1 || openMode == 2)
         fidp->flags |= SMB_FID_OPENWRITE;
 
+    /* remember that the file was newly created */
+    if (created)
+       fidp->flags |= SMB_FID_CREATED;
+
+    lock_ReleaseMutex(&fidp->mx);
+
     smb_ReleaseFID(fidp);
         
     cm_Open(scp, 0, userp);
 
     /* copy out remainder of the parms */
     parmSlot = 0;
-    outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
+    outp->parmsp[parmSlot++] = fidp->fid;
     lock_ObtainMutex(&scp->mx);
     if (extraInfo) {
-        outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
+        outp->parmsp[parmSlot++] = smb_Attributes(scp);
         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
-        outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
-        outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
-        outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
-        parmSlot++;
-        outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
-        parmSlot++;
-        outp->parmsp[parmSlot] = openMode; parmSlot++;
-        outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
-        outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
+        outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
+        outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
+        outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
+        outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
+        outp->parmsp[parmSlot++] = openMode;
+        outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
+        outp->parmsp[parmSlot++] = 0;   /* IPC junk */
     }   
     /* and the final "always present" stuff */
-    outp->parmsp[parmSlot] = openAction; parmSlot++;
+    outp->parmsp[parmSlot++] = openAction;
     /* next write out the "unique" ID */
-    outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
-    outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
-    outp->parmsp[parmSlot] = 0; parmSlot++;
+    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
+    outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
+    outp->parmsp[parmSlot++] = 0; 
     if (returnEALength) {
-        outp->parmsp[parmSlot] = 0; parmSlot++;
-        outp->parmsp[parmSlot] = 0; parmSlot++;
+        outp->parmsp[parmSlot++] = 0; 
+        outp->parmsp[parmSlot++] = 0; 
     }   
     lock_ReleaseMutex(&scp->mx);
     outp->totalData = 0;               /* total # of data bytes */
@@ -2323,16 +2463,16 @@ 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;
 }
 
 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
@@ -2340,24 +2480,38 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
     smb_tran2Packet_t *outp;
     smb_tran2QFSInfo_t qi;
     int responseSize;
-    osi_hyper_t temp;
-    static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
+    static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
         
     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
 
     switch (p->parmsp[0]) {
-    case 1: responseSize = sizeof(qi.u.allocInfo); break;
-    case 2: responseSize = sizeof(qi.u.volumeInfo); break;
-    case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
-    case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
-    case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
-    case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
-    default: return CM_ERROR_INVAL;
+    case SMB_INFO_ALLOCATION: 
+       responseSize = sizeof(qi.u.allocInfo); 
+       break;
+    case SMB_INFO_VOLUME: 
+       responseSize = sizeof(qi.u.volumeInfo); 
+       break;
+    case SMB_QUERY_FS_VOLUME_INFO: 
+       responseSize = sizeof(qi.u.FSvolumeInfo); 
+       break;
+    case SMB_QUERY_FS_SIZE_INFO: 
+       responseSize = sizeof(qi.u.FSsizeInfo); 
+       break;
+    case SMB_QUERY_FS_DEVICE_INFO: 
+       responseSize = sizeof(qi.u.FSdeviceInfo); 
+       break;
+    case SMB_QUERY_FS_ATTRIBUTE_INFO: 
+       responseSize = sizeof(qi.u.FSattributeInfo); 
+       break;
+    case SMB_INFO_UNIX:        /* CIFS Unix Info */
+    case SMB_INFO_MACOS:       /* Mac FS Info */
+    default: 
+       return CM_ERROR_BADOP;
     }
 
     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
     switch (p->parmsp[0]) {
-    case 1:
+    case SMB_INFO_ALLOCATION: 
         /* alloc info */
         qi.u.allocInfo.FSID = 0;
         qi.u.allocInfo.sectorsPerAllocUnit = 1;
@@ -2366,7 +2520,7 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         qi.u.allocInfo.bytesPerSector = 1024;
         break;
 
-    case 2:
+    case SMB_INFO_VOLUME: 
         /* volume info */
         qi.u.volumeInfo.vsn = 1234;
         qi.u.volumeInfo.vnCount = 4;
@@ -2375,45 +2529,45 @@ long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
         memcpy(qi.u.volumeInfo.label, "AFS", 4);
         break;
 
-    case 0x102:
+    case SMB_QUERY_FS_VOLUME_INFO: 
         /* FS volume info */
-        memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
+        memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
         qi.u.FSvolumeInfo.vsn = 1234;
         qi.u.FSvolumeInfo.vnCount = 8;
-        memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
+        memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
         break;
 
-    case 0x103:
+    case SMB_QUERY_FS_SIZE_INFO: 
         /* FS size info */
-        temp.HighPart = 0;
-        temp.LowPart = 0x7fffffff;
-        qi.u.FSsizeInfo.totalAllocUnits = temp;
-        temp.LowPart = 0x3fffffff;
-        qi.u.FSsizeInfo.availAllocUnits = temp;
+        qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
+       qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
+        qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
+       qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
         qi.u.FSsizeInfo.bytesPerSector = 1024;
         break;
 
-    case 0x104:
+    case SMB_QUERY_FS_DEVICE_INFO: 
         /* FS device info */
-        qi.u.FSdeviceInfo.devType = 0; /* don't have a number */
+        qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
         break;
 
-       case 0x105:
+    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_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 = 0x4003;
-        qi.u.FSattributeInfo.maxCompLength = 255;
-        qi.u.FSattributeInfo.FSnameLength = 6;
-        memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
+        qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
+        qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
+        memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
         break;
     }   
         
@@ -2476,10 +2630,20 @@ long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
     spacep = cm_GetSpace();
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
+    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
                      reqp, &dscp);
     cm_FreeSpace(spacep);
-    if (code) return code;
+    if (code) 
+        return code;
+
+#ifdef DFS_SUPPORT
+    if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+        cm_ReleaseSCache(dscp);
+        cm_ReleaseUser(userp);
+        DebugBreak();
+        return CM_ERROR_PATH_NOT_COVERED;
+    }
+#endif /* DFS_SUPPORT */
 
     if (!lastNamep) lastNamep = pathp;
     else lastNamep++;
@@ -2488,8 +2652,7 @@ long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
     rock.shortName = shortName;
     rock.vnode = vnode;
     rock.maskp = lastNamep;
-    code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
-                        reqp, NULL);
+    code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
 
     cm_ReleaseSCache(dscp);
 
@@ -2505,10 +2668,11 @@ long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     smb_tran2Packet_t *outp;
-    time_t dosTime;
+    afs_uint32 dosTime;
     FILETIME ft;
     unsigned short infoLevel;
-    int nbytesRequired;
+    smb_tran2QPathInfo_t qpi;
+    int responseSize;
     unsigned short attributes;
     unsigned long extAttributes;
     char shortName[13];
@@ -2516,8 +2680,10 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     cm_user_t *userp;
     cm_space_t *spacep;
     cm_scache_t *scp, *dscp;
+    int scp_mx_held = 0;
+    int delonclose = 0;
     long code = 0;
-    char *op;
+    char *pathp;
     char *tidPathp;
     char *lastComp;
     cm_req_t req;
@@ -2525,35 +2691,50 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     cm_InitReq(&req);
 
     infoLevel = p->parmsp[0];
-    if (infoLevel == 6) nbytesRequired = 0;
-    else if (infoLevel == 1) nbytesRequired = 22;
-    else if (infoLevel == 2) nbytesRequired = 26;
-    else if (infoLevel == 0x101) nbytesRequired = 40;
-    else if (infoLevel == 0x102) nbytesRequired = 24;
-    else if (infoLevel == 0x103) nbytesRequired = 4;
-    else if (infoLevel == 0x108) nbytesRequired = 30;
+    if (infoLevel == SMB_INFO_IS_NAME_VALID) 
+        responseSize = 0;
+    else if (infoLevel == SMB_INFO_STANDARD) 
+        responseSize = sizeof(qpi.u.QPstandardInfo);
+    else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
+        responseSize = sizeof(qpi.u.QPeaSizeInfo);
+    else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
+        responseSize = sizeof(qpi.u.QPfileBasicInfo);
+    else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
+       responseSize = sizeof(qpi.u.QPfileStandardInfo);
+    else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
+        responseSize = sizeof(qpi.u.QPfileEaInfo);
+    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
+        responseSize = sizeof(qpi.u.QPfileNameInfo);
+    else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
+        responseSize = sizeof(qpi.u.QPfileAllInfo);
+    else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
+        responseSize = sizeof(qpi.u.QPfileAltNameInfo);
     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);
         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, (char *)(&p->parmsp[3])));
+              osi_LogSaveString(smb_logp, pathp));
 
-    outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
+    outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
 
     if (infoLevel > 0x100)
         outp->totalParms = 2;
     else
         outp->totalParms = 0;
-    outp->totalData = nbytesRequired;
+    outp->totalData = responseSize;
         
     /* now, if we're at infoLevel 6, we're only being asked to check
      * the syntax, so we just OK things now.  In particular, we're *not*
      * being asked to verify anything about the state of any parent dirs.
      */
-    if (infoLevel == 6) {
+    if (infoLevel == SMB_INFO_IS_NAME_VALID) {
         smb_SendTran2Packet(vcp, outp, opx);
         smb_FreeTran2Packet(outp);
         return 0;
@@ -2588,26 +2769,36 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
      * yet been evaluated and for directories that haven't yet been
      * fetched.
      */
-    if (infoLevel == 0x101) {
+    if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
         spacep = cm_GetSpace();
-        smb_StripLastComponent(spacep->data, &lastComp,
-                                (char *)(&p->parmsp[3]));
+        smb_StripLastComponent(spacep->data, &lastComp, pathp);
+#ifndef SPECIAL_FOLDERS
         /* Make sure that lastComp is not NULL */
         if (lastComp) {
-            if (strcmp(lastComp, "\\desktop.ini") == 0) {
-                code = cm_NameI(cm_rootSCachep, spacep->data,
+            if (stricmp(lastComp, "\\desktop.ini") == 0) {
+                code = cm_NameI(cm_data.rootSCachep, spacep->data,
                                  CM_FLAG_CASEFOLD
                                  | CM_FLAG_DIRSEARCH
                                  | CM_FLAG_FOLLOW,
                                  userp, tidPathp, &req, &dscp);
                 if (code == 0) {
-                    if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
-                         && !dscp->mountRootFidp)
+#ifdef DFS_SUPPORT
+                    if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+                        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                        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)
+                        if (bp) {
                             buf_Release(bp);
+                            bp = NULL;
+                        }
                         else
                             code = CM_ERROR_NOSUCHFILE;
                     }
@@ -2622,11 +2813,13 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 }
             }
         }
+#endif /* SPECIAL_FOLDERS */
+
         cm_FreeSpace(spacep);
     }
 
     /* now do namei and stat, and copy out the info */
-    code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
+    code = cm_NameI(cm_data.rootSCachep, pathp,
                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
 
     if (code) {
@@ -2636,194 +2829,362 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return 0;
     }
 
+#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) || 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 */
+
     lock_ObtainMutex(&scp->mx);
+    scp_mx_held = 1;
     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);
         
     /* now we have the status in the cache entry, and everything is locked.
      * Marshall the output data.
      */
-    op = outp->datap;
     /* for info level 108, figure out short name */
-    if (infoLevel == 0x108) {
-        code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
+    if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
+        code = cm_GetShortName(pathp, userp, &req,
                                 tidPathp, scp->fid.vnode, shortName,
                                 (size_t *) &len);
         if (code) {
             goto done;
         }
 
-        op = outp->datap;
-        *((u_long *)op) = len * 2; op += 4;
-        mbstowcs((unsigned short *)op, shortName, len);
-        op += (len * 2);
+       qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
+        mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
+
+        goto done;
+    }
+    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+       len = strlen(lastComp);
+       qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
+        mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
 
         goto done;
     }
-    if (infoLevel == 1 || infoLevel == 2) {
+    else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
-        *((u_long *)op) = dosTime; op += 4;    /* creation time */
-        *((u_long *)op) = dosTime; op += 4;    /* access time */
-        *((u_long *)op) = dosTime; op += 4;    /* write time */
-        *((u_long *)op) = scp->length.LowPart; op += 4;        /* length */
-        *((u_long *)op) = scp->length.LowPart; op += 4;        /* alloc size */
+       qpi.u.QPstandardInfo.creationDateTime = dosTime;
+       qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
+       qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
+        qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
+        qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
         attributes = smb_Attributes(scp);
-        *((u_short *)op) = attributes; op += 2;        /* attributes */
+        qpi.u.QPstandardInfo.attributes = attributes;
+       qpi.u.QPstandardInfo.eaSize = 0;
     }
-    else if (infoLevel == 0x101) {
+    else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
-        *((FILETIME *)op) = ft; op += 8;       /* creation time */
-        *((FILETIME *)op) = ft; op += 8;       /* last access time */
-        *((FILETIME *)op) = ft; op += 8;       /* last write time */
-        *((FILETIME *)op) = ft; op += 8;       /* last change time */
+        qpi.u.QPfileBasicInfo.creationTime = ft;
+        qpi.u.QPfileBasicInfo.lastAccessTime = ft;
+        qpi.u.QPfileBasicInfo.lastWriteTime = ft;
+        qpi.u.QPfileBasicInfo.changeTime = ft;
         extAttributes = smb_ExtAttributes(scp);
-        *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
-        *((u_long *)op) = 0; op += 4;  /* don't know what this is */
-    }
-    else if (infoLevel == 0x102) {
-        *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
-        *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
-        *((u_long *)op) = scp->linkCount; op += 4;
-        *op++ = 0;
-        *op++ = 0;
-        *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
-        *op++ = 0;
+       qpi.u.QPfileBasicInfo.attributes = extAttributes;
+       qpi.u.QPfileBasicInfo.reserved = 0;
+    }
+    else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
+       smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
+
+        qpi.u.QPfileStandardInfo.allocationSize = scp->length;
+        qpi.u.QPfileStandardInfo.endOfFile = scp->length;
+        qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
+        qpi.u.QPfileStandardInfo.directory = 
+           ((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_ReleaseMutex(&scp->mx);
+           scp_mx_held = 0;
+           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 == 0x103) {
-        memset(op, 0, 4); op += 4;     /* EA size */
+    else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
+        qpi.u.QPfileEaInfo.eaSize = 0;
     }
-
-    /* now, if we are being asked about extended attrs, return a 0 size */
-    if (infoLevel == 2) {
-        *((u_long *)op) = 0; op += 4;
+    else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
+        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        qpi.u.QPfileAllInfo.creationTime = ft;
+        qpi.u.QPfileAllInfo.lastAccessTime = ft;
+        qpi.u.QPfileAllInfo.lastWriteTime = ft;
+        qpi.u.QPfileAllInfo.changeTime = ft;
+        extAttributes = smb_ExtAttributes(scp);
+       qpi.u.QPfileAllInfo.attributes = extAttributes;
+        qpi.u.QPfileAllInfo.allocationSize = scp->length;
+        qpi.u.QPfileAllInfo.endOfFile = scp->length;
+        qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
+        qpi.u.QPfileAllInfo.deletePending = 0;
+        qpi.u.QPfileAllInfo.directory = 
+           ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+             scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+             scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
+       qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
+       qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
+       qpi.u.QPfileAllInfo.eaSize = 0;
+       qpi.u.QPfileAllInfo.accessFlags = 0;
+       qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
+       qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
+       qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
+       qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
+       qpi.u.QPfileAllInfo.mode = 0;
+       qpi.u.QPfileAllInfo.alignmentRequirement = 0;
+       len = strlen(lastComp);
+       qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
+        mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
     }
 
-
     /* send and free the packets */
   done:
-    lock_ReleaseMutex(&scp->mx);
+    if (scp_mx_held)
+       lock_ReleaseMutex(&scp->mx);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
-    if (code == 0) 
-        smb_SendTran2Packet(vcp, outp, opx);
-    else 
+    if (code == 0) {
+       memcpy(outp->datap, &qpi, responseSize);
+       smb_SendTran2Packet(vcp, outp, opx);
+    } else {
         smb_SendTran2Error(vcp, p, opx, code);
+    }
     smb_FreeTran2Packet(outp);
 
     return 0;
 }
 
-long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
+#if 0
     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
     return CM_ERROR_BADOP;
-}
-
-long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
-{
-    smb_tran2Packet_t *outp;
-    FILETIME ft;
-    unsigned long attributes;
+#else
+    long code = 0;
+    smb_fid_t *fidp;
     unsigned short infoLevel;
-    int nbytesRequired;
-    unsigned short fid;
+    char * pathp;
+    smb_tran2Packet_t *outp;
+    smb_tran2QPathInfo_t *spi;
     cm_user_t *userp;
-    smb_fid_t *fidp;
-    cm_scache_t *scp;
-    char *op;
-    long code = 0;
+    cm_scache_t *scp, *dscp;
     cm_req_t req;
+    cm_space_t *spacep;
+    char *tidPathp;
+    char *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;
-    }
-
-    infoLevel = p->parmsp[1];
-    if (infoLevel == 0x101) nbytesRequired = 40;
-    else if (infoLevel == 0x102) nbytesRequired = 24;
-    else if (infoLevel == 0x103) nbytesRequired = 4;
-    else if (infoLevel == 0x104) nbytesRequired = 6;
-    else {
+    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);
+        smb_SendTran2Error(vcp, p, opx, 
+                           infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
         return 0;
     }
-    osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
 
-    outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
-
-    if (infoLevel > 0x100)
-        outp->totalParms = 2;
-    else
-        outp->totalParms = 0;
-    outp->totalData = nbytesRequired;
+    pathp = (char *)(&p->parmsp[3]);
+    if (smb_StoreAnsiFilenames)
+       OemToChar(pathp,pathp);
+    osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
+              osi_LogSaveString(smb_logp, pathp));
 
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
-       osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
+       osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
        code = CM_ERROR_BADSMB;
        goto done;
     }   
 
-    scp = fidp->scp;
-    lock_ObtainMutex(&scp->mx);
-    code = cm_SyncOp(scp, NULL, userp, &req, 0,
-                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) 
-        goto done;
+    code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
+    if (code == CM_ERROR_TIDIPC) {
+        /* Attempt to use a TID allocated for IPC.  The client
+         * is probably looking for DCE RPC end points which we
+         * don't support OR it could be looking to make a DFS
+         * referral request. 
+         */
+        osi_Log0(smb_logp, "Tran2Open received IPC TID");
+        cm_ReleaseUser(userp);
+        return CM_ERROR_NOSUCHPATH;
+    }
 
-    /* now we have the status in the cache entry, and everything is locked.
-     * Marshall the output data.
-     */
-    op = outp->datap;
-    if (infoLevel == 0x101) {
-        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
-        *((FILETIME *)op) = ft; op += 8;       /* creation time */
-        *((FILETIME *)op) = ft; op += 8;       /* last access time */
-        *((FILETIME *)op) = ft; op += 8;       /* last write time */
-        *((FILETIME *)op) = ft; op += 8;       /* last change time */
-        attributes = smb_ExtAttributes(scp);
-        *((u_long *)op) = attributes; op += 4;
-        *((u_long *)op) = 0; op += 4;
-    }
-    else if (infoLevel == 0x102) {
-        *((LARGE_INTEGER *)op) = scp->length; op += 8; /* alloc size */
-        *((LARGE_INTEGER *)op) = scp->length; op += 8; /* EOF */
-        *((u_long *)op) = scp->linkCount; op += 4;
-        *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
-        *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
-        *op++ = 0;
-        *op++ = 0;
-    }
-    else if (infoLevel == 0x103) {
-        *((u_long *)op) = 0; op += 4;
-    }
-    else if (infoLevel == 0x104) {
-        unsigned long len;
-        char *name;
+    /*
+    * 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->data, &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,
+                                 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->data);
+                        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 */
 
-        if (fidp->NTopen_wholepathp)
-            name = fidp->NTopen_wholepathp;
-        else
-            name = "\\";       /* probably can't happen */
-        len = strlen(name);
-        outp->totalData = (len*2) + 4; /* this is actually what we want to return */
-        *((u_long *)op) = len * 2; op += 4;
-        mbstowcs((unsigned short *)op, name, len); op += (len * 2);
+        cm_FreeSpace(spacep);
     }
 
-    /* send and free the packets */
+    /* 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_ObtainMutex(&scp->mx);
+        code = cm_SyncOp(scp, NULL, userp, &req, 0,
+                          CM_SCACHESYNC_GETSTATUS
+                         | CM_SCACHESYNC_NEEDCALLBACK);
+        if (code) {
+           lock_ReleaseMutex(&scp->mx);
+            goto done;
+        }
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+       lock_ReleaseMutex(&scp->mx);
+       lock_ObtainMutex(&fidp->mx);
+       lock_ObtainMutex(&scp->mx);
+
+        /* prepare for setattr call */
+        attr.mask = CM_ATTRMASK_LENGTH;
+        attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
+        attr.length.HighPart = 0;
+
+       if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
+           smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
+            attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
+            fidp->flags |= SMB_FID_MTIMESETDONE;
+        }
+               
+        if (spi->u.QPstandardInfo.attributes != 0) {
+            if ((scp->unixModeBits & 0222)
+                 && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
+                /* make a writable file read-only */
+                attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+                attr.unixModeBits = scp->unixModeBits & ~0222;
+            }
+            else if ((scp->unixModeBits & 0222) == 0
+                      && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
+                /* make a read-only file writable */
+                attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
+                attr.unixModeBits = scp->unixModeBits | 0222;
+            }
+        }
+        lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseMutex(&fidp->mx);
+
+        /* call setattr */
+        if (attr.mask)
+            code = cm_SetAttr(scp, &attr, userp, &req);
+        else
+            code = 0;
+    }               
+    else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
+       /* we don't support EAs */
+       code = CM_ERROR_EAS_NOT_SUPPORTED;
+    }       
+
   done:
-    lock_ReleaseMutex(&scp->mx);
+    cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
     if (code == 0) 
@@ -2833,17 +3194,158 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     smb_FreeTran2Packet(outp);
 
     return 0;
+#endif
+}
+
+long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
+{
+    smb_tran2Packet_t *outp;
+    FILETIME ft;
+    unsigned long attributes;
+    unsigned short infoLevel;
+    int responseSize;
+    unsigned short fid;
+    int delonclose = 0;
+    cm_user_t *userp;
+    smb_fid_t *fidp;
+    cm_scache_t *scp;
+    smb_tran2QFileInfo_t qfi;
+    long code = 0;
+    cm_req_t req;
+
+    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;
+    }
+
+    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);
+    else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
+        responseSize = sizeof(qfi.u.QFstandardInfo);
+    else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
+        responseSize = sizeof(qfi.u.QFeaInfo);
+    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
+        responseSize = sizeof(qfi.u.QFfileNameInfo);
+    else {
+        osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
+                  p->opcode, infoLevel);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
+        smb_ReleaseFID(fidp);
+        return 0;
+    }
+    osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
+
+    outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
+
+    if (infoLevel > 0x100)
+        outp->totalParms = 2;
+    else
+        outp->totalParms = 0;
+    outp->totalData = responseSize;
+
+    userp = smb_GetTran2User(vcp, p);
+    if (!userp) {
+       osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
+       code = CM_ERROR_BADSMB;
+       goto done;
+    }   
+
+    lock_ObtainMutex(&fidp->mx);
+    delonclose = fidp->flags & SMB_FID_DELONCLOSE;
+    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);
+    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);
+
+    /* now we have the status in the cache entry, and everything is locked.
+     * Marshall the output data.
+     */
+    if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
+        smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
+        qfi.u.QFbasicInfo.creationTime = ft;
+        qfi.u.QFbasicInfo.lastAccessTime = ft;
+        qfi.u.QFbasicInfo.lastWriteTime = ft;
+        qfi.u.QFbasicInfo.lastChangeTime = ft;
+        attributes = smb_ExtAttributes(scp);
+        qfi.u.QFbasicInfo.attributes = attributes;
+    }
+    else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
+       qfi.u.QFstandardInfo.allocationSize = scp->length;
+       qfi.u.QFstandardInfo.endOfFile = scp->length;
+        qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
+        qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
+        qfi.u.QFstandardInfo.directory = 
+           ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+             scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+             scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
+    }
+    else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
+        qfi.u.QFeaInfo.eaSize = 0;
+    }
+    else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
+        unsigned long len;
+        char *name;
+
+       lock_ReleaseMutex(&scp->mx);
+       lock_ObtainMutex(&fidp->mx);
+       lock_ObtainMutex(&scp->mx);
+        if (fidp->NTopen_wholepathp)
+            name = fidp->NTopen_wholepathp;
+        else
+            name = "\\";       /* probably can't happen */
+       lock_ReleaseMutex(&fidp->mx);
+        len = (unsigned long)strlen(name);
+        outp->totalData = ((len+1)*2) + 4;     /* this is actually what we want to return */
+        qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
+        mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
+    }
+
+    /* send and free the packets */
+  done:
+    lock_ReleaseMutex(&scp->mx);
+    cm_ReleaseSCache(scp);
+    cm_ReleaseUser(userp);
+    smb_ReleaseFID(fidp);
+    if (code == 0) {
+       memcpy(outp->datap, &qfi, responseSize);
+        smb_SendTran2Packet(vcp, outp, opx);
+    } else {
+        smb_SendTran2Error(vcp, p, opx, code);
+    }
+    smb_FreeTran2Packet(outp);
+
+    return 0;
 }       
 
-long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
+long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     long code = 0;
     unsigned short fid;
     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);
@@ -2852,35 +3354,54 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     fidp = smb_FindFID(vcp, fid, 0);
 
     if (fidp == NULL) {
-        smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
+        return 0;
+    }
+
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
         return 0;
     }
 
     infoLevel = p->parmsp[1];
-    osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
-    if (infoLevel > 0x104 || infoLevel < 0x101) {
+    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, op, CM_ERROR_INVAL);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
         smb_ReleaseFID(fidp);
         return 0;
     }
 
-    if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
-        smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
+    lock_ObtainMutex(&fidp->mx);
+    if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && 
+       !(fidp->flags & SMB_FID_OPENDELETE)) {
+       osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
+                 fidp, fidp->scp, fidp->flags);
+       lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
         return 0;
     }
-    if ((infoLevel == 0x103 || infoLevel == 0x104)
+    if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
+        infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
          && !(fidp->flags & SMB_FID_OPENWRITE)) {
-        smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
+       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);
         return 0;
     }
 
-    osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
+    scp = fidp->scp;
+    osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
 
-    outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
+    outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
 
     outp->totalParms = 2;
     outp->totalData = 0;
@@ -2892,14 +3413,15 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        goto done;
     }   
 
-    scp = fidp->scp;
-
-    if (infoLevel == 0x101) {
+    if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
         FILETIME lastMod;
         unsigned int attribute;
         cm_attr_t attr;
+       smb_tran2QFileInfo_t *sfi;
 
-        /* lock the vnode with a callback; we need the current status
+       sfi = (smb_tran2QFileInfo_t *)p->datap;
+
+       /* 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);
@@ -2907,14 +3429,20 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                           CM_SCACHESYNC_GETSTATUS
                          | CM_SCACHESYNC_NEEDCALLBACK);
         if (code) {
-            lock_ReleaseMutex(&scp->mx);
+           lock_ReleaseMutex(&scp->mx);
             goto done;
-        }
+       }
+
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
+       lock_ReleaseMutex(&scp->mx);
+       lock_ObtainMutex(&fidp->mx);
+       lock_ObtainMutex(&scp->mx);
 
         /* prepare for setattr call */
         attr.mask = 0;
 
-        lastMod = *((FILETIME *)(p->datap + 16));
+        lastMod = sfi->u.QFbasicInfo.lastWriteTime;
         /* when called as result of move a b, lastMod is (-1, -1). 
          * If the check for -1 is not present, timestamp
          * of the resulting file will be 1969 (-1)
@@ -2922,63 +3450,76 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
-            smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
-                                             &lastMod);
+            smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
             fidp->flags |= SMB_FID_MTIMESETDONE;
         }
                
-        attribute = *((u_long *)(p->datap + 32));
+        attribute = sfi->u.QFbasicInfo.attributes;
         if (attribute != 0) {
             if ((scp->unixModeBits & 0222)
-                 && (attribute & 1) != 0) {
+                 && (attribute & SMB_ATTR_READONLY) != 0) {
                 /* make a writable file read-only */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
                 attr.unixModeBits = scp->unixModeBits & ~0222;
             }
             else if ((scp->unixModeBits & 0222) == 0
-                      && (attribute & 1) == 0) {
+                      && (attribute & SMB_ATTR_READONLY) == 0) {
                 /* make a read-only file writable */
                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
                 attr.unixModeBits = scp->unixModeBits | 0222;
             }
         }
         lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseMutex(&fidp->mx);
 
         /* call setattr */
         if (attr.mask)
             code = cm_SetAttr(scp, &attr, userp, &req);
         else
             code = 0;
-    }               
-    else if (infoLevel == 0x103 || infoLevel == 0x104) {
-        LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
-        cm_attr_t attr;
-
-        attr.mask = CM_ATTRMASK_LENGTH;
-        attr.length.LowPart = size.LowPart;
-        attr.length.HighPart = size.HighPart;
-        code = cm_SetAttr(scp, &attr, userp, &req);
-    }       
-    else if (infoLevel == 0x102) {
-        if (*((char *)(p->datap))) {
+    }
+    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);
-            if (code == 0)          
+            if (code == 0) {
+               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 {  
             code = 0;
+           lock_ObtainMutex(&fidp->mx);
             fidp->flags &= ~SMB_FID_DELONCLOSE;
+           lock_ReleaseMutex(&fidp->mx);
         }
     }       
+    else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
+            infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
+        LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
+        cm_attr_t attr;
+
+        attr.mask = CM_ATTRMASK_LENGTH;
+        attr.length.LowPart = size.LowPart;
+        attr.length.HighPart = size.HighPart;
+        code = cm_SetAttr(scp, &attr, userp, &req);
+    }       
 
   done:
+    cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
     if (code == 0) 
-        smb_SendTran2Packet(vcp, outp, op);
+        smb_SendTran2Packet(vcp, outp, opx);
     else 
-        smb_SendTran2Error(vcp, p, op, code);
+        smb_SendTran2Error(vcp, p, opx, code);
     smb_FreeTran2Packet(outp);
 
     return 0;
@@ -3026,53 +3567,298 @@ smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *
     return CM_ERROR_BADOP;
 }
 
+struct smb_v2_referral {
+    USHORT ServerType;
+    USHORT ReferralFlags;
+    ULONG  Proximity;
+    ULONG  TimeToLive;
+    USHORT DfsPathOffset;
+    USHORT DfsAlternativePathOffset;
+    USHORT NetworkAddressOffset;
+};
+
 long 
-smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
+smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 {
-    osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
+    /* This is a UNICODE only request (bit15 of Flags2) */
+    /* The TID must be IPC$ */
+
+    /* The documentation for the Flags response field is contradictory */
+
+    /* Use Version 1 Referral Element Format */
+    /* ServerType = 0; indicates the next server should be queried for the file */
+    /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
+    /* Node = UnicodeString of UNC path of the next share name */
+#ifdef DFS_SUPPORT
+    long code = 0;
+    int maxReferralLevel = 0;
+    char requestFileName[1024] = "";
+    char referralPath[1024] = "";
+    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, refLen;
+    int idx;
+
+    cm_InitReq(&req);
+
+    maxReferralLevel = p->parmsp[0];
+
+    GetCPInfo(CP_ACP, &CodePageInfo);
+    WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1, 
+                        requestFileName, 1024, NULL, NULL);
+
+    osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
+             maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
+
+    nbnLen = strlen(cm_NetbiosName);
+    reqLen = strlen(requestFileName);
+
+    if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
+        !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
+        requestFileName[nbnLen+1] == '\\') 
+    {
+        int found = 0;
+
+        if (!_strnicmp("all",&requestFileName[nbnLen+2],3) ||
+             !_strnicmp("*.",&requestFileName[nbnLen+2],2)) 
+        {
+            found = 1;
+            strcpy(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;
+                strcpy(referralPath, requestFileName);
+                refLen = reqLen;
+            } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
+                char temp[1024];
+                char pathName[1024];
+                char *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);
+
+                strcpy(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 = nbnLen+2 + strlen(pathName) + 1 + strlen(lastComponent);
+
+                    strcpy(referralPath, &scp->mountPointStringp[strlen("msdfs:")]);
+                    refLen = strlen(referralPath);
+                    found = 1;
+                }
+            } else {
+                char shareName[MAX_PATH + 1];
+                char *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, "", 
+                                    CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                                    userp, p, &req, &scp);
+                    free(p);
+
+                    if (code == 0) {
+                        found = 1;
+                        strcpy(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++] = 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<=refLen; i++ )
+                sp[i+idx] = referralPath[i];
+#endif
+        } 
+    } else {
+        code = CM_ERROR_NOSUCHPATH;
+    }
+         
+  done:
+    if (dscp)
+        cm_ReleaseSCache(dscp);
+    if (scp)
+        cm_ReleaseSCache(scp);
+    if (userp)
+        cm_ReleaseUser(userp);
+    if (code == 0) 
+        smb_SendTran2Packet(vcp, outp, op);
+    else 
+        smb_SendTran2Error(vcp, p, op, code);
+    if (outp)
+        smb_FreeTran2Packet(outp);
+    return 0;
+#else /* DFS_SUPPORT */
+    osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
     return CM_ERROR_BADOP;
+#endif /* DFS_SUPPORT */
 }
 
 long 
 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
 {
+    /* This is a UNICODE only request (bit15 of Flags2) */
+
+    /* There is nothing we can do about this operation.  The client is going to
+     * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
+     * Unfortunately, there is really nothing we can do about it other then log it 
+     * somewhere.  Even then I don't think there is anything for us to do.
+     * So let's return an error value.
+     */
+
     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
     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, 
+                          char * tidPathp, char * 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;
-    time_t dosTime;
+    afs_uint32 dosTime;
     FILETIME ft;
     int shortTemp;
     unsigned short attr;
     unsigned long lattr;
     smb_dirListPatch_t *patchp;
     smb_dirListPatch_t *npatchp;
-        
+    afs_uint32 rights;
+    afs_int32 mustFake = 0;
+    char path[AFSPATHMAX];
+
+    code = cm_FindACLCache(dscp, userp, &rights);
+    if (code == 0 && !(rights & PRSFS_READ))
+        mustFake = 1;
+    else if (code == -1) {
+        lock_ObtainMutex(&dscp->mx);
+        code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseMutex(&dscp->mx);
+        if (code == CM_ERROR_NOACCESS) {
+            mustFake = 1;
+            code = 0;
+        }
+    }
+    if (code)
+        return code;
+
     for(patchp = *dirPatchespp; patchp; patchp =
          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
-               code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
-        if (code) continue;
+        snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", 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_ObtainMutex(&scp->mx);
-        code = cm_SyncOp(scp, NULL, userp, reqp, 0,
-                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        if (code) { 
+        if (mustFake == 0)
+            code = cm_SyncOp(scp, NULL, userp, reqp, 0,
+                             CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        if (mustFake || code) { 
             lock_ReleaseMutex(&scp->mx);
-            cm_ReleaseSCache(scp);
 
             dptr = patchp->dptr;
 
             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
                errors in the client. */
-            if (infoLevel >= 0x101) {
+            if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
                 /* 1969-12-31 23:59:59 +00 */
                 ft.dwHighDateTime = 0x19DB200;
                 ft.dwLowDateTime = 0x5BB78980;
@@ -3093,9 +3879,30 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
                 *((FILETIME *)dptr) = ft;
                 dptr += 24;
 
+                switch (scp->fileType) {
+                case CM_SCACHETYPE_DIRECTORY:
+                case CM_SCACHETYPE_MOUNTPOINT:
+                case CM_SCACHETYPE_SYMLINK:
+                case CM_SCACHETYPE_INVALID:
+                    *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
+                    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))
+                        *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
+                    else
+                        *((u_long *)dptr) = SMB_ATTR_NORMAL;
+                        
+                }
                 /* merge in hidden attribute */
                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
-                    *((u_long *)dptr) = SMB_ATTR_HIDDEN;
+                    *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
                 }
                 dptr += 4;
             } else {
@@ -3132,21 +3939,39 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
                 *((u_short *)dptr) = shortTemp;
                 dptr += 10;
 
+                /* set the attribute */
+                switch (scp->fileType) {
+                case CM_SCACHETYPE_DIRECTORY:
+                case CM_SCACHETYPE_MOUNTPOINT:
+                case CM_SCACHETYPE_SYMLINK:
+                case CM_SCACHETYPE_INVALID:
+                    attr = SMB_ATTR_DIRECTORY;
+                default:
+                    attr = 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;
+                    attr |= SMB_ATTR_HIDDEN;
                 }       
+                *dptr++ = attr & 0xff;
+                *dptr++ = (attr >> 8) & 0xff;
             }
+            
+            cm_ReleaseSCache(scp);
             continue;
         }
-                
+        
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
         /* now watch for a symlink */
         code = 0;
         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
             lock_ReleaseMutex(&scp->mx);
+            snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", 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,
@@ -3162,7 +3987,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
 
         dptr = patchp->dptr;
 
-        if (infoLevel >= 0x101) {
+        if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
             /* get filetime */
             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
 
@@ -3190,13 +4015,23 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
 
             /* Copy attributes */
             lattr = smb_ExtAttributes(scp);
+            if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
+                code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+                if (lattr == SMB_ATTR_NORMAL)
+                    lattr = SMB_ATTR_DIRECTORY;
+                else
+                    lattr |= SMB_ATTR_DIRECTORY;
+            }
             /* merge in hidden (dot file) attribute */
-            if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
-                lattr |= SMB_ATTR_HIDDEN;
+            if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
+                if (lattr == SMB_ATTR_NORMAL)
+                    lattr = SMB_ATTR_HIDDEN;
+                else
+                    lattr |= SMB_ATTR_HIDDEN;
+            }
             *((u_long *)dptr) = lattr;
             dptr += 4;
-        }
-        else {
+        } else {
             /* get dos time */
             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
 
@@ -3241,8 +4076,12 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
             /* finally copy out attributes as short */
             attr = smb_Attributes(scp);
             /* merge in hidden (dot file) attribute */
-            if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
-                attr |= SMB_ATTR_HIDDEN;
+            if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
+                if (lattr == SMB_ATTR_NORMAL)
+                    lattr = SMB_ATTR_HIDDEN;
+                else
+                    lattr |= SMB_ATTR_HIDDEN;
+            }
             *dptr++ = attr & 0xff;
             *dptr++ = (attr >> 8) & 0xff;
         }
@@ -3263,7 +4102,6 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
     return code;
 }
 
-#ifndef USE_OLD_MATCHING
 // char table for case insensitive comparison
 char mapCaseTable[256];
 
@@ -3290,7 +4128,7 @@ VOID initUpperCaseTable(VOID)
 // BOOL : TRUE/FALSE (match/mistmatch)
 
 BOOL 
-szWildCardMatchFileName(PSZ pattern, PSZ name) 
+szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
 {
     PSZ pename;         // points to the last 'name' character
     PSZ p;
@@ -3298,32 +4136,37 @@ szWildCardMatchFileName(PSZ pattern, PSZ name)
     while (*name) {
         switch (*pattern) {
         case '?':
-            if (*name == '.') 
-                return FALSE;
-            ++pattern, ++name;
+           ++pattern;
+            if (*name == '.')
+               continue;
+            ++name;
             break;
          case '*':
             ++pattern;
             if (*pattern == '\0')
                 return TRUE;
             for (p = pename; p >= name; --p) {
-                if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
-                     szWildCardMatchFileName(pattern + 1, p + 1))
+                if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
+                     !casefold && (*p == *pattern)) &&
+                     szWildCardMatchFileName(pattern + 1, p + 1, casefold))
                     return TRUE;
             } /* endfor */
             return FALSE;
         default:
-            if (mapCaseTable[*name] != mapCaseTable[*pattern]) 
+            if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
+                (!casefold && *name != *pattern))
                 return FALSE;
             ++pattern, ++name;
             break;
         } /* endswitch */
     } /* endwhile */ 
 
-    if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
-        return TRUE;
-    else 
-        return FALSE;
+    /* if all we have left are wildcards, then we match */
+    for (;*pattern; pattern++) {
+       if (*pattern != '*' && *pattern != '?')
+           return FALSE;
+    }
+    return TRUE;
 }
 
 /* do a case-folding search of the star name mask with the name in namep.
@@ -3332,12 +4175,14 @@ szWildCardMatchFileName(PSZ pattern, PSZ name)
 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
 {
     char * newmask;
-    int    i, j, star, qmark, retval;
+    int    i, j, star, qmark, casefold, retval;
 
     /* make sure we only match 8.3 names, if requested */
     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
         return 0;
     
+    casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
+
     /* optimize the pattern:
      * if there is a mixture of '?' and '*',
      * for example  the sequence "*?*?*?*"
@@ -3374,163 +4219,450 @@ int smb_V3MatchMask(char *namep, char *maskp, int flags)
     }
     newmask[j++] = '\0';
 
-    retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
+    retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
 
     free(newmask);
     return retval;
 }
 
-#else /* USE_OLD_MATCHING */
-/* do a case-folding search of the star name mask with the name in namep.
- * Return 1 if we match, otherwise 0.
+
+/* smb_ReceiveTran2SearchDir implements both 
+ * Tran2_Find_First and Tran2_Find_Next
  */
-int smb_V3MatchMask(char *namep, char *maskp, int flags)
+#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.
+   */
+long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
-    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;
+    int attribute;
+    long nextCookie;
+    long code = 0, code2 = 0;
+    char *pathp = 0;
+    int maxCount;
+    smb_dirListPatch_t *dirListPatchesp;
+    smb_dirListPatch_t *curPatchp;
+    long orbytes;                      /* # of bytes in this output record */
+    long ohbytes;                      /* # of bytes, except file name */
+    long onbytes;                      /* # of bytes in name, incl. term. null */
+    cm_scache_t *scp = NULL;
+    cm_scache_t *targetscp = NULL;
+    cm_user_t *userp = NULL;
+    char *op;                          /* output data ptr */
+    char *origOp;                      /* original value of op */
+    cm_space_t *spacep;                        /* for pathname buffer */
+    long maxReturnData;                        /* max # of return data */
+    long maxReturnParms;               /* max # of return parms */
+    long bytesInBuffer;                        /* # data bytes in the output buffer */
+    char *maskp;                       /* mask part of path */
+    int infoLevel;
+    int searchFlags;
+    int eos;
+    smb_tran2Packet_t *outp;           /* response packet */
+    char *tidPathp = 0;
+    int align;
+    char shortName[13];                        /* 8.3 name if needed */
+    int NeedShortName;
+    char *shortNameEnd;
+    cm_dirEntry_t * dep = NULL;
+    cm_req_t req;
+    char * s;
 
-    /* make sure we only match 8.3 names, if requested */
-    req8dot3 = (flags & CM_FLAG_8DOT3);
-    if (req8dot3 && !cm_Is8Dot3(namep)) 
+    cm_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 = ((char *) p->parmsp) + 12; /* points to path */
+    nextCookie = 0;
+    maskp = strrchr(pathp, '\\');
+    if (maskp == NULL) 
+       maskp = pathp;
+    else 
+       maskp++;        /* skip over backslash */
+    /* track if this is likely to match a lot of entries */
+
+    osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
+            osi_LogSaveString(smb_logp, pathp),
+            osi_LogSaveString(smb_logp, maskp));
+
+    switch ( infoLevel ) {
+    case SMB_INFO_STANDARD:
+       s = "InfoStandard";
+       break;
+    case SMB_INFO_QUERY_EA_SIZE:
+       s = "InfoQueryEaSize";
+       break;
+    case SMB_INFO_QUERY_EAS_FROM_LIST:
+       s = "InfoQueryEasFromList";
+       break;
+    case SMB_FIND_FILE_DIRECTORY_INFO:
+       s = "FindFileDirectoryInfo";
+       break;
+    case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+       s = "FindFileFullDirectoryInfo";
+       break;
+    case SMB_FIND_FILE_NAMES_INFO:
+       s = "FindFileNamesInfo";
+       break;
+    case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+       s = "FindFileBothDirectoryInfo";
+       break;
+    default:
+       s = "unknownInfoLevel";
+    }
+
+    osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
+
+    osi_Log4(smb_logp,
+             "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
+             attribute, infoLevel, maxCount, searchFlags);
+    
+    if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+        osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
+        return CM_ERROR_INVAL;
+    }
+
+    if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
+        searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;    /* no resume keys */
+
+    dirListPatchesp = NULL;
+
+    maxReturnData = p->maxReturnData;
+    maxReturnParms = 10;       /* return params for findfirst, which
+                                   is the only one we handle.*/
+
+#ifndef CM_CONFIG_MULTITRAN2RESPONSES
+    if (maxReturnData > 6000) 
+        maxReturnData = 6000;
+#endif /* CM_CONFIG_MULTITRAN2RESPONSES */
+
+    outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
+                                      maxReturnData);
+
+    osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
+             maxCount, osi_LogSaveString(smb_logp, pathp));
+        
+    /* bail out if request looks bad */
+    if (!pathp) {
+        smb_FreeTran2Packet(outp);
+        return CM_ERROR_BADSMB;
+    }
+        
+    userp = smb_GetTran2User(vcp, p);
+    if (!userp) {
+       osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
+       smb_FreeTran2Packet(outp);
+       return CM_ERROR_BADSMB;
+    }
+
+    /* try to get the vnode for the path name next */
+    spacep = cm_GetSpace();
+    smb_StripLastComponent(spacep->data, NULL, pathp);
+    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;
+    }
 
-    /* loop */
-    while (1) {
-        /* Next pattern character */
-        tcp1 = *maskp++;
+    code = cm_NameI(cm_data.rootSCachep, spacep->data,
+                    CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                    userp, tidPathp, &req, &scp);
+    cm_FreeSpace(spacep);
 
-        /* Next name character */
-        tcn1 = *namep;
+    if (code) {
+        cm_ReleaseUser(userp);
+       smb_SendTran2Error(vcp, p, opx, code);
+        smb_FreeTran2Packet(outp);
+        return 0;
+    }
 
-        if (tcp1 == 0) {
-            /* 0 - end of pattern */
-            if (tcn1 == 0)
-                return 1;
-            else
-                return 0;
-        }
-        else if (tcp1 == '.' || tcp1 == '"') {
-            if (sawDot) {
-                if (tcn1 == '.') {
-                    namep++;
-                    continue;
-                } else
-                    return 0;
-            }
-            else {
-                /*
-                 * first dot in pattern;
-                 * must match dot or end of name
-                 */
-                sawDot = 1;
-                if (tcn1 == 0)
-                    continue;
-                else if (tcn1 == '.') {
-                    sawStar = 0;
-                    namep++;
-                    continue;
-                }
-                else
-                    return 0;
-            }
-        }
-        else if (tcp1 == '?') {
-            if (tcn1 == 0 || tcn1 == '.')
-                return 0;
-            namep++;
-            continue;
-        }
-        else if (tcp1 == '>') {
-            if (tcn1 != 0 && tcn1 != '.')
-                namep++;
-            continue;
-        }
-        else if (tcp1 == '*' || tcp1 == '<') {
-            tcp2 = *maskp++;
-            if (tcp2 == 0)
-                return 1;
-            else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
-                while (req8dot3 && tcn1 != '.' && tcn1 != 0)
-                    tcn1 = *++namep;
-                if (tcn1 == 0) {
-                    if (sawDot)
-                        return 0;
-                    else
-                        continue;
-                }
-                else {
-                    namep++;
-                    continue;
-                }
-            }
-            else {
-                /*
-                 * pattern character after '*' is not null or
-                 * period.  If it is '?' or '>', we are not
-                 * going to understand it.  If it is '*' or
-                 * '<', we are going to skip over it.  None of
-                 * these are likely, I hope.
-                 */
-                /* skip over '*' and '<' */
-                while (tcp2 == '*' || tcp2 == '<')
-                    tcp2 = *maskp++;
-
-                /* skip over characters that don't match tcp2 */
-                while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
-                        ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
-                          (!casefold && tcn1 != tcp2)))
-                    tcn1 = *++namep;
-
-                /* No match */
-                if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
-                    return 0;
-
-                /* Remember where we are */
-                sawStar = 1;
-                starMaskp = maskp;
-                starNamep = namep;
-
-                namep++;
-                continue;
-            }
+#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;
+    }
+
+    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_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
+        NeedShortName = 1;
+    } else {
+        NeedShortName = 0;
+    }
+
+    osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
+             htonl(targetscp->fid.vnode),
+             htonl(targetscp->fid.unique),
+             osi_LogSaveString(smb_logp, pathp),
+             NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
+
+    /* Eliminate entries that don't match requested attributes */
+    if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
+        smb_IsDotFile(maskp)) {
+
+        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;
+
+    }
+
+    /* Check if the name will fit */
+    if (infoLevel < 0x101)
+        ohbytes = 23;           /* pre-NT */
+    else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
+        ohbytes = 12;           /* NT names only */
+    else
+        ohbytes = 64;           /* NT */
+
+    if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
+        ohbytes += 26;          /* Short name & length */
+
+    if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
+        ohbytes += 4;           /* if resume key required */
+    }
+
+    if (infoLevel != SMB_INFO_STANDARD
+        && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
+        && infoLevel != SMB_FIND_FILE_NAMES_INFO)
+        ohbytes += 4;           /* EASIZE */
+
+    /* add header to name & term. null */
+    onbytes = strlen(maskp);
+    orbytes = ohbytes + onbytes + 1;
+
+    /* 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, ohbytes);
+
+    if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
+        *(origOp + ohbytes - 1) = (unsigned char) onbytes;
+    else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
+        *((u_long *)(op + 8)) = onbytes;
+    else
+        *((u_long *)(op + 60)) = onbytes;
+    strcpy(origOp+ohbytes, maskp);
+    if (smb_StoreAnsiFilenames)
+        CharToOem(origOp+ohbytes, origOp+ohbytes);
+
+    /* Short name if requested and needed */
+    if (infoLevel == 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);
         }
-        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;
+    }
+
+    /* NextEntryOffset and FileIndex */
+    if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
+        int entryOffset = orbytes + align;
+        *((u_long *)op) = 0;
+        *((u_long *)(op+4)) = 0;
+    }
+
+    if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
+        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;
+
+        if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
+            curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
+        } else {
+            curPatchp->flags = 0;
         }
+
+        curPatchp->fid.cell = targetscp->fid.cell;
+        curPatchp->fid.volume = targetscp->fid.volume;
+        curPatchp->fid.vnode = targetscp->fid.vnode;
+        curPatchp->fid.unique = targetscp->fid.unique;
+
+        /* temp */
+        dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+strlen(maskp));
+        strcpy(dep->name, maskp);
+        dep->fid.vnode = targetscp->fid.vnode;
+        dep->fid.unique = targetscp->fid.unique;
+        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->data, 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);
+    cm_ReleaseSCache(scp);
+    cm_ReleaseSCache(targetscp);
+    cm_ReleaseUser(userp);
+
+    return code;
 }
-#endif /* USE_OLD_MATCHING */
+
 
 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
 {
     int attribute;
     long nextCookie;
     char *tp;
-    long code = 0;
+    long code = 0, code2 = 0;
     char *pathp;
-    cm_dirEntry_t *dep;
+    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 */
@@ -3571,6 +4703,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     int fileType;
     cm_fid_t fid;
     cm_req_t req;
+    char * s;
 
     cm_InitReq(&req);
 
@@ -3581,44 +4714,105 @@ 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);
         nextCookie = 0;
         maskp = strrchr(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
+        dir_enums++;
+
+        dsp = smb_NewDirSearch(1);
+        dsp->attribute = attribute;
+        strcpy(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]);
-        if (!dsp) 
-            return CM_ERROR_BADFD;
-        attribute = dsp->attribute;
         maxCount = p->parmsp[1];
         infoLevel = p->parmsp[2];
+        nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
         searchFlags = p->parmsp[5];
+        if (!dsp) {
+            osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
+                     p->parmsp[0], nextCookie);
+            return CM_ERROR_BADFD;
+        }
+        attribute = dsp->attribute;
         pathp = NULL;
-        nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
         maskp = dsp->mask;
         starPattern = 1;       /* assume, since required a Find Next */
     }
 
+    switch ( infoLevel ) {
+    case SMB_INFO_STANDARD:
+       s = "InfoStandard";
+       break;
+    case SMB_INFO_QUERY_EA_SIZE:
+       s = "InfoQueryEaSize";
+       break;
+    case SMB_INFO_QUERY_EAS_FROM_LIST:
+       s = "InfoQueryEasFromList";
+       break;
+    case SMB_FIND_FILE_DIRECTORY_INFO:
+       s = "FindFileDirectoryInfo";
+       break;
+    case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+       s = "FindFileFullDirectoryInfo";
+       break;
+    case SMB_FIND_FILE_NAMES_INFO:
+       s = "FindFileNamesInfo";
+       break;
+    case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+       s = "FindFileBothDirectoryInfo";
+       break;
+    default:
+       s = "unknownInfoLevel";
+    }
+
+    osi_Log1(smb_logp, "T2 search dir info level: %s", s);
+
     osi_Log4(smb_logp,
-              "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
+              "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
               attribute, infoLevel, maxCount, searchFlags);
 
-    osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
-              p->opcode, nextCookie);
+    osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
+              p->opcode, dsp->cookie, nextCookie);
 
-    if (infoLevel >= 0x101)
-        searchFlags &= ~4;     /* no resume keys */
+    if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+        osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
+        smb_ReleaseDirSearch(dsp);
+        return CM_ERROR_INVAL;
+    }
+
+    if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
+        searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;    /* no resume keys */
 
     dirListPatchesp = NULL;
 
@@ -3636,8 +4830,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
                                       maxReturnData);
 
-    osi_Log1(smb_logp, "T2 receive search dir %s",
-             osi_LogSaveString(smb_logp, pathp));
+    osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
+             maxCount, osi_LogSaveString(smb_logp, pathp));
         
     /* bail out if request looks bad */
     if (p->opcode == 1 && !pathp) {
@@ -3646,12 +4840,12 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return CM_ERROR_BADSMB;
     }
         
-    osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
-             nextCookie, dsp->cookie);
+    osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
+             dsp->cookie, nextCookie, attribute);
 
     userp = smb_GetTran2User(vcp, p);
     if (!userp) {
-       osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
+       osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
        smb_ReleaseDirSearch(dsp);
        smb_FreeTran2Packet(outp);
        return CM_ERROR_BADSMB;
@@ -3661,31 +4855,51 @@ 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 {
+    } else {
         spacep = cm_GetSpace();
         smb_StripLastComponent(spacep->data, NULL, pathp);
         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
         if (code) {
-            lock_ReleaseMutex(&dsp->mx);
             cm_ReleaseUser(userp);
             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
             smb_FreeTran2Packet(outp);
+            lock_ReleaseMutex(&dsp->mx);
             smb_DeleteDirSearch(dsp);
             smb_ReleaseDirSearch(dsp);
             return 0;
         }
-        code = cm_NameI(cm_rootSCachep, spacep->data,
+
+        strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
+        strcpy(dsp->relPath, spacep->data);
+
+        code = cm_NameI(cm_data.rootSCachep, spacep->data,
                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &scp);
         cm_FreeSpace(spacep);
 
         if (code == 0) {
-            if (dsp->scp != 0) 
-                cm_ReleaseSCache(dsp->scp);
+#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);
+                lock_ReleaseMutex(&dsp->mx);
+                smb_DeleteDirSearch(dsp);
+                smb_ReleaseDirSearch(dsp);
+                return 0;
+            }
+#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
@@ -3700,7 +4914,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 dsp->flags |= SMB_DIRSEARCH_BULKST;
             }
             lock_ReleaseMutex(&scp->mx);
-        }       
+        } 
     }
     lock_ReleaseMutex(&dsp->mx);
     if (code) {
@@ -3725,6 +4939,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;
@@ -3739,7 +4955,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     bytesInBuffer = 0;
     while (1) {
         op = origOp;
-        if (searchFlags & 4)
+        if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
             /* skip over resume key */
             op += 4;
 
@@ -3768,6 +4984,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
         /* check if we've passed the dir's EOF */
         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
+            osi_Log0(smb_logp, "T2 search dir passed eof");
             eos = 1;
             break;
         }
@@ -3778,6 +4995,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
          * the dir entry, since we'll need to check its size.
          */
         if (returnedNames >= maxCount) {
+            osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
+                      returnedNames, maxCount);
             break;
         }
 
@@ -3786,7 +5005,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
          * the offset of the buffer we have.  If not, get the buffer.
          */
         thyper.HighPart = curOffset.HighPart;
-        thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
+        thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
             /* wrong buffer */
             if (bufferp) {
@@ -3803,27 +5022,28 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
              * of all of the status info for files in the dir.
              */
             if (starPattern) {
-                smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
-                                           infoLevel, userp,
-                                           &req);
+                code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, 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 = GetCurrentTime();
-                    if (now - req.startTime > 5000) {
+                    DWORD now = GetTickCount();
+                    if (now - req.startTime > RDRtimeout * 1000) {
                         scp->bulkStatProgress = thyper;
                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
                     } else
-                        cm_TryBulkStat(scp, &thyper, userp, &req);
+                        code = cm_TryBulkStat(scp, &thyper, userp, &req);
                 }
             } else {
                 lock_ObtainMutex(&scp->mx);
             }
             lock_ReleaseMutex(&dsp->mx);
-            if (code) 
+            if (code) {
+                osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
                 break;
+            }
 
             bufferOffset = thyper;
 
@@ -3833,14 +5053,26 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                                  PRSFS_LOOKUP,
                                  CM_SCACHESYNC_NEEDCALLBACK
                                  | CM_SCACHESYNC_READ);
-                if (code) break;
-                                
-                if (cm_HaveBuffer(scp, bufferp, 0)) break;
+                if (code) {
+                    osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
+                    break;
+                }
+                       
+               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
+                if (cm_HaveBuffer(scp, bufferp, 0)) {
+                    osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
+                    break;
+                }
 
                 /* otherwise, load the buffer and try again */
                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
                                     &req);
-                if (code) break;
+                if (code) {
+                    osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
+                              scp, bufferp, code);
+                    break;
+                }
             }
             if (code) {
                 buf_Release(bufferp);
@@ -3853,7 +5085,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
          * in; copy it out if it represents a non-deleted entry.
          */
         entryInDir = curOffset.LowPart & (2048-1);
-        entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
+        entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
 
         /* page header will help tell us which entries are free.  Page
          * header can change more often than once per buffer, since
@@ -3861,7 +5093,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
          * a buffer package buffer.
          */
         /* only look intra-buffer */
-        temp = curOffset.LowPart & (buf_bufferSize - 1);
+        temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
         temp &= ~(2048 - 1);   /* turn off intra-page bits */
         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
 
@@ -3891,28 +5123,35 @@ 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 */
+
         /* Need 8.3 name? */
         NeedShortName = 0;
-        if (infoLevel == 0x104
-             && dep->fid.vnode != 0
-             && !cm_Is8Dot3(dep->name)) {
+        if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO && 
+             !cm_Is8Dot3(dep->name)) {
             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) : "");
+
         /* 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 (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
+             (NeedShortName && smb_V3MatchMask(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(dep->name)) {
+                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 */
@@ -3921,11 +5160,15 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 fid.vnode = ntohl(dep->fid.vnode);
                 fid.unique = 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)
-                    goto nextEntry;
+                /* 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;
             }
 
             /* finally check if this name will fit */
@@ -3933,21 +5176,21 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             /* standard dir entry stuff */
             if (infoLevel < 0x101)
                 ohbytes = 23;  /* pre-NT */
-            else if (infoLevel == 0x103)
+            else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
                 ohbytes = 12;  /* NT names only */
             else
                 ohbytes = 64;  /* NT */
 
-            if (infoLevel == 0x104)
+            if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
                 ohbytes += 26; /* Short name & length */
 
-            if (searchFlags & 4) {
+            if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
                 ohbytes += 4;  /* if resume key required */
             }   
 
-            if (infoLevel != 1
-                 && infoLevel != 0x101
-                 && infoLevel != 0x103)
+            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 */
@@ -3956,15 +5199,18 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             /* 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 >= 0x101)
+            if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
                 align = (4 - (orbytes & 3)) & 3;
             else
                 align = 0;
-            if (orbytes + bytesInBuffer + align > maxReturnData)
-                break;
+            if (orbytes + bytesInBuffer + align > maxReturnData) {
+                osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
+                          maxReturnData);
+                break;      
+            }       
 
             /* this is one of the entries to use: it is not deleted
              * and it matches the star pattern we're looking for.
@@ -3973,19 +5219,23 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             /* First zero everything else */
             memset(origOp, 0, ohbytes);
 
-            if (infoLevel <= 0x101)
+            if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
-            else if (infoLevel == 0x103)
+            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);
 
             /* Short name if requested and needed */
-            if (infoLevel == 0x104) {
+            if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
                 if (NeedShortName) {
                     strcpy(op + 70, shortName);
-                    *(op + 68) = shortNameEnd - shortName;
+                    if (smb_StoreAnsiFilenames)
+                        CharToOem(op + 70, op + 70);
+                    *(op + 68) = (char)(shortNameEnd - shortName);
                 }
             }
 
@@ -3993,7 +5243,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             returnedNames++;
 
             /* NextEntryOffset and FileIndex */
-            if (infoLevel >= 101) {
+            if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
                 int entryOffset = orbytes + align;
                 *((u_long *)op) = entryOffset;
                 *((u_long *)(op+4)) = nextEntryCookie;
@@ -4002,7 +5252,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             /* 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
-             * out data from * a buffer, while holding the scp
+             * out data from a buffer, while holding the scp
              * locked, so it isn't really convenient to stat
              * something now.  We'll put in a place holder
              * now, and make a second pass before returning this
@@ -4012,12 +5262,11 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
              * later.  The replay will happen at a time when it is
              * safe to unlock the directory.
              */
-            if (infoLevel != 0x103) {
+            if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
                 curPatchp = malloc(sizeof(*curPatchp));
-                osi_QAdd((osi_queue_t **) &dirListPatchesp,
-                          &curPatchp->q);
+                osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
                 curPatchp->dptr = op;
-                if (infoLevel >= 0x101)
+                if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
                     curPatchp->dptr += 8;
 
                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
@@ -4035,7 +5284,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 curPatchp->dep = dep;
             }   
 
-            if (searchFlags & 4)
+            if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
                 /* put out resume key */
                 *((u_long *)origOp) = nextEntryCookie;
 
@@ -4049,15 +5298,13 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 bytesInBuffer++;
             }
         }      /* if we're including this name */
-        else if (!NeedShortName &&
-                 !starPattern &&
-                 !foundInexact &&
-                 dep->fid.vnode != 0 &&
-                 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
+        else if (!starPattern &&
+                  !foundInexact &&
+                  smb_V3MatchMask(dep->name, 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;
@@ -4071,23 +5318,27 @@ 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) buf_Release(bufferp);
+    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.
      */
-    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;
+    if (returnedNames == 0) 
+        eos = 1;
     if (p->opcode == 1) {
         /* find first */
         outp->parmsp[0] = (unsigned short) dsp->cookie;
@@ -4114,26 +5365,28 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     /* return # of bytes in the buffer */
     outp->totalData = bytesInBuffer;
 
-    osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
-             returnedNames, code);
-
     /* Return error code if unsuccessful on first request */
     if (code == 0 && p->opcode == 1 && returnedNames == 0)
         code = CM_ERROR_NOSUCHFILE;
 
+    osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
+             p->opcode, dsp->cookie, returnedNames, code);
+
     /* if we're supposed to close the search after this request, or if
      * 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 {
+    else
         smb_SendTran2Packet(vcp, outp, opx);
-    }
+
     smb_FreeTran2Packet(outp);
     smb_ReleaseDirSearch(dsp);
     cm_ReleaseSCache(scp);
@@ -4185,7 +5438,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_fid_t *fidp;
     int attributes;
     char *lastNamep;
-    time_t dosTime;
+    afs_uint32 dosTime;
     int openFun;
     int trunc;
     int openMode;
@@ -4194,26 +5447,30 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     int parmSlot;                      /* which parm we're dealing with */
     char *tidPathp;
     cm_req_t req;
+    int created = 0;
 
     cm_InitReq(&req);
 
     scp = NULL;
         
-    extraInfo = (smb_GetSMBParm(inp, 2) & 1);  /* return extra info */
-    openFun = smb_GetSMBParm(inp, 8);  /* open function */
+    extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
+    openFun = smb_GetSMBParm(inp, 8); /* open function */
     excl = ((openFun & 3) == 0);
-    trunc = ((openFun & 3) == 2);              /* truncate it */
+    trunc = ((openFun & 3) == 2); /* truncate it */
     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
-    openAction = 0;                    /* tracks what we did */
+    openAction = 0;             /* tracks what we did */
 
     attributes = smb_GetSMBParm(inp, 5);
     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
 
-       /* compute initial mode bits based on read-only flag in attributes */
+                                /* compute initial mode bits based on read-only flag in attributes */
     initialModeBits = 0666;
-    if (attributes & 1) initialModeBits &= ~0222;
+    if (attributes & SMB_ATTR_READONLY) 
+       initialModeBits &= ~0222;
         
     pathp = smb_GetSMBData(inp, NULL);
+    if (smb_StoreAnsiFilenames)
+        OemToChar(pathp,pathp);
 
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
@@ -4267,7 +5524,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        free(hexp);
     }
 #endif
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     dscp = NULL;
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
@@ -4275,29 +5532,54 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
-    code = cm_NameI(cm_rootSCachep, pathp,
+    code = cm_NameI(cm_data.rootSCachep, pathp,
                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                     userp, tidPathp, &req, &scp);
+
+#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) || pnc )
+            return CM_ERROR_PATH_NOT_COVERED;
+        else
+            return CM_ERROR_BADSHARENAME;
+    }
+#endif /* DFS_SUPPORT */
+
     if (code != 0) {
-        code = cm_NameI(cm_rootSCachep, spacep->data,
+        code = cm_NameI(cm_data.rootSCachep, spacep->data,
                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &dscp);
-
         if (code) {
             cm_ReleaseUser(userp);
             return code;
         }
-        
+
+#ifdef DFS_SUPPORT
+        if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+            cm_ReleaseSCache(dscp);
+            cm_ReleaseUser(userp);
+            if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+                return CM_ERROR_PATH_NOT_COVERED;
+            else
+                return CM_ERROR_BADSHARENAME;
+        }
+#endif /* DFS_SUPPORT */
         /* otherwise, scp points to the parent directory.  Do a lookup,
          * and truncate the file if we find it, otherwise we create the
          * file.
          */
-        if (!lastNamep) lastNamep = pathp;
-        else lastNamep++;
+        if (!lastNamep) 
+            lastNamep = pathp;
+        else 
+            lastNamep++;
         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
                           &req, &scp);
-        if (code && code != CM_ERROR_NOSUCHFILE) {
-                       cm_ReleaseSCache(dscp);
+        if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
+            cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
             return code;
         }
@@ -4319,7 +5601,8 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         if (excl) {
             /* oops, file shouldn't be there */
-            if (dscp) cm_ReleaseSCache(dscp);
+            if (dscp) 
+                cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             return CM_ERROR_EXISTS;
@@ -4334,14 +5617,14 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         }
         else openAction = 1;   /* found existing file */
     }
-    else if (!(openFun & 0x10)) {
+    else if (!(openFun & SMB_ATTR_DIRECTORY)) {
         /* don't create if not found */
         if (dscp) cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHFILE;
     }
     else {
-        osi_assert(dscp != NULL);
+        osi_assertx(dscp != NULL, "null cm_scache_t");
         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
                  osi_LogSaveString(smb_logp, lastNamep));
         openAction = 2;        /* created file */
@@ -4349,11 +5632,13 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                          &req);
-        if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-            smb_NotifyChange(FILE_ACTION_ADDED,
-                             FILE_NOTIFY_CHANGE_FILE_NAME,
-                             dscp, lastNamep, NULL, TRUE);
-        if (!excl && code == CM_ERROR_EXISTS) {
+        if (code == 0) {
+           created = 1;
+           if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+               smb_NotifyChange(FILE_ACTION_ADDED,
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
+                                dscp, lastNamep, NULL, TRUE);
+       } else if (!excl && code == CM_ERROR_EXISTS) {
             /* 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
@@ -4374,11 +5659,13 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
         
     /* we don't need this any longer */
-    if (dscp) cm_ReleaseSCache(dscp);
+    if (dscp) 
+        cm_ReleaseSCache(dscp);
 
     if (code) {
         /* something went wrong creating or truncating the file */
-        if (scp) cm_ReleaseSCache(scp);
+        if (scp) 
+            cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         return code;
     }
@@ -4392,16 +5679,30 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* now all we have to do is open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
        
+    cm_HoldUser(userp);
+    lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    lock_ObtainMutex(&scp->mx);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseMutex(&scp->mx);
+    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;
+    if (openMode != 1) 
+        fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     if (openMode == 1 || openMode == 2)
         fidp->flags |= SMB_FID_OPENWRITE;
 
+    /* remember if the file was newly created */
+    if (created)
+       fidp->flags |= SMB_FID_CREATED;
+
+    lock_ReleaseMutex(&fidp->mx);
     smb_ReleaseFID(fidp);
         
     cm_Open(scp, 0, userp);
@@ -4440,6 +5741,32 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }       
 
+static void smb_GetLockParams(unsigned char LockType, 
+                              char ** buf, 
+                              unsigned int * ppid, 
+                              LARGE_INTEGER * pOffset, 
+                              LARGE_INTEGER * pLength)
+{
+    if (LockType & LOCKING_ANDX_LARGE_FILES) {
+        /* Large Files */
+        *ppid = *((USHORT *) *buf);
+        pOffset->HighPart = *((LONG *)(*buf + 4));
+        pOffset->LowPart = *((DWORD *)(*buf + 8));
+        pLength->HighPart = *((LONG *)(*buf + 12));
+        pLength->LowPart = *((DWORD *)(*buf + 16));
+        *buf += 20;
+    }
+    else {
+        /* Not Large Files */
+        *ppid = *((USHORT *) *buf);
+        pOffset->HighPart = 0;
+        pOffset->LowPart = *((DWORD *)(*buf + 2));
+        pLength->HighPart = 0;
+        pLength->LowPart = *((DWORD *)(*buf + 6));
+        *buf += 10;
+    }
+}
+
 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     cm_req_t req;
@@ -4449,13 +5776,16 @@ 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;
-    unsigned long Timeout;
+    long Timeout;
     char *op;
+    char *op_locks;
     LARGE_INTEGER LOffset, LLength;
-    smb_waitingLock_t *waitingLock;
-    void *lockp;
+    smb_waitingLockRequest_t *wlRequest = NULL;
+    cm_file_lock_t *lockp;
     long code = 0;
     int i;
+    cm_key_t key;
+    unsigned int pid;
 
     cm_InitReq(&req);
 
@@ -4463,107 +5793,247 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     fid = smb_ChainFID(fid, inp);
 
     fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
+    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");
+       lock_ReleaseMutex(&fidp->mx);
+       smb_ReleaseFID(fidp);
         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);
+
     /* set inp->fid so that later read calls in same msg can find fid */
     inp->fid = fid;
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
-    scp = fidp->scp;
 
     lock_ObtainMutex(&scp->mx);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK
                         | CM_SCACHESYNC_GETSTATUS
                         | CM_SCACHESYNC_LOCK);
-       if (code) goto doneSync;
-
-       LockType = smb_GetSMBParm(inp, 3) & 0xff;
-       Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
-       NumberOfUnlocks = smb_GetSMBParm(inp, 6);
-       NumberOfLocks = smb_GetSMBParm(inp, 7);
-
-       op = smb_GetSMBData(inp, NULL);
-
-       for (i=0; i<NumberOfUnlocks; i++) {
-            if (LockType & 0x10) {
-                /* Large Files */
-                LOffset.HighPart = *((LONG *)(op + 4));
-                LOffset.LowPart = *((DWORD *)(op + 8));
-                LLength.HighPart = *((LONG *)(op + 12));
-                LLength.LowPart = *((DWORD *)(op + 16));
-                op += 20;
-            }
-            else {
-                /* Not Large Files */
-                LOffset.HighPart = 0;
-                LOffset.LowPart = *((DWORD *)(op + 2));
-                LLength.HighPart = 0;
-                LLength.LowPart = *((DWORD *)(op + 6));
-                op += 10;
-            }
-            if (LargeIntegerNotEqualToZero(LOffset))
-                continue;
-            /* Do not check length -- length check done in cm_Unlock */
-
-            code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
-            if (code) goto done;
-       }       
-
-       for (i=0; i<NumberOfLocks; i++) {
-            if (LockType & 0x10) {
-                /* Large Files */
-                LOffset.HighPart = *((LONG *)(op + 4));
-                LOffset.LowPart = *((DWORD *)(op + 8));
-                LLength.HighPart = *((LONG *)(op + 12));
-                LLength.LowPart = *((DWORD *)(op + 16));
-                op += 20;
-            }
-            else {
-                /* Not Large Files */
-                LOffset.HighPart = 0;
-                LOffset.LowPart = *((DWORD *)(op + 2));
-                LLength.HighPart = 0;
-                LLength.LowPart = *((DWORD *)(op + 6));
-                op += 10;
-            }
-            if (LargeIntegerNotEqualToZero(LOffset))
-                continue;
-            if (LargeIntegerLessThan(LOffset, scp->length))
-                continue;
-
-            code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
-                            userp, &req, &lockp);
-            if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
-                /* Put on waiting list */
-                waitingLock = malloc(sizeof(smb_waitingLock_t));
-                waitingLock->vcp = vcp;
-                waitingLock->inp = smb_CopyPacket(inp);
-                waitingLock->outp = smb_CopyPacket(outp);
-                waitingLock->timeRemaining = Timeout;
-                waitingLock->lockp = lockp;
-                lock_ObtainWrite(&smb_globalLock);
-                osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
-                          &waitingLock->q);
-                osi_Wakeup((long) &smb_allWaitingLocks);
-                lock_ReleaseWrite(&smb_globalLock);
-                /* don't send reply immediately */
-                outp->flags |= SMB_PACKETFLAG_NOSEND;
+    if (code) {
+        osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
+        goto doneSync;
+    }
+
+    LockType = smb_GetSMBParm(inp, 3) & 0xff;
+    Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
+    NumberOfUnlocks = smb_GetSMBParm(inp, 6);
+    NumberOfLocks = smb_GetSMBParm(inp, 7);
+
+    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_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.*/
+
+        code = CM_ERROR_BADOP;
+        goto done;
+
+    }
+
+    op = smb_GetSMBData(inp, NULL);
+
+    for (i=0; i<NumberOfUnlocks; i++) {
+        smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
+
+        key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+        code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
+
+        if (code) 
+            goto done;
+    }
+
+    op_locks = op;
+
+    for (i=0; i<NumberOfLocks; i++) {
+        smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
+
+        key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+        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;
+
+            /* Put on waiting list */
+            if(wlRequest == NULL) {
+                int j;
+                char * opt;
+                cm_key_t tkey;
+                LARGE_INTEGER tOffset, tLength;
+
+                wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
+
+                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->locks = NULL;
+
+                /* The waiting lock request needs to have enough
+                   information to undo all the locks in the request.
+                   We do the following to store info about locks that
+                   have already been granted.  Sure, we can get most
+                   of the info from the packet, but the packet doesn't
+                   hold the result of cm_Lock call.  In practice we
+                   only receive packets with one or two locks, so we
+                   are only wasting a few bytes here and there and
+                   only for a limited period of time until the waiting
+                   lock times out or is freed. */
+
+                for(opt = op_locks, j=i; j > 0; j--) {
+                    smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
+
+                    tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+                    wLock = malloc(sizeof(smb_waitingLock_t));
+
+                    osi_assertx(wLock != NULL, "null smb_waitingLock_t");
+
+                    wLock->key = tkey;
+                    wLock->LOffset = tOffset;
+                    wLock->LLength = tLength;
+                    wLock->lockp = NULL;
+                    wLock->state = SMB_WAITINGLOCKSTATE_DONE;
+                    osi_QAdd((osi_queue_t **) &wlRequest->locks,
+                             &wLock->q);
+                }
             }
-            if (code) break;
-       }       
 
-    if (code) {
-        /* release any locks acquired before the failure */
+            wLock = malloc(sizeof(smb_waitingLock_t));
+
+            osi_assertx(wLock != NULL, "null smb_waitingLock_t");
+
+            wLock->key = key;
+            wLock->LOffset = LOffset;
+            wLock->LLength = LLength;
+            wLock->lockp = lockp;
+            wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
+            osi_QAdd((osi_queue_t **) &wlRequest->locks,
+                     &wLock->q);
+
+            osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
+                     wLock);
+
+            code = 0;
+            continue;
+        }
+
+        if (code) {
+            osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
+            break;
+        }
     }
-    else
+
+    if (code) {
+
+        /* Since something went wrong with the lock number i, we now
+           have to go ahead and release any locks acquired before the
+           failure.  All locks before lock number i (of which there
+           are i of them) have either been successful or are waiting.
+           Either case requires calling cm_Unlock(). */
+
+        /* And purge the waiting lock */
+        if(wlRequest != NULL) {
+            smb_waitingLock_t * wl;
+            smb_waitingLock_t * wlNext;
+            long ul_code;
+
+            for(wl = wlRequest->locks; wl; wl = wlNext) {
+
+                wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
+
+                ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
+                
+                if(ul_code != 0) {
+                    osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
+                } else {
+                    osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
+                }
+
+                osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
+                free(wl);
+
+            }
+
+            smb_ReleaseVC(wlRequest->vcp);
+            cm_ReleaseSCache(wlRequest->scp);
+            smb_FreePacket(wlRequest->inp);
+            smb_FreePacket(wlRequest->outp);
+
+            free(wlRequest);
+
+            wlRequest = NULL;
+        }
+
+    } else {
+
+        if (wlRequest != NULL) {
+
+            lock_ObtainWrite(&smb_globalLock);
+            osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
+                     &wlRequest->q);
+            osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
+            lock_ReleaseWrite(&smb_globalLock);
+
+            /* don't send reply immediately */
+            outp->flags |= SMB_PACKETFLAG_NOSEND;
+        }
+
         smb_SetSMBDataLength(outp, 0);
+    }
+
   done:   
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+
   doneSync:
     lock_ReleaseMutex(&scp->mx);
+    cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
 
@@ -4576,7 +6046,7 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     smb_fid_t *fidp;
     cm_scache_t *scp;
     long code = 0;
-    time_t searchTime;
+    afs_uint32 searchTime;
     cm_user_t *userp;
     cm_req_t req;
 
@@ -4586,19 +6056,37 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     fid = smb_ChainFID(fid, inp);
         
     fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
+    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);
+       smb_ReleaseFID(fidp);
         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);
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
         
-    scp = fidp->scp;
         
     /* otherwise, stat the file */
     lock_ObtainMutex(&scp->mx);
     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);
 
     /* decode times.  We need a search time, but the response to this
      * call provides the date first, not the time, as returned in the
@@ -4627,6 +6115,7 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
   done:
     lock_ReleaseMutex(&scp->mx);
+    cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
     return code;
@@ -4638,84 +6127,297 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     smb_fid_t *fidp;
     cm_scache_t *scp;
     long code = 0;
-    time_t searchTime;
+    afs_uint32 searchTime;
     time_t unixTime;
     cm_user_t *userp;
     cm_attr_t attrs;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    cm_InitReq(&req);
+
+    fid = smb_GetSMBParm(inp, 0);
+    fid = smb_ChainFID(fid, inp);
+        
+    fidp = smb_FindFID(vcp, fid, 0);
+    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);
+       smb_ReleaseFID(fidp);
+        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);
+        
+    userp = smb_GetUserFromVCP(vcp, inp);
+        
+        
+    /* now prepare to call cm_setattr.  This message only sets various times,
+     * and AFS only implements mtime, and we'll set the mtime if that's
+     * requested.  The others we'll ignore.
+     */
+    searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
+        
+    if (searchTime != 0) {
+        smb_UnixTimeFromSearchTime(&unixTime, searchTime);
+
+        if ( unixTime != -1 ) {
+            attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
+            attrs.clientModTime = unixTime;
+            code = cm_SetAttr(scp, &attrs, userp, &req);
+
+            osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
+        } else {
+            osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
+        }
+    }
+    else 
+       code = 0;
+
+    cm_ReleaseSCache(scp);
+    cm_ReleaseUser(userp);
+    smb_ReleaseFID(fidp);
+    return code;
+}
+
+long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
+{
+    osi_hyper_t offset;
+    long count, written = 0, total_written = 0;
+    unsigned short fd;
+    unsigned pid;
+    smb_fid_t *fidp;
+    long code = 0;
+    cm_user_t *userp;
+    char *op;
+    int inDataBlockCount;
+
+    fd = smb_GetSMBParm(inp, 2);
+    count = smb_GetSMBParm(inp, 10);
+
+    offset.HighPart = 0;
+    offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
+
+    if (*inp->wctp == 14) {
+        /* we have a request with 64-bit file offsets */
+#ifdef AFS_LARGEFILES
+        offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
+#else
+        if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
+            /* uh oh */
+            osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
+            /* we shouldn't have received this op if we didn't specify
+               largefile support */
+            return CM_ERROR_BADOP;
+        }
+#endif
+    }
+
+    op = inp->data + smb_GetSMBParm(inp, 11);
+    inDataBlockCount = count;
+
+    osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
+             fd, offset.HighPart, offset.LowPart, count);
+        
+    fd = smb_ChainFID(fd, inp);
+    fidp = smb_FindFID(vcp, fd, 0);
+    if (!fidp)
+        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);
+        code = smb_IoctlV3Write(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       return code;
+    }
+    lock_ReleaseMutex(&fidp->mx);
+    userp = smb_GetUserFromVCP(vcp, inp);
+
+    /* special case: 0 bytes transferred means there is no data
+       transferred.  A slight departure from SMB_COM_WRITE where this
+       means that we are supposed to truncate the file at this
+       position. */
+
+    {
+        cm_key_t key;
+        LARGE_INTEGER LOffset;
+        LARGE_INTEGER LLength;
+        cm_scache_t * scp;
+
+        pid = ((smb_t *) inp)->pid;
+        key = cm_GenerateKey(vcp->vcID, pid, fd);
 
-    fid = smb_GetSMBParm(inp, 0);
-    fid = smb_ChainFID(fid, inp);
-        
-    fidp = smb_FindFID(vcp, fid, 0);
-    if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
-        return CM_ERROR_BADFD;
+        LOffset.HighPart = offset.HighPart;
+        LOffset.LowPart = offset.LowPart;
+        LLength.HighPart = 0;
+        LLength.LowPart = count;
+
+        scp = fidp->scp;
+        lock_ObtainMutex(&scp->mx);
+        code = cm_LockCheckWrite(scp, LOffset, LLength, key);
+        lock_ReleaseMutex(&scp->mx);
+
+        if (code)
+            goto done;
     }
-        
-    userp = smb_GetUser(vcp, inp);
-        
-    scp = fidp->scp;
-        
-    /* now prepare to call cm_setattr.  This message only sets various times,
-     * and AFS only implements mtime, and we'll set the mtime if that's
-     * requested.  The others we'll ignore.
+
+    /*
+     * Work around bug in NT client
+     *
+     * When copying a file, the NT client should first copy the data,
+     * then copy the last write time.  But sometimes the NT client does
+     * these in the wrong order, so the data copies would inadvertently
+     * cause the last write time to be overwritten.  We try to detect this,
+     * and don't set client mod time if we think that would go against the
+     * intention.
      */
-    searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
-        
-    if (searchTime != 0) {
-        smb_UnixTimeFromSearchTime(&unixTime, searchTime);
+    lock_ObtainMutex(&fidp->mx);
+    if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
+        fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
+        fidp->scp->clientModTime = time(NULL);
+    }
+    lock_ReleaseMutex(&fidp->mx);
 
-        if ( unixTime != -1 ) {
-            attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
-            attrs.clientModTime = unixTime;
-            code = cm_SetAttr(scp, &attrs, userp, &req);
+    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;
 
-            osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
-        } else {
-            osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
-        }
+        offset = LargeIntegerAdd(offset,
+                                 ConvertLongToLargeInteger(written));
+        count -= written;
+        total_written += written;
+        written = 0;
     }
-    else code = 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);
+    smb_SetSMBParm(outp, 3, 0); /* reserved */
+    smb_SetSMBParm(outp, 4, 0); /* reserved */
+    smb_SetSMBParm(outp, 5, 0); /* reserved */
+    smb_SetSMBDataLength(outp, 0);
+
+ done:
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
+
     return code;
 }
 
-
 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
-    long count, finalCount;
+    long count;
+    long finalCount = 0;
     unsigned short fd;
+    unsigned pid;
     smb_fid_t *fidp;
     long code = 0;
     cm_user_t *userp;
+    cm_key_t key;
     char *op;
         
     fd = smb_GetSMBParm(inp, 2);
     count = smb_GetSMBParm(inp, 5);
-    offset.HighPart = 0;       /* too bad */
     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
 
-    osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
-             fd, offset.LowPart, count);
-        
+    if (*inp->wctp == 12) {
+        /* a request with 64-bit offsets */
+#ifdef AFS_LARGEFILES
+        offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
+
+        if (LargeIntegerLessThanZero(offset)) {
+            osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
+                     offset.HighPart, offset.LowPart);
+            return CM_ERROR_BADSMB;
+        }
+#else
+        if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
+            osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit.  Dropping");
+            return CM_ERROR_BADSMB;
+        } else {
+            offset.HighPart = 0;
+        }
+#endif
+    } else {
+        offset.HighPart = 0;
+    }
+
+    osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
+             fd, offset.HighPart, offset.LowPart, count);
+
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
     if (!fidp) {
         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;
+    }
+
+    pid = ((smb_t *) inp)->pid;
+    key = cm_GenerateKey(vcp->vcID, pid, fd);
+    {
+        LARGE_INTEGER LOffset, LLength;
+        cm_scache_t *scp;
+
+        LOffset.HighPart = offset.HighPart;
+        LOffset.LowPart = offset.LowPart;
+        LLength.HighPart = 0;
+        LLength.LowPart = count;
+
+        scp = fidp->scp;
+        lock_ObtainMutex(&scp->mx);
+        code = cm_LockCheckRead(scp, LOffset, LLength, key);
+        lock_ReleaseMutex(&scp->mx);
+    }
+
+    if (code) {
+        smb_ReleaseFID(fidp);
+        return code;
+    }
+
     /* set inp->fid so that later read calls in same msg can find fid */
     inp->fid = fd;
 
+    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
-        return smb_IoctlV3Read(fidp, vcp, inp, outp);
+       lock_ReleaseMutex(&fidp->mx);
+        code = smb_IoctlV3Read(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       return code;
     }
-        
-    userp = smb_GetUser(vcp, inp);
+    lock_ReleaseMutex(&fidp->mx);
+
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /* 0 and 1 are reserved for request chaining, were setup by our caller,
      * and will be further filled in after we return.
@@ -4752,9 +6454,8 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_SetSMBParm(outp, 5, finalCount);
     smb_SetSMBDataLength(outp, finalCount);
 
-    smb_ReleaseFID(fidp);
-
     cm_ReleaseUser(userp);
+    smb_ReleaseFID(fidp);
     return code;
 }   
         
@@ -4768,6 +6469,23 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #define  FILE_OVERWRITE        4       // (open & truncate, but do not create)
 #define  FILE_OVERWRITE_IF 5   // (open & truncate, or create)
 
+/* Flags field */
+#define REQUEST_OPLOCK 2
+#define REQUEST_BATCH_OPLOCK 4
+#define OPEN_DIRECTORY 8
+#define EXTENDED_RESPONSE_REQUIRED 0x10
+
+/* CreateOptions field. */
+#define FILE_DIRECTORY_FILE       0x0001
+#define FILE_WRITE_THROUGH        0x0002
+#define FILE_SEQUENTIAL_ONLY      0x0004
+#define FILE_NON_DIRECTORY_FILE   0x0040
+#define FILE_NO_EA_KNOWLEDGE      0x0200
+#define FILE_EIGHT_DOT_THREE_ONLY 0x0400
+#define FILE_RANDOM_ACCESS        0x0800
+#define FILE_DELETE_ON_CLOSE      0x1000
+#define FILE_OPEN_BY_FILE_ID      0x2000
+
 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp, *realPathp;
@@ -4785,12 +6503,14 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     unsigned int requestOpLock;
     unsigned int requestBatchOpLock;
     unsigned int mustBeDir;
+    unsigned int extendedRespRequired;
     unsigned int treeCreate;
     int realDirFlag;
     unsigned int desiredAccess;
     unsigned int extAttributes;
     unsigned int createDisp;
     unsigned int createOptions;
+    unsigned int shareAccess;
     int initialModeBits;
     unsigned short baseFid;
     smb_fid_t *baseFidp;
@@ -4804,19 +6524,27 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     char *tidPathp;
     BOOL foundscp;
     cm_req_t req;
+    int created = 0;
+    cm_lock_data_t *ldp = NULL;
 
     cm_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 
+     * we don't lose a reference.  Start by ensuring that they are NULL.
+     */
+    scp = NULL;
+    dscp = NULL;
     treeCreate = FALSE;
     foundscp = FALSE;
-    scp = NULL;
 
     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
     flags = smb_GetSMBOffsetParm(inp, 3, 1)
         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
-    requestOpLock = flags & 0x02;
-    requestBatchOpLock = flags & 0x04;
-    mustBeDir = flags & 0x08;
+    requestOpLock = flags & REQUEST_OPLOCK;
+    requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
+    mustBeDir = flags & OPEN_DIRECTORY;
+    extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
 
     /*
      * Why all of a sudden 32-bit FID?
@@ -4829,6 +6557,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
+    shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
+        | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
@@ -4837,9 +6567,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* mustBeDir is never set; createOptions directory bit seems to be
      * more important
      */
-    if (createOptions & 1)
+    if (createOptions & FILE_DIRECTORY_FILE)
         realDirFlag = 1;
-    else if (createOptions & 0x40)
+    else if (createOptions & FILE_NON_DIRECTORY_FILE)
         realDirFlag = 0;
     else
         realDirFlag = -1;
@@ -4849,7 +6579,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
      * extended attributes
      */
     initialModeBits = 0666;
-    if (extAttributes & 1) 
+    if (extAttributes & SMB_ATTR_READONLY) 
         initialModeBits &= ~0222;
 
     pathp = smb_GetSMBData(inp, NULL);
@@ -4857,13 +6587,15 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     realPathp = malloc(nameLength+1);
     memcpy(realPathp, pathp, nameLength);
     realPathp[nameLength] = 0;
+    if (smb_StoreAnsiFilenames)
+        OemToChar(realPathp,realPathp);
 
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
 
     osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
-    osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
+    osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
 
     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
         /* special case magic file name for receiving IOCTL requests
@@ -4911,7 +6643,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        free(hexp);
     }
 #endif
-    userp = smb_GetUser(vcp, inp);
+
+    userp = smb_GetUserFromVCP(vcp, inp);
     if (!userp) {
        osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
        free(realPathp);
@@ -4919,19 +6652,23 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 
     if (baseFid == 0) {
-        baseDirp = cm_rootSCachep;
+       baseFidp = NULL;
+        baseDirp = cm_data.rootSCachep;
         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
         if (code == CM_ERROR_TIDIPC) {
             /* Attempt to use a TID allocated for IPC.  The client
              * is probably looking for DCE RPC end points which we
-             * don't support. */
+             * don't support OR it could be looking to make a DFS
+             * referral request. 
+             */
             osi_Log0(smb_logp, "NTCreateX received IPC TID");
+#ifndef DFS_SUPPORT
             free(realPathp);
             cm_ReleaseUser(userp);
             return CM_ERROR_NOSUCHFILE;
+#endif /* DFS_SUPPORT */
         }
-    }
-    else {
+    } else {
         baseFidp = smb_FindFID(vcp, baseFid, 0);
         if (!baseFidp) {
             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
@@ -4939,6 +6676,15 @@ 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;
     }
@@ -4950,12 +6696,27 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (desiredAccess & DELETE)
         fidflags |= SMB_FID_OPENDELETE;
     if (desiredAccess & AFS_ACCESS_READ)
-        fidflags |= SMB_FID_OPENREAD;
+        fidflags |= SMB_FID_OPENREAD_LISTDIR;
     if (desiredAccess & AFS_ACCESS_WRITE)
         fidflags |= SMB_FID_OPENWRITE;
-
-    dscp = NULL;
+    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 (smb_IsExecutableFileName(lastNamep))
+        fidflags |= SMB_FID_EXECUTABLE;
+
+    /* and the share mode */
+    if (shareAccess & FILE_SHARE_READ)
+        fidflags |= SMB_FID_SHARE_READ;
+    if (shareAccess & FILE_SHARE_WRITE)
+        fidflags |= SMB_FID_SHARE_WRITE;
+
+    osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
     code = 0;
+
     /* For an exclusive create, we want to do a case sensitive match for the last component. */
     if ( createDisp == FILE_CREATE || 
          createDisp == FILE_OVERWRITE ||
@@ -4963,9 +6724,23 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &dscp);
         if (code == 0) {
+#ifdef DFS_SUPPORT
+            if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                cm_ReleaseSCache(dscp);
+                cm_ReleaseUser(userp);
+                free(realPathp);
+               if (baseFidp) 
+                   smb_ReleaseFID(baseFidp);
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+                    return CM_ERROR_PATH_NOT_COVERED;
+                else
+                    return CM_ERROR_BADSHARENAME;
+            }
+#endif /* DFS_SUPPORT */
             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
                              userp, &req, &scp);
-            if (code == CM_ERROR_NOSUCHFILE) {
+            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) {
@@ -4973,18 +6748,36 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                     cm_ReleaseSCache(dscp);
                     cm_ReleaseUser(userp);
                     free(realPathp);
+                   if (baseFidp) 
+                       smb_ReleaseFID(baseFidp);
                     return CM_ERROR_EXISTS;
                 }
             }
-        } else
-            dscp = NULL;
+        }
+        /* we have both scp and dscp */
     } else {
         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         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) || pnc )
+                return CM_ERROR_PATH_NOT_COVERED;
+            else
+                return CM_ERROR_BADSHARENAME;
+        }
+#endif /* DFS_SUPPORT */
+        /* we might have scp but not dscp */
     }
-    if (code == 0) 
-        foundscp = TRUE;
 
+    if (scp)
+        foundscp = TRUE;
+    
     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
         /* look up parent directory */
         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
@@ -4992,14 +6785,33 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
          * recognize.
          */
 
-        if ( !dscp ) {
-            while (1) {
+        /* we might or might not have scp */
+
+        if (dscp == NULL) {
+            do {
                 char *tp;
 
                 code = cm_NameI(baseDirp, spacep->data,
                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                              userp, tidPathp, &req, &dscp);
 
+#ifdef DFS_SUPPORT
+                if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+                    int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                    if (scp)
+                        cm_ReleaseSCache(scp);
+                    cm_ReleaseSCache(dscp);
+                    cm_ReleaseUser(userp);
+                    free(realPathp);
+                   if (baseFidp) 
+                       smb_ReleaseFID(baseFidp);
+                    if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+                        return CM_ERROR_PATH_NOT_COVERED;
+                    else
+                        return CM_ERROR_BADSHARENAME;
+                }
+#endif /* DFS_SUPPORT */
+
                 if (code && 
                      (tp = strrchr(spacep->data,'\\')) &&
                      (createDisp == FILE_CREATE) &&
@@ -5009,258 +6821,310 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                     treeStartp = realPathp + (tp - spacep->data);
 
                     if (*tp && !smb_IsLegalFilename(tp)) {
-                        if (baseFid != 0) 
-                            smb_ReleaseFID(baseFidp);
                         cm_ReleaseUser(userp);
+                        if (baseFidp) 
+                            smb_ReleaseFID(baseFidp);
                         free(realPathp);
+                        if (scp)
+                            cm_ReleaseSCache(scp);
                         return CM_ERROR_BADNTFILENAME;
                     }
+                    code = 0;
+                }
+            } while (dscp == NULL && code == 0);
+        } else
+            code = 0;
+
+        /* we might have scp and we might have dscp */
+
+        if (baseFidp)
+            smb_ReleaseFID(baseFidp);
+
+        if (code) {
+            osi_Log0(smb_logp,"NTCreateX parent not found");
+            if (scp)
+                cm_ReleaseSCache(scp);
+            if (dscp)
+                cm_ReleaseSCache(dscp);
+            cm_ReleaseUser(userp);
+            free(realPathp);
+            return code;
+        }
+
+        if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
+            /* A file exists where we want a directory. */
+            if (scp)
+                cm_ReleaseSCache(scp);
+            cm_ReleaseSCache(dscp);
+            cm_ReleaseUser(userp);
+            free(realPathp);
+            return CM_ERROR_EXISTS;
+        }
+
+        if (!lastNamep) 
+            lastNamep = realPathp;
+        else 
+            lastNamep++;
+
+        if (!smb_IsLegalFilename(lastNamep)) {
+            if (scp)
+                cm_ReleaseSCache(scp);
+            if (dscp)
+                cm_ReleaseSCache(dscp);
+            cm_ReleaseUser(userp);
+            free(realPathp);
+            return CM_ERROR_BADNTFILENAME;
+        }
+
+        if (!foundscp && !treeCreate) {
+            if ( createDisp == FILE_CREATE || 
+                 createDisp == FILE_OVERWRITE ||
+                 createDisp == FILE_OVERWRITE_IF) 
+            {
+                code = cm_Lookup(dscp, lastNamep,
+                                  CM_FLAG_FOLLOW, userp, &req, &scp);
+            } else {
+                code = cm_Lookup(dscp, lastNamep,
+                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
+                                 userp, &req, &scp);
+            }
+            if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
+                if (dscp)
+                    cm_ReleaseSCache(dscp);
+                cm_ReleaseUser(userp);
+                free(realPathp);
+                return code;
+            }
+        }
+        /* we have scp and dscp */
+    } else {
+        /* we have scp but not dscp */
+        if (baseFidp)
+            smb_ReleaseFID(baseFidp);
+    }
+
+    /* if we get here, if code is 0, the file exists and is represented by
+     * scp.  Otherwise, we have to create it.  The dir may be represented
+     * by dscp, or we may have found the file directly.  If code is non-zero,
+     * scp is NULL.
+     */
+    if (code == 0 && !treeCreate) {
+        code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
+        if (code) {
+            if (dscp)
+                cm_ReleaseSCache(dscp);
+            if (scp)
+                cm_ReleaseSCache(scp);
+            cm_ReleaseUser(userp);
+            free(realPathp);
+            return code;
+        }
+
+       if (createDisp == FILE_CREATE) {
+            /* oops, file shouldn't be there */
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+            if (dscp)
+                cm_ReleaseSCache(dscp);
+            if (scp)
+                cm_ReleaseSCache(scp);
+            cm_ReleaseUser(userp);
+            free(realPathp);
+            return CM_ERROR_EXISTS;
+        }
+
+        if ( createDisp == FILE_OVERWRITE || 
+             createDisp == FILE_OVERWRITE_IF) {
+
+            setAttr.mask = CM_ATTRMASK_LENGTH;
+            setAttr.length.LowPart = 0;
+            setAttr.length.HighPart = 0;
+            /* now watch for a symlink */
+            code = 0;
+            while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+                targetScp = 0;
+                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
+                     * target of the symbolic link).  Otherwise,
+                     * we'll just use the symlink anyway.
+                     */
+                    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) {
+                       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 */
+        }
+        else 
+            openAction = 1;    /* found existing file */
+
+    } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
+        /* don't create if not found */
+        if (dscp)
+            cm_ReleaseSCache(dscp);
+        if (scp)
+            cm_ReleaseSCache(scp);
+        cm_ReleaseUser(userp);
+        free(realPathp);
+        return CM_ERROR_NOSUCHFILE;
+    } else if (realDirFlag == 0 || realDirFlag == -1) {
+        osi_assertx(dscp != NULL, "null cm_scache_t");
+        osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
+                  osi_LogSaveString(smb_logp, lastNamep));
+        openAction = 2;                /* created file */
+        setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+        setAttr.clientModTime = time(NULL);
+        code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
+        if (code == 0) {
+           created = 1;
+           if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+               smb_NotifyChange(FILE_ACTION_ADDED,
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
+                                dscp, lastNamep, NULL, TRUE);
+       } else if (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
+             * fails, that means that the file was deleted after we
+             * started this call.
+             */
+            code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
+                              userp, &req, &scp);
+            if (code == 0) {
+                if (createDisp == FILE_OVERWRITE_IF) {
+                    setAttr.mask = CM_ATTRMASK_LENGTH;
+                    setAttr.length.LowPart = 0;
+                    setAttr.length.HighPart = 0;
+
+                    /* now watch for a symlink */
+                    code = 0;
+                    while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+                        targetScp = 0;
+                        code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
+                        if (code == 0) {
+                            /* we have a more accurate file to use (the
+                             * target of the symbolic link).  Otherwise,
+                             * we'll just use the symlink anyway.
+                             */
+                            osi_Log2(smb_logp, "symlink vp %x to vp %x",
+                                      scp, targetScp);
+                            cm_ReleaseSCache(scp);
+                            scp = targetScp;
+                        }
+                    }
+                    code = cm_SetAttr(scp, &setAttr, userp, &req);
                 }
-                else
-                    break;
-            }
-        } else
-            code = 0;
-
-        if (baseFid != 0) 
-            smb_ReleaseFID(baseFidp);
-
-        if (code) {
-            osi_Log0(smb_logp,"NTCreateX parent not found");
-            cm_ReleaseUser(userp);
-            free(realPathp);
-            return code;
+            }  /* lookup succeeded */
         }
+    } else {
+        char *tp, *pp;
+        char *cp; /* This component */
+        int clen = 0; /* length of component */
+        cm_scache_t *tscp1, *tscp2;
+        int isLast = 0;
 
-        if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
-            /* A file exists where we want a directory. */
-            cm_ReleaseSCache(dscp);
-            cm_ReleaseUser(userp);
-            free(realPathp);
-            return CM_ERROR_EXISTS;
-        }
+        /* create directory */
+        if ( !treeCreate ) 
+            treeStartp = lastNamep;
+        osi_assertx(dscp != NULL, "null cm_scache_t");
+        osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
+                  osi_LogSaveString(smb_logp, treeStartp));
+        openAction = 2;                /* created directory */
 
-        if (!lastNamep) 
-            lastNamep = realPathp;
-        else 
-            lastNamep++;
+       /* 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 || code == CM_ERROR_BPLUS_NOMATCH))
+           code = CM_ERROR_EXISTS;
 
-        if (!smb_IsLegalFilename(lastNamep)) {
-            cm_ReleaseSCache(dscp);
-            cm_ReleaseUser(userp);
-            free(realPathp);
-            return CM_ERROR_BADNTFILENAME;
-        }
+        setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
+        setAttr.clientModTime = time(NULL);
 
-        if (!foundscp && !treeCreate) {
-            if ( createDisp == FILE_CREATE || 
-                 createDisp == FILE_OVERWRITE ||
-                 createDisp == FILE_OVERWRITE_IF) 
-            {
-                code = cm_Lookup(dscp, lastNamep,
-                                  CM_FLAG_FOLLOW, userp, &req, &scp);
+        pp = treeStartp;
+        cp = spacep->data;
+        tscp1 = dscp;
+        cm_HoldSCache(tscp1);
+        tscp2 = NULL;
+
+        while (pp && *pp) {
+            tp = strchr(pp, '\\');
+            if (!tp) {
+                strcpy(cp,pp);
+                clen = (int)strlen(cp);
+                isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
             } else {
-                code = cm_Lookup(dscp, lastNamep,
-                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
-                                 userp, &req, &scp);
-            }
-            if (code && code != CM_ERROR_NOSUCHFILE) {
-                cm_ReleaseSCache(dscp);
-                cm_ReleaseUser(userp);
-                free(realPathp);
-                return code;
-            }
-        }
-    }
-    else {
-        if (baseFid != 0) 
-            smb_ReleaseFID(baseFidp);
-       }       
-
-       /* if we get here, if code is 0, the file exists and is represented by
-        * scp.  Otherwise, we have to create it.  The dir may be represented
-        * by dscp, or we may have found the file directly.  If code is non-zero,
-        * scp is NULL.
-        */
-       if (code == 0 && !treeCreate) {
-            if (createDisp == FILE_CREATE) {
-                /* oops, file shouldn't be there */
-                if (dscp) cm_ReleaseSCache(dscp);
-                cm_ReleaseSCache(scp);
-                cm_ReleaseUser(userp);
-                free(realPathp);
-                return CM_ERROR_EXISTS;
+                clen = (int)(tp - pp);
+                strncpy(cp,pp,clen);
+                *(cp + clen) = 0;
+                tp++;
             }
+            pp = tp;
 
-            if ( createDisp == FILE_OVERWRITE || 
-                 createDisp == FILE_OVERWRITE_IF) {
-                setAttr.mask = CM_ATTRMASK_LENGTH;
-                setAttr.length.LowPart = 0;
-                setAttr.length.HighPart = 0;
-                /* now watch for a symlink */
-                code = 0;
-                while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
-                    targetScp = 0;
-                    code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
-                    if (code == 0) {
-                        /* we have a more accurate file to use (the
-                        * target of the symbolic link).  Otherwise,
-                        * we'll just use the symlink anyway.
-                        */
-                        osi_Log2(smb_logp, "symlink vp %x to vp %x",
-                                  scp, targetScp);
-                        cm_ReleaseSCache(scp);
-                        scp = targetScp;
-                    }
-                }
-                code = cm_SetAttr(scp, &setAttr, userp, &req);
-                openAction = 3;        /* truncated existing file */
-            }
-            else 
-                openAction = 1;        /* found existing file */
+            if (clen == 0) 
+                continue; /* the supplied path can't have consecutive slashes either , but */
 
-            code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
-                                  &req);
-            if (code) {
-                if (dscp) cm_ReleaseSCache(dscp);
-                cm_ReleaseSCache(scp);
-                cm_ReleaseUser(userp);
-                free(realPathp);
-                return code;
-            }
-       }       
-       else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
-            /* don't create if not found */
-            if (dscp) cm_ReleaseSCache(dscp);
-            cm_ReleaseUser(userp);
-            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));
-            openAction = 2;            /* created file */
-            setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
-            setAttr.clientModTime = time(NULL);
-            code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
-                              &req);
-            if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
+            /* cp is the next component to be created. */
+            code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
+            if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
                 smb_NotifyChange(FILE_ACTION_ADDED,
-                                  FILE_NOTIFY_CHANGE_FILE_NAME,
-                                  dscp, lastNamep, NULL, TRUE);
-            if (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
                  * fails, that means that the file was deleted after we
                  * started this call.
                  */
-                code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
-                                  userp, &req, &scp);
-                if (code == 0) {
-                    if (createDisp == FILE_OVERWRITE_IF) {
-                        setAttr.mask = CM_ATTRMASK_LENGTH;
-                        setAttr.length.LowPart = 0;
-                        setAttr.length.HighPart = 0;
-
-                        /* now watch for a symlink */
-                        code = 0;
-                        while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
-                            targetScp = 0;
-                            code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
-                            if (code == 0) {
-                                /* we have a more accurate file to use (the
-                                * target of the symbolic link).  Otherwise,
-                                * we'll just use the symlink anyway.
-                                */
-                                osi_Log2(smb_logp, "symlink vp %x to vp %x",
-                                          scp, targetScp);
-                                cm_ReleaseSCache(scp);
-                                scp = targetScp;
-                            }
-                        }
-                        code = cm_SetAttr(scp, &setAttr, userp, &req);
-                    }
-                }      /* lookup succeeded */
-            }
-       }       
-       else {
-            char *tp, *pp;
-            char *cp; /* This component */
-            int clen = 0; /* length of component */
-            cm_scache_t *tscp;
-            int isLast = 0;
-               
-            /* create directory */
-            if ( !treeCreate ) 
-                treeStartp = lastNamep;
-            osi_assert(dscp != NULL);
-            osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
-                      osi_LogSaveString(smb_logp, treeStartp));
-            openAction = 2;            /* created directory */
-
-            setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
-            setAttr.clientModTime = time(NULL);
-               
-            pp = treeStartp;
-            cp = spacep->data;
-            tscp = dscp;
-
-            while (pp && *pp) {
-                tp = strchr(pp, '\\');
-                if (!tp) {
-                    strcpy(cp,pp);
-                    clen = strlen(cp);
-                    isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
-                }
-                else {
-                    clen = tp - pp;
-                    strncpy(cp,pp,clen);
-                    *(cp + clen) = 0;
-                    tp++;
-                }
-                pp = tp;
-
-                if (clen == 0) 
-                    continue; /* the supplied path can't have consecutive slashes either , but */
-
-                /* cp is the next component to be created. */
-                code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
-                if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
-                    smb_NotifyChange(FILE_ACTION_ADDED,
-                                      FILE_NOTIFY_CHANGE_DIR_NAME,
-                                      tscp, 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
-                     * fails, that means that the file was deleted after we
-                     * started this call.
-                     */
-                    code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
-                                      userp, &req, &scp);
-                }
-                if (code) break;
+                code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
+                                  userp, &req, &tscp2);
+            }       
+            if (code) 
+                break;
 
-                if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
-                    cm_ReleaseSCache(tscp);
-                    tscp = scp; /* Newly created directory will be next parent */
-                }
+            if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
+                cm_ReleaseSCache(tscp1);
+                tscp1 = tscp2; /* Newly created directory will be next parent */
+                /* the hold is transfered to tscp1 from tscp2 */
             }
+        }
 
-            /* 
-             * if we get here and code == 0, then scp is the last directory created, and tscp is the
-             * parent of scp.  dscp got released if dscp != tscp. both tscp and scp are held.
-             */
-            dscp = tscp;
-       }
+        if (dscp)
+            cm_ReleaseSCache(dscp);
+        dscp = tscp1;
+        if (scp)
+            cm_ReleaseSCache(scp);
+        scp = tscp2;
+        /* 
+         * if we get here and code == 0, then scp is the last directory created, and dscp is the
+         * parent of scp.
+         */
+    }
 
     if (code) {
         /* something went wrong creating or truncating the file */
-        if (scp) cm_ReleaseSCache(scp);
-        if (dscp) cm_ReleaseSCache(dscp);
+       if (ldp)
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+        if (scp) 
+            cm_ReleaseSCache(scp);
+        if (dscp) 
+            cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         free(realPathp);
         return code;
@@ -5278,14 +7142,19 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 * target of the symbolic link).  Otherwise,
                 * we'll just use the symlink anyway.
                 */
-                osi_Log2(smb_logp, "symlink vp %x to vp %x",
-                          scp, targetScp);
+                osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
+               if (ldp)
+                   cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
         }
 
         if (scp->fileType != CM_SCACHETYPE_FILE) {
+           if (ldp)
+               cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+            if (dscp)
+                cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
@@ -5295,8 +7164,11 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* (only applies to single component case) */
     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
+       if (ldp)
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         cm_ReleaseSCache(scp);
-        if (dscp) cm_ReleaseSCache(dscp);
+        if (dscp)
+            cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         free(realPathp);
         return CM_ERROR_NOTDIR;
@@ -5304,23 +7176,92 @@ 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);
+    fidp->userp = userp;
+
+    /* If we are restricting sharing, we should do so with a suitable
+       share lock. */
+    if (scp->fileType == CM_SCACHETYPE_FILE &&
+        !(fidflags & SMB_FID_SHARE_WRITE)) {
+        cm_key_t key;
+        LARGE_INTEGER LOffset, LLength;
+        int sLockType;
+
+        LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+        LOffset.LowPart = SMB_FID_QLOCK_LOW;
+        LLength.HighPart = 0;
+        LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+        /* If we are not opening the file for writing, then we don't
+           try to get an exclusive lock.  Noone else should be able to
+           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;
+        }
+
+        key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
+        
+        lock_ObtainMutex(&scp->mx);
+        code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
+        lock_ReleaseMutex(&scp->mx);
+
+        if (code) {
+           if (ldp)
+               cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+            cm_ReleaseSCache(scp);
+            if (dscp)
+                cm_ReleaseSCache(dscp);
+           cm_ReleaseUser(userp);
+           /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
+           smb_CloseFID(vcp, fidp, NULL, 0);
+           smb_ReleaseFID(fidp);
+            free(realPathp);
+            return code;
+        }
+    }
+
+    /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
+    if (ldp)
+       cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+
+    lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
-    fidp->scp = scp;
+    fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
+    lock_ObtainMutex(&scp->mx);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseMutex(&scp->mx);
+    osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
 
     fidp->flags = fidflags;
 
+    /* remember if the file was newly created */
+    if (created)
+       fidp->flags |= SMB_FID_CREATED;
+
     /* 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);
+       dscp = NULL;
         fidp->NTopen_pathp = strdup(lastNamep);
     }
     fidp->NTopen_wholepathp = realPathp;
+    lock_ReleaseMutex(&fidp->mx);
 
     /* we don't need this any longer */
-    if (dscp) cm_ReleaseSCache(dscp);
+    if (dscp) {
+        cm_ReleaseSCache(dscp);
+        dscp = NULL;
+    }
+
     cm_Open(scp, 0, userp);
 
     /* set inp->fid so that later read calls in same msg can find fid */
@@ -5344,18 +7285,28 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;     /* filetype */
     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;     /* dev state */
     smb_SetSMBParmByte(outp, parmSlot,
-                        scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
-    lock_ReleaseMutex(&scp->mx);
+                        (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+                        scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                        scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
     smb_SetSMBDataLength(outp, 0);
 
+    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
+        LargeIntegerGreaterThanZero(fidp->scp->length) && 
+        !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+        cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
+                           fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
+                           userp);
+    }
+    lock_ReleaseMutex(&scp->mx);
+
     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
               osi_LogSaveString(smb_logp, realPathp));
 
-    smb_ReleaseFID(fidp);
-
     cm_ReleaseUser(userp);
+    smb_ReleaseFID(fidp);
 
-    /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
+    /* Can't free realPathp if we get here since
+       fidp->NTopen_wholepathp is pointing there */
 
     /* leave scp held since we put it in fidp->scp */
     return 0;
@@ -5386,8 +7337,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     unsigned int desiredAccess;
 #ifdef DEBUG_VERBOSE    
     unsigned int allocSize;
-    unsigned int shareAccess;
 #endif
+    unsigned int shareAccess;
     unsigned int extAttributes;
     unsigned int createDisp;
 #ifdef DEBUG_VERBOSE
@@ -5410,6 +7361,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     ULONG *lparmp;
     char *outData;
     cm_req_t req;
+    int created = 0;
+    cm_lock_data_t *ldp = NULL;
 
     cm_InitReq(&req);
 
@@ -5422,10 +7375,10 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     lparmp = (ULONG *) parmp;
 
     flags = lparmp[0];
-    requestOpLock = flags & 0x02;
-    requestBatchOpLock = flags & 0x04;
-    mustBeDir = flags & 0x08;
-    extendedRespRequired = flags & 0x10;
+    requestOpLock = flags & REQUEST_OPLOCK;
+    requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
+    mustBeDir = flags & OPEN_DIRECTORY;
+    extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
 
     /*
      * Why all of a sudden 32-bit FID?
@@ -5439,9 +7392,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     allocSize = lparmp[3];
 #endif /* DEBUG_VERSOSE */
     extAttributes = lparmp[5];
-#ifdef DEBUG_VEROSE
     shareAccess = lparmp[6];
-#endif
     createDisp = lparmp[7];
     createOptions = lparmp[8];
 #ifdef DEBUG_VERBOSE
@@ -5458,9 +7409,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     /* mustBeDir is never set; createOptions directory bit seems to be
      * more important
      */
-    if (createOptions & 1)
+    if (createOptions & FILE_DIRECTORY_FILE)
         realDirFlag = 1;
-    else if (createOptions & 0x40)
+    else if (createOptions & FILE_NON_DIRECTORY_FILE)
         realDirFlag = 0;
     else
         realDirFlag = -1;
@@ -5470,7 +7421,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
      * extended attributes
      */
     initialModeBits = 0666;
-    if (extAttributes & 1) 
+    if (extAttributes & SMB_ATTR_READONLY) 
         initialModeBits &= ~0222;
 
     pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
@@ -5478,6 +7429,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     realPathp = malloc(nameLength+1);
     memcpy(realPathp, pathp, nameLength);
     realPathp[nameLength] = 0;
+    if (smb_StoreAnsiFilenames)
+        OemToChar(realPathp,realPathp);
 
     spacep = cm_GetSpace();
     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
@@ -5497,7 +7450,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
 #endif
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
     if (!userp) {
        osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
        free(realPathp);
@@ -5505,26 +7458,39 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
 
     if (baseFid == 0) {
-        baseDirp = cm_rootSCachep;
+       baseFidp = NULL;
+        baseDirp = cm_data.rootSCachep;
         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
-        if(code == CM_ERROR_TIDIPC) {
-            /* Attempt to use TID allocated for IPC.  The client is
-             * probably trying to locate DCE RPC endpoints, which we
-             * don't support. */
+        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, "NTTranCreate received IPC TID");
+#ifndef DFS_SUPPORT
             free(realPathp);
             cm_ReleaseUser(userp);
             return CM_ERROR_NOSUCHPATH;
+#endif 
         }
-    }
-    else {
+    } else {
         baseFidp = smb_FindFID(vcp, baseFid, 0);
         if (!baseFidp) {
-               osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
+           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;
     }
@@ -5534,9 +7500,23 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     if (desiredAccess & DELETE)
         fidflags |= SMB_FID_OPENDELETE;
     if (desiredAccess & AFS_ACCESS_READ)
-        fidflags |= SMB_FID_OPENREAD;
+        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 (smb_IsExecutableFileName(lastNamep))
+        fidflags |= SMB_FID_EXECUTABLE;
+
+    /* And the share mode */
+    if (shareAccess & FILE_SHARE_READ)
+        fidflags |= SMB_FID_SHARE_READ;
+    if (shareAccess & FILE_SHARE_WRITE)
+        fidflags |= SMB_FID_SHARE_WRITE;
 
     dscp = NULL;
     code = 0;
@@ -5546,9 +7526,23 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         userp, tidPathp, &req, &dscp);
         if (code == 0) {
+#ifdef DFS_SUPPORT
+            if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                cm_ReleaseSCache(dscp);
+                cm_ReleaseUser(userp);
+                free(realPathp);
+               if (baseFidp)
+                   smb_ReleaseFID(baseFidp);
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+                    return CM_ERROR_PATH_NOT_COVERED;
+                else
+                    return CM_ERROR_BADSHARENAME;
+            }
+#endif /* DFS_SUPPORT */
             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
                              userp, &req, &scp);
-            if (code == CM_ERROR_NOSUCHFILE) {
+            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) {
@@ -5556,6 +7550,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                     cm_ReleaseSCache(dscp);
                     cm_ReleaseUser(userp);
                     free(realPathp);
+                   if (baseFidp)
+                       smb_ReleaseFID(baseFidp);
                     return CM_ERROR_EXISTS;
                 }
             }
@@ -5564,26 +7560,52 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     } else {
         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                         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) || pnc )
+                return CM_ERROR_PATH_NOT_COVERED;
+            else
+                return CM_ERROR_BADSHARENAME;
+        }
+#endif /* DFS_SUPPORT */
     }
 
     if (code == 0) 
         foundscp = TRUE;
-    if (code != 0
-         || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
+
+    if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
         /* look up parent directory */
         if ( !dscp ) {
             code = cm_NameI(baseDirp, spacep->data,
                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
                              userp, tidPathp, &req, &dscp);
+#ifdef DFS_SUPPORT
+            if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                cm_ReleaseSCache(dscp);
+                cm_ReleaseUser(userp);
+                free(realPathp);
+               if (baseFidp)
+                   smb_ReleaseFID(baseFidp);
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
+                    return CM_ERROR_PATH_NOT_COVERED;
+                else
+                    return CM_ERROR_BADSHARENAME;
+            }
+#endif /* DFS_SUPPORT */
         } else
             code = 0;
         
         cm_FreeSpace(spacep);
 
-        if (baseFid != 0) {
+        if (baseFidp)
             smb_ReleaseFID(baseFidp);
-            baseFidp = 0;
-        }
 
         if (code) {
             cm_ReleaseUser(userp);
@@ -5591,8 +7613,10 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
             return code;
         }
 
-        if (!lastNamep) lastNamep = realPathp;
-        else lastNamep++;
+        if (!lastNamep)
+           lastNamep = realPathp;
+        else 
+           lastNamep++;
 
         if (!smb_IsLegalFilename(lastNamep))
             return CM_ERROR_BADNTFILENAME;
@@ -5606,19 +7630,16 @@ 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);
                 return code;
             }
         }
-    }
-    else {
-        if (baseFid != 0) {
+    } else {
+        if (baseFidp)
             smb_ReleaseFID(baseFidp);
-            baseFidp = 0;
-        }
         cm_FreeSpace(spacep);
     }
 
@@ -5628,10 +7649,10 @@ 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) {     
-            if (dscp) cm_ReleaseSCache(dscp);
+            if (dscp) 
+                cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
@@ -5640,7 +7661,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
         if (createDisp == FILE_CREATE) {
             /* oops, file shouldn't be there */
-            if (dscp) cm_ReleaseSCache(dscp);
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+            if (dscp) 
+                cm_ReleaseSCache(dscp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
@@ -5665,8 +7688,19 @@ 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) {
+                       if (dscp)
+                           cm_ReleaseSCache(dscp);
+                       if (scp)
+                           cm_ReleaseSCache(scp);
+                       cm_ReleaseUser(userp);
+                       free(realPathp);
+                       return code;
+                   }
                 }
             }
             code = cm_SetAttr(scp, &setAttr, userp, &req);
@@ -5676,13 +7710,14 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     }
     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
         /* don't create if not found */
-        if (dscp) cm_ReleaseSCache(dscp);
+        if (dscp) 
+            cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         free(realPathp);
         return CM_ERROR_NOSUCHFILE;
     }
     else if (realDirFlag == 0 || realDirFlag == -1) {
-        osi_assert(dscp != NULL);
+        osi_assertx(dscp != NULL, "null cm_scache_t");
         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
                   osi_LogSaveString(smb_logp, lastNamep));
         openAction = 2;                /* created file */
@@ -5690,11 +7725,13 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         setAttr.clientModTime = time(NULL);
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                           &req);
-        if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-            smb_NotifyChange(FILE_ACTION_ADDED,
-                              FILE_NOTIFY_CHANGE_FILE_NAME,
-                              dscp, lastNamep, NULL, TRUE);
-        if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
+        if (code == 0) {
+           created = 1;
+           if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+               smb_NotifyChange(FILE_ACTION_ADDED,
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
+                                dscp, lastNamep, NULL, TRUE);
+       } else if (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
@@ -5729,10 +7766,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                 }       
             }  /* lookup succeeded */
         }
-    }
-    else {
+    } 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));
@@ -5759,7 +7795,10 @@ 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) cm_ReleaseSCache(scp);
+       if (ldp)
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+       if (scp) 
+            cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         free(realPathp);
         return code;
@@ -5779,12 +7818,16 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                 */
                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
                           scp, targetScp);
+               if (ldp)
+                   cm_CheckNTOpenDone(scp, userp, &req, &ldp);
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
         }
 
         if (scp->fileType != CM_SCACHETYPE_FILE) {
+           if (ldp)
+               cm_CheckNTOpenDone(scp, userp, &req, &ldp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
@@ -5793,6 +7836,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 (ldp)
+           cm_CheckNTOpenDone(scp, userp, &req, &ldp);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         free(realPathp);
@@ -5801,24 +7846,85 @@ 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);
+    fidp->userp = userp;
+
+    /* If we are restricting sharing, we should do so with a suitable
+       share lock. */
+    if (scp->fileType == CM_SCACHETYPE_FILE &&
+        !(fidflags & SMB_FID_SHARE_WRITE)) {
+        cm_key_t key;
+        LARGE_INTEGER LOffset, LLength;
+        int sLockType;
+
+        LOffset.HighPart = SMB_FID_QLOCK_HIGH;
+        LOffset.LowPart = SMB_FID_QLOCK_LOW;
+        LLength.HighPart = 0;
+        LLength.LowPart = SMB_FID_QLOCK_LENGTH;
+
+        /* 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;
+        }
+
+        key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
+        
+        lock_ObtainMutex(&scp->mx);
+        code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
+        lock_ReleaseMutex(&scp->mx);
+
+        if (code) {
+           if (ldp)
+               cm_CheckNTOpenDone(scp, userp, &req, &ldp);
+            cm_ReleaseSCache(scp);
+            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 CM_ERROR_SHARING_VIOLATION;
+        }
+    }
+
+    /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
+    if (ldp)
+       cm_CheckNTOpenDone(scp, userp, &req, &ldp);
 
+    lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    lock_ObtainMutex(&scp->mx);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseMutex(&scp->mx);
+    osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
 
     fidp->flags = fidflags;
 
+    /* remember if the file was newly created */
+    if (created)
+       fidp->flags |= SMB_FID_CREATED;
+
     /* save parent dir and pathname for deletion or change notification */
     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
         fidp->flags |= SMB_FID_NTOPEN;
         fidp->NTopen_dscp = dscp;
-        cm_HoldSCache(dscp);
+       osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
+       dscp = NULL;
         fidp->NTopen_pathp = strdup(lastNamep);
     }
     fidp->NTopen_wholepathp = realPathp;
+    lock_ReleaseMutex(&fidp->mx);
 
     /* we don't need this any longer */
-    if (dscp) cm_ReleaseSCache(dscp);
+    if (dscp) 
+        cm_ReleaseSCache(dscp);
 
     cm_Open(scp, 0, userp);
 
@@ -5871,7 +7977,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
         *((USHORT *)outData) = 0; outData += 2;        /* filetype */
         *((USHORT *)outData) = 0; outData += 2;        /* dev state */
-        *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
+        *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
         outData += 2;  /* is a dir? */
         lock_ReleaseMutex(&scp->mx);
     } else {
@@ -5919,7 +8027,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
         *((USHORT *)outData) = 0; outData += 2;        /* filetype */
         *((USHORT *)outData) = 0; outData += 2;        /* dev state */
-        *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
+        *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
+                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
         outData += 1;  /* is a dir? */
         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
@@ -5927,11 +8037,20 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         lock_ReleaseMutex(&scp->mx);
     }
 
-    osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
+    lock_ObtainMutex(&scp->mx);
+    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
+         LargeIntegerGreaterThanZero(fidp->scp->length) && 
+         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
+        cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
+                           fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
+                           userp);
+    }
+    lock_ReleaseMutex(&scp->mx);
 
-    smb_ReleaseFID(fidp);
+    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 */
@@ -5942,14 +8061,15 @@ 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) {
@@ -5957,18 +8077,57 @@ 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;
+
+    /* 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;
+    osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"", 
+             fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
+    osi_Log3(smb_logp, "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_ObtainMutex(&scp->mx);
     if (watchtree)
         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
@@ -5984,16 +8143,16 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
 unsigned char nullSecurityDesc[36] = {
     0x01,                              /* security descriptor revision */
     0x00,                              /* reserved, should be zero */
-    0x00, 0x80,                        /* security descriptor control;
-    * 0x8000 : self-relative format */
+    0x00, 0x80,                                /* security descriptor control;
+                                         * 0x8000 : self-relative format */
     0x14, 0x00, 0x00, 0x00,            /* offset of owner SID */
     0x1c, 0x00, 0x00, 0x00,            /* offset of group SID */
     0x00, 0x00, 0x00, 0x00,            /* offset of DACL would go here */
     0x00, 0x00, 0x00, 0x00,            /* offset of SACL would go here */
     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    /* "null SID" owner SID */
+                                        /* "null SID" owner SID */
     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-    /* "null SID" group SID */
+                                        /* "null SID" group SID */
 };      
 
 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
@@ -6074,18 +8233,26 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* We can handle long names */
     if (vcp->flags & SMB_VCFLAG_USENT)
-        ((smb_t *)outp)->flg2 |= 0x40; /* IS_LONG_NAME */
+        ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
         
     switch (function) {
-    case 6: 
-        return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
-    case 4: 
-        return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
     case 1: 
         return smb_ReceiveNTTranCreate(vcp, inp, outp);
-    default: 
-        return CM_ERROR_INVAL;
+    case 2:
+       osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
+       break;
+    case 3:
+       osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
+       break;
+    case 4:
+        return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
+    case 5:
+       osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
+       break;
+    case 6:
+        return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
     }
+    return CM_ERROR_INVAL;
 }
 
 /*
@@ -6094,6 +8261,9 @@ 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,
@@ -6108,7 +8278,6 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
     BOOL twoEntries = FALSE;
     ULONG otherNameLen, oldParmCount = 0;
     DWORD otherAction;
-    smb_vc_t *vcp;
     smb_fid_t *fidp;
 
     /* Get ready for rename within directory */
@@ -6117,8 +8286,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_LogSaveString(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;
@@ -6126,29 +8307,31 @@ 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);
-        vcp = watch->vcp;
 
         /*
-         * 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(vcp, fid, 0);
+        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);
+        }      
+
+        if (fidp->scp != dscp ||
+            fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
+            (filter & notifyFilter) == 0 ||
+            (!isDirectParent && !wtree)) 
+        {
+            osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
             smb_ReleaseFID(fidp);
             lastWatch = watch;
             watch = watch->nextp;
@@ -6159,7 +8342,32 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
         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));
-
+       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;
@@ -6175,18 +8383,21 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
         lock_ReleaseMutex(&dscp->mx);
 
         /* Convert to response packet */
-        ((smb_t *) watch)->reb = 0x80;
+        ((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)
             parmCount = 0;
         else {
-            nameLen = strlen(filename);
+            nameLen = (ULONG)strlen(filename);
             parmCount = 3*4 + nameLen*2;
             parmCount = (parmCount + 3) & ~3;  /* pad to 4 */
             if (twoEntries) {
-                otherNameLen = strlen(otherFilename);
+                otherNameLen = (ULONG)strlen(otherFilename);
                 oldParmCount = parmCount;
                 parmCount += 3*4 + otherNameLen*2;
                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
@@ -6220,6 +8431,7 @@ 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;
@@ -6229,7 +8441,11 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             /* Action */
             *((DWORD *)outData) = nameLen*2; outData += 4;
             /* File Name Length */
-            mbstowcs((WCHAR *)outData, filename, nameLen);
+            p = strdup(filename);
+            if (smb_StoreAnsiFilenames)
+                CharToOem(p,p);
+            mbstowcs((WCHAR *)outData, p, nameLen);
+            free(p);
             /* File Name */
             if (twoEntries) {
                 outData = oldOutData + oldParmCount;
@@ -6239,8 +8455,11 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
                 /* Action */
                 *((DWORD *)outData) = otherNameLen*2;
                 outData += 4;  /* File Name Length */
-                mbstowcs((WCHAR *)outData, otherFilename,
-                          otherNameLen);       /* File Name */
+                p = strdup(otherFilename);
+                if (smb_StoreAnsiFilenames)
+                    CharToOem(p,p);
+                mbstowcs((WCHAR *)outData, p, otherNameLen);   /* File Name */
+                free(p);
             }       
         }       
 
@@ -6257,11 +8476,10 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             ((smb_t *) watch)->errLow = 0;
             ((smb_t *) watch)->errHigh = 0;
             /* Set NT Status codes flag */
-            ((smb_t *) watch)->flg2 |= 0x4000;
+            ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
         }
 
-        smb_SendPacket(vcp, watch);
-        smb_ReleaseVC(vcp);
+        smb_SendPacket(watch->vcp, watch);
         smb_FreePacket(watch);
         watch = nextWatch;
     }
@@ -6306,6 +8524,7 @@ long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                           osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
 
                 scp = fidp->scp;
+               osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
                 lock_ObtainMutex(&scp->mx);
                 if (watchtree)
                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
@@ -6326,10 +8545,8 @@ long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             ((smb_t *)watch)->reh = 0x1;
             ((smb_t *)watch)->errLow = 0;
             ((smb_t *)watch)->errHigh = 0xC0;
-            ((smb_t *)watch)->flg2 |= 0x4000;
+            ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
             smb_SendPacket(vcp, watch);
-            if (watch->vcp)
-                smb_ReleaseVC(watch->vcp);
             smb_FreePacket(watch);
             return 0;
         }
@@ -6352,9 +8569,8 @@ 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 *oldname, *newname;
+    char *oldPathp, *newPathp;
     long code = 0;
-    cm_user_t *userp;
     char * tp;
     int attrs;
     int rename_type;
@@ -6363,23 +8579,27 @@ 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);
-    oldname = smb_ParseASCIIBlock(tp, &tp);
-    newname = smb_ParseASCIIBlock(tp, &tp);
+    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, oldname),
-             osi_LogSaveString(smb_logp, newname),
+             osi_LogSaveString(smb_logp, oldPathp),
+             osi_LogSaveString(smb_logp, newPathp),
              ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
 
     if (rename_type == RENAME_FLAG_RENAME) {
-        code = smb_Rename(vcp,inp,oldname,newname,attrs);
+        code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
     } else { /* RENAME_FLAG_HARD_LINK */
-        code = smb_Link(vcp,inp,oldname,newname);
+        code = smb_Link(vcp,inp,oldPathp,newPathp);
     }
     return code;
 }
@@ -6389,22 +8609,23 @@ void smb3_Init()
     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
 }
 
-cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
+cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
 {
-    /*int newUid;*/
     smb_username_t *unp;
+    cm_user_t *     userp;
 
-    unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
+    unp = smb_FindUserByName(usern, machine, flags);
     if (!unp->userp) {
         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_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
+        osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(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_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);
-       }
-    return unp->userp;
+    }
+    userp = unp->userp;
+    cm_HoldUser(userp);
+    smb_ReleaseUsername(unp);
+    return userp;
 }