windows-afs-execute-only-20080309
[openafs.git] / src / WINNT / afsd / smb3.c
index ff8ff13..27c6e1a 100644 (file)
 #include <afs/stds.h>
 
 #include <windows.h>
+#pragma warning(push)
+#pragma warning(disable: 4005)
 #include <ntstatus.h>
 #define SECURITY_WIN32
 #include <security.h>
 #include <lmaccess.h>
+#pragma warning(pop)
 #include <stdlib.h>
 #include <malloc.h>
 #include <string.h>
@@ -39,6 +42,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)
@@ -57,6 +62,28 @@ cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
     return up;
 }
 
+/* 
+ * Return boolean specifying if the path name is thought to be an 
+ * executable file.  For now .exe or .dll.
+ */
+afs_uint32 smb_IsExecutableFileName(const char *name)
+{
+    int i, j, len;
+        
+    if ( smb_ExecutableExtensions == NULL || name == NULL)
+        return 0;
+
+    len = (int)strlen(name);
+
+    for ( i=0; smb_ExecutableExtensions[i]; i++) {
+        j = len - (int)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
@@ -132,7 +159,7 @@ void OutputDebugF(char * format, ...) {
 }
 
 void OutputDebugHexDump(unsigned char * buffer, int len) {
-    int i,j,k,pcts=0;
+    int i,j,k;
     char buf[256];
     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
 
@@ -141,7 +168,7 @@ 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));
+                osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
                 strcat(buf,"\r\n");
                 OutputDebugString(buf);
             }
@@ -157,16 +184,12 @@ void OutputDebugHexDump(unsigned char * buffer, int len) {
         buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
 
         j = (i%16);
-        j = j + 56 + ((j>7)?1:0) + pcts;
+        j = j + 56 + ((j>7)?1:0);
 
         buf[j] = (k>32 && k<127)?k:'.';
-               if (k == '%') {
-                       buf[++j] = k;
-                       pcts++;
-               }
     }    
     if(i) {
-        osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
+        osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
         strcat(buf,"\r\n");
         OutputDebugString(buf);
     }   
@@ -982,7 +1005,7 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     smb_tid_t *tidp;
     smb_user_t *uidp = NULL;
     unsigned short newTid;
-    char shareName[256];
+    char shareName[AFSPATHMAX];
     char *sharePath;
     int shareFound;
     char *tp;
@@ -1038,17 +1061,28 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
        if (!shareFound) {
            if (uidp)
                smb_ReleaseUID(uidp);
-            smb_ReleaseTID(tidp);
+            smb_ReleaseTID(tidp, FALSE);
             return CM_ERROR_BADSHARENAME;
        }
 
        if (vcp->flags & SMB_VCFLAG_USENT)
         {
             int policy = smb_FindShareCSCPolicy(shareName);
+            HKEY parmKey;
+            DWORD code;
+            DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
+
+            code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
+                                 0, KEY_QUERY_VALUE, &parmKey);
+            if (code == ERROR_SUCCESS) {
+                code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
+                                       (BYTE *)&dwAdvertiseDFS, &dwSize);
+                if (code != ERROR_SUCCESS)
+                    dwAdvertiseDFS = 0;
+                RegCloseKey (parmKey);
+            }
             smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | 
-#ifdef DFS_SUPPORT
-                            SMB_SHARE_IS_IN_DFS |
-#endif
+                           (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
                             (policy << 2));
         }
     } else {
@@ -1064,7 +1098,7 @@ long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *o
     if (ipc) 
         tidp->flags |= SMB_TIDFLAG_IPC;
     lock_ReleaseMutex(&tidp->mx);
-    smb_ReleaseTID(tidp);
+    smb_ReleaseTID(tidp, FALSE);
 
     ((smb_t *)outp)->tid = newTid;
     ((smb_t *)inp)->tid = newTid;
@@ -1434,14 +1468,14 @@ typedef struct smb_rap_share_info_1 {
 } smb_rap_share_info_1_t;
 
 typedef struct smb_rap_share_info_2 {
-    char                               shi2_netname[13];
-    char                               shi2_pad;
+    char                       shi2_netname[13];
+    char                       shi2_pad;
     unsigned short             shi2_type;
-    DWORD                              shi2_remark; /* char *shi2_remark; data offset */
+    DWORD                      shi2_remark; /* char *shi2_remark; data offset */
     unsigned short             shi2_permissions;
     unsigned short             shi2_max_uses;
     unsigned short             shi2_current_uses;
-    DWORD                              shi2_path;  /* char *shi2_path; data offset */
+    DWORD                      shi2_path;  /* char *shi2_path; data offset */
     unsigned short             shi2_passwd[9];
     unsigned short             shi2_pad2;
 } smb_rap_share_info_2_t;
@@ -1496,7 +1530,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     smb_rap_share_info_1_t * shares;
     USHORT cshare = 0;
     char * cstrp;
-    char thisShare[256];
+    char thisShare[AFSPATHMAX];
     int i,j;
     DWORD dw;
     int nonrootShares;
@@ -1655,6 +1689,11 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     DWORD allSubmount;
     LONG rv;
     long code = 0;
+    cm_scache_t *scp = NULL;
+    cm_user_t   *userp;
+    cm_req_t    req;
+
+    cm_InitReq(&req);
 
     tp = p->parmsp + 1; /* skip over function number (always 1) */
     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
@@ -1674,8 +1713,6 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     else
         return CM_ERROR_INVAL;
 
-    outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
-
     if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                           KEY_QUERY_VALUE, &hkParam);
@@ -1693,22 +1730,34 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
             shareFound = TRUE;
 
     } else {
-        rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
-                          KEY_QUERY_VALUE, &hkSubmount);
-        if (rv == ERROR_SUCCESS) {
-            rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
+        userp = smb_GetTran2User(vcp, p);
+        if (!userp) {
+            osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
+            return CM_ERROR_BADSMB;
+        }   
+        code = cm_NameI(cm_data.rootSCachep, shareName,
+                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
+                         userp, NULL, &req, &scp);
+        if (code == 0) {
+            cm_ReleaseSCache(scp);
+            shareFound = TRUE;
+        } else {
+            rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
+                              KEY_QUERY_VALUE, &hkSubmount);
             if (rv == ERROR_SUCCESS) {
-                shareFound = TRUE;
+                rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
+                if (rv == ERROR_SUCCESS) {
+                    shareFound = TRUE;
+                }
+                RegCloseKey(hkSubmount);
             }
-            RegCloseKey(hkSubmount);
         }
     }
 
-    if (!shareFound) {
-        smb_FreeTran2Packet(outp);
+    if (!shareFound)
         return CM_ERROR_BADSHARENAME;
-    }
 
+    outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
     memset(outp->datap, 0, totalData);
 
     outp->parmsp[0] = 0;
@@ -2099,7 +2148,11 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     spacep = cm_GetSpace();
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+    if (lastNamep && 
+         (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
+           stricmp(lastNamep, "\\srvsvc") == 0 ||
+           stricmp(lastNamep, "\\wkssvc") == 0 ||
+           stricmp(lastNamep, "\\ipc$") == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
@@ -2193,10 +2246,11 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         
 #ifdef DFS_SUPPORT
         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
             cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
             smb_FreeTran2Packet(outp);
-            if ( WANTS_DFS_PATHNAMES(p) )
+            if ( WANTS_DFS_PATHNAMES(p) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
                 return CM_ERROR_BADSHARENAME;
@@ -2222,10 +2276,11 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     } else {
 #ifdef DFS_SUPPORT
         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             smb_FreeTran2Packet(outp);
-            if ( WANTS_DFS_PATHNAMES(p) )
+            if ( WANTS_DFS_PATHNAMES(p) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
                 return CM_ERROR_BADSHARENAME;
@@ -2274,13 +2329,13 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         /* don't create if not found */
         if (dscp) 
             cm_ReleaseSCache(dscp);
-        osi_assert(scp == NULL);
+        osi_assertx(scp == NULL, "null cm_scache_t");
         cm_ReleaseUser(userp);
         smb_FreeTran2Packet(outp);
         return CM_ERROR_NOSUCHFILE;
     }
     else {
-        osi_assert(dscp != NULL && scp == NULL);
+        osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
         openAction = 2;        /* created file */
         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
         smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
@@ -2353,16 +2408,16 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
 
     /* now all we have to do is open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
        
     cm_HoldUser(userp);
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
     fidp->scp = scp;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     
     /* and the user */
     fidp->userp = userp;
@@ -2386,7 +2441,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     /* copy out remainder of the parms */
     parmSlot = 0;
     outp->parmsp[parmSlot++] = fidp->fid;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainRead(&scp->rw);
     if (extraInfo) {
         outp->parmsp[parmSlot++] = smb_Attributes(scp);
         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
@@ -2408,7 +2463,7 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
         outp->parmsp[parmSlot++] = 0; 
         outp->parmsp[parmSlot++] = 0; 
     }   
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseRead(&scp->rw);
     outp->totalData = 0;               /* total # of data bytes */
     outp->totalParms = parmSlot * 2;   /* shorts are two bytes */
 
@@ -2598,6 +2653,7 @@ long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
+        DebugBreak();
         return CM_ERROR_PATH_NOT_COVERED;
     }
 #endif /* DFS_SUPPORT */
@@ -2741,7 +2797,8 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 if (code == 0) {
 #ifdef DFS_SUPPORT
                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                        if ( WANTS_DFS_PATHNAMES(p) )
+                        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                        if ( WANTS_DFS_PATHNAMES(p) || pnc )
                             code = CM_ERROR_PATH_NOT_COVERED;
                         else
                             code = CM_ERROR_BADSHARENAME;
@@ -2751,8 +2808,10 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                         code = CM_ERROR_NOSUCHFILE;
                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
                         cm_buf_t *bp = buf_Find(dscp, &hzero);
-                        if (bp)
+                        if (bp) {
                             buf_Release(bp);
+                            bp = NULL;
+                        }
                         else
                             code = CM_ERROR_NOSUCHFILE;
                     }
@@ -2785,9 +2844,10 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
 #ifdef DFS_SUPPORT
     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
-        if ( WANTS_DFS_PATHNAMES(p) )
+        if ( WANTS_DFS_PATHNAMES(p) || pnc )
             code = CM_ERROR_PATH_NOT_COVERED;
         else
             code = CM_ERROR_BADSHARENAME;
@@ -2797,7 +2857,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     }
 #endif /* DFS_SUPPORT */
 
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp_mx_held = 1;
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
@@ -2805,6 +2865,8 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         
+    lock_ConvertWToR(&scp->rw);
+
     /* now we have the status in the cache entry, and everything is locked.
      * Marshall the output data.
      */
@@ -2823,7 +2885,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         goto done;
     }
     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
-       len = strlen(lastComp);
+       len = (unsigned int)strlen(lastComp);
        qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
         mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
 
@@ -2863,7 +2925,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         qpi.u.QPfileStandardInfo.reserved = 0;
 
        if (fidp) {
-           lock_ReleaseMutex(&scp->mx);
+           lock_ReleaseRead(&scp->rw);
            scp_mx_held = 0;
            lock_ObtainMutex(&fidp->mx);
            delonclose = fidp->flags & SMB_FID_DELONCLOSE;
@@ -2901,7 +2963,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
        qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
        qpi.u.QPfileAllInfo.mode = 0;
        qpi.u.QPfileAllInfo.alignmentRequirement = 0;
-       len = strlen(lastComp);
+       len = (unsigned int)strlen(lastComp);
        qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
         mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
     }
@@ -2909,7 +2971,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     /* send and free the packets */
   done:
     if (scp_mx_held)
-       lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseRead(&scp->rw);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     if (code == 0) {
@@ -2951,7 +3013,8 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        infoLevel != SMB_INFO_QUERY_ALL_EAS) {
         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
                   p->opcode, infoLevel);
-        smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
+        smb_SendTran2Error(vcp, p, opx, 
+                           infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
         return 0;
     }
 
@@ -3009,7 +3072,8 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                 if (code == 0) {
 #ifdef DFS_SUPPORT
                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                        if ( WANTS_DFS_PATHNAMES(p) )
+                        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                        if ( WANTS_DFS_PATHNAMES(p) || pnc )
                             code = CM_ERROR_PATH_NOT_COVERED;
                         else
                             code = CM_ERROR_BADSHARENAME;
@@ -3019,8 +3083,10 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                         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;
                     }
@@ -3079,19 +3145,19 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         /* lock the vnode with a callback; we need the current status
          * to determine what the new status is, in some cases.
          */
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_SyncOp(scp, NULL, userp, &req, 0,
                           CM_SCACHESYNC_GETSTATUS
                          | CM_SCACHESYNC_NEEDCALLBACK);
         if (code) {
-           lock_ReleaseMutex(&scp->mx);
+           lock_ReleaseWrite(&scp->rw);
             goto done;
         }
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-       lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseWrite(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainRead(&scp->rw);
 
         /* prepare for setattr call */
         attr.mask = CM_ATTRMASK_LENGTH;
@@ -3118,7 +3184,7 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                 attr.unixModeBits = scp->unixModeBits | 0222;
             }
         }
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseRead(&scp->rw);
        lock_ReleaseMutex(&fidp->mx);
 
         /* call setattr */
@@ -3129,7 +3195,7 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
     }               
     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
        /* we don't support EAs */
-       code = CM_ERROR_INVAL;
+       code = CM_ERROR_EAS_NOT_SUPPORTED;
     }       
 
   done:
@@ -3160,6 +3226,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     cm_scache_t *scp;
     smb_tran2QFileInfo_t qfi;
     long code = 0;
+    int  readlock = 0;
     cm_req_t req;
 
     cm_InitReq(&req);
@@ -3172,6 +3239,13 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         return 0;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return 0;
+    }
+
     infoLevel = p->parmsp[1];
     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
         responseSize = sizeof(qfi.u.QFbasicInfo);
@@ -3211,7 +3285,7 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) 
@@ -3219,6 +3293,9 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
+    lock_ConvertWToR(&scp->rw);
+    readlock = 1;
+
     /* now we have the status in the cache entry, and everything is locked.
      * Marshall the output data.
      */
@@ -3248,9 +3325,9 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         unsigned long len;
         char *name;
 
-       lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseRead(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainRead(&scp->rw);
         if (fidp->NTopen_wholepathp)
             name = fidp->NTopen_wholepathp;
         else
@@ -3264,7 +3341,10 @@ long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
     /* send and free the packets */
   done:
-    lock_ReleaseMutex(&scp->mx);
+    if (readlock)
+        lock_ReleaseRead(&scp->rw);
+    else
+        lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
@@ -3300,6 +3380,13 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
         return 0;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return 0;
+    }
+
     infoLevel = p->parmsp[1];
     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
@@ -3359,20 +3446,20 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
        /* lock the vnode with a callback; we need the current status
          * to determine what the new status is, in some cases.
          */
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_SyncOp(scp, NULL, userp, &req, 0,
                           CM_SCACHESYNC_GETSTATUS
                          | CM_SCACHESYNC_NEEDCALLBACK);
         if (code) {
-           lock_ReleaseMutex(&scp->mx);
+           lock_ReleaseWrite(&scp->rw);
             goto done;
        }
 
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-       lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseWrite(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainRead(&scp->rw);
 
         /* prepare for setattr call */
         attr.mask = 0;
@@ -3404,7 +3491,7 @@ long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
                 attr.unixModeBits = scp->unixModeBits | 0222;
             }
         }
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseRead(&scp->rw);
        lock_ReleaseMutex(&fidp->mx);
 
         /* call setattr */
@@ -3528,11 +3615,14 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     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;
+    int i, nbnLen, reqLen, refLen;
     int idx;
 
     cm_InitReq(&req);
@@ -3546,60 +3636,159 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
              maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
 
-    nbnLen = strlen(cm_NetbiosName);
-    reqLen = strlen(requestFileName);
+    nbnLen = (int)strlen(cm_NetbiosName);
+    reqLen = (int)strlen(requestFileName);
 
-    if (reqLen == nbnLen + 5 &&
-        requestFileName[0] == '\\' &&
+    if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
         !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
-        requestFileName[nbnLen+1] == '\\' &&
-        (!_strnicmp("all",&requestFileName[nbnLen+2],3) || 
-         !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
+        requestFileName[nbnLen+1] == '\\') 
     {
-        USHORT * sp;
-        struct smb_v2_referral * v2ref;
-        outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
-
-        sp = (USHORT *)outp->datap;
-        idx = 0;
-        sp[idx++] = reqLen;   /* path consumed */
-        sp[idx++] = 1;        /* number of referrals */
-        sp[idx++] = 0x03;     /* flags */
+        int found = 0;
+
+        if (!_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 = (int)(nbnLen+2 + strlen(pathName) + 1 + strlen(lastComponent));
+
+                    strcpy(referralPath, &scp->mountPointStringp[strlen("msdfs:")]);
+                    refLen = (int)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++] = reqLen + 4;  /* Referral Size */ 
-        sp[idx++] = 1;        /* Type = SMB Server */
-        sp[idx++] = 0;        /* Do not strip path consumed */
-        for ( i=0;i<=reqLen; i++ )
-            sp[i+idx] = requestFileName[i];
+            sp[idx++] = 1;        /* Version Number */
+            sp[idx++] = refLen + 4;  /* Referral Size */ 
+            sp[idx++] = 1;        /* Type = SMB Server */
+            sp[idx++] = 0;        /* Do not strip path consumed */
+            for ( i=0;i<=refLen; i++ )
+                sp[i+idx] = referralPath[i];
 #else /* DFS_VERSION_2 */
-        sp[idx++] = 2;      /* Version Number */
-        sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
-        idx += (sizeof(struct smb_v2_referral) / 2);
-        v2ref = (struct smb_v2_referral *) &sp[5];
-        v2ref->ServerType = 1;  /* SMB Server */
-        v2ref->ReferralFlags = 0x03;
-        v2ref->Proximity = 0;   /* closest */
-        v2ref->TimeToLive = 3600; /* seconds */
-        v2ref->DfsPathOffset = idx * 2;
-        v2ref->DfsAlternativePathOffset = idx * 2;
-        v2ref->NetworkAddressOffset = 0;
-        for ( i=0;i<=reqLen; i++ )
-            sp[i+idx] = requestFileName[i];
+            sp[idx++] = 2;      /* Version Number */
+            sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
+            idx += (sizeof(struct smb_v2_referral) / 2);
+            v2ref = (struct smb_v2_referral *) &sp[5];
+            v2ref->ServerType = 1;  /* SMB Server */
+            v2ref->ReferralFlags = 0x03;
+            v2ref->Proximity = 0;   /* closest */
+            v2ref->TimeToLive = 3600; /* seconds */
+            v2ref->DfsPathOffset = idx * 2;
+            v2ref->DfsAlternativePathOffset = idx * 2;
+            v2ref->NetworkAddressOffset = 0;
+            for ( i=0;i<=refLen; i++ )
+                sp[i+idx] = referralPath[i];
 #endif
+        } 
     } else {
-        userp = smb_GetTran2User(vcp, p);
-        if (!userp) {
-            osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
-            code = CM_ERROR_BADSMB;
-            goto done;
-        }   
-
-               /* not done yet */
         code = CM_ERROR_NOSUCHPATH;
     }
-
+         
   done:
+    if (dscp)
+        cm_ReleaseSCache(dscp);
+    if (scp)
+        cm_ReleaseSCache(scp);
     if (userp)
         cm_ReleaseUser(userp);
     if (code == 0) 
@@ -3612,7 +3801,7 @@ smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     return 0;
 #else /* DFS_SUPPORT */
     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
-    return CM_ERROR_BADOP;
+    return CM_ERROR_NOSUCHDEVICE;
 #endif /* DFS_SUPPORT */
 }
 
@@ -3632,10 +3821,11 @@ smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_
     return CM_ERROR_BADOP;
 }
 
-long 
-smb_ApplyV3DirListPatches(cm_scache_t *dscp,
-       smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
-       cm_req_t *reqp)
+static long 
+smb_ApplyV3DirListPatches(cm_scache_t *dscp,smb_dirListPatch_t **dirPatchespp, 
+                          char * tidPathp, char * relPathp, 
+                          int infoLevel, cm_user_t *userp,
+                          cm_req_t *reqp)
 {
     long code = 0;
     cm_scache_t *scp;
@@ -3650,15 +3840,16 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
     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);
+        lock_ObtainWrite(&dscp->rw);
         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        lock_ReleaseMutex(&dscp->mx);
+        lock_ReleaseWrite(&dscp->rw);
         if (code == CM_ERROR_NOACCESS) {
             mustFake = 1;
             code = 0;
@@ -3669,16 +3860,21 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
 
     for(patchp = *dirPatchespp; patchp; patchp =
          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+        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);
+        lock_ObtainWrite(&scp->rw);
         if (mustFake == 0)
             code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         if (mustFake || code) { 
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
 
             dptr = patchp->dptr;
 
@@ -3792,8 +3988,12 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
         /* now watch for a symlink */
         code = 0;
         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
+            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,
@@ -3804,9 +4004,11 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
                 cm_ReleaseSCache(scp);
                 scp = targetScp;
             }
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
         }
 
+        lock_ConvertWToR(&scp->rw);
+
         dptr = patchp->dptr;
 
         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
@@ -3837,7 +4039,8 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
 
             /* Copy attributes */
             lattr = smb_ExtAttributes(scp);
-            if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
+            if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
+                code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
                 if (lattr == SMB_ATTR_NORMAL)
                     lattr = SMB_ATTR_DIRECTORY;
                 else
@@ -3907,7 +4110,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
             *dptr++ = (attr >> 8) & 0xff;
         }
 
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseRead(&scp->rw);
         cm_ReleaseSCache(scp);
     }
         
@@ -3923,7 +4126,6 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
     return code;
 }
 
-#ifndef USE_OLD_MATCHING
 // char table for case insensitive comparison
 char mapCaseTable[256];
 
@@ -4047,145 +4249,6 @@ int smb_V3MatchMask(char *namep, char *maskp, int flags)
     return retval;
 }
 
-#else /* USE_OLD_MATCHING */
-/* do a case-folding search of the star name mask with the name in namep.
- * Return 1 if we match, otherwise 0.
- */
-int smb_V3MatchMask(char *namep, char *maskp, int flags)
-{
-    unsigned char tcp1, tcp2;  /* Pattern characters */
-    unsigned char tcn1;                /* Name characters */
-    int sawDot = 0, sawStar = 0, req8dot3 = 0;
-    char *starNamep, *starMaskp;
-    static char nullCharp[] = {0};
-    int casefold = flags & CM_FLAG_CASEFOLD;
-
-    /* make sure we only match 8.3 names, if requested */
-    req8dot3 = (flags & CM_FLAG_8DOT3);
-    if (req8dot3 && !cm_Is8Dot3(namep)) 
-        return 0;
-
-    /* loop */
-    while (1) {
-        /* Next pattern character */
-        tcp1 = *maskp++;
-
-        /* Next name character */
-        tcn1 = *namep;
-
-        if (tcp1 == 0) {
-            /* 0 - end of pattern */
-            if (tcn1 == 0)
-                return 1;
-            else
-                return 0;
-        }
-        else if (tcp1 == '.' || tcp1 == '"') {
-            if (sawDot) {
-                if (tcn1 == '.') {
-                    namep++;
-                    continue;
-                } else
-                    return 0;
-            }
-            else {
-                /*
-                 * first dot in pattern;
-                 * must match dot or end of name
-                 */
-                sawDot = 1;
-                if (tcn1 == 0)
-                    continue;
-                else if (tcn1 == '.') {
-                    sawStar = 0;
-                    namep++;
-                    continue;
-                }
-                else
-                    return 0;
-            }
-        }
-        else if (tcp1 == '?') {
-            if (tcn1 == 0 || tcn1 == '.')
-                return 0;
-            namep++;
-            continue;
-        }
-        else if (tcp1 == '>') {
-            if (tcn1 != 0 && tcn1 != '.')
-                namep++;
-            continue;
-        }
-        else if (tcp1 == '*' || tcp1 == '<') {
-            tcp2 = *maskp++;
-            if (tcp2 == 0)
-                return 1;
-            else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
-                while (req8dot3 && tcn1 != '.' && tcn1 != 0)
-                    tcn1 = *++namep;
-                if (tcn1 == 0) {
-                    if (sawDot)
-                        return 0;
-                    else
-                        continue;
-                }
-                else {
-                    namep++;
-                    continue;
-                }
-            }
-            else {
-                /*
-                 * pattern character after '*' is not null or
-                 * period.  If it is '?' or '>', we are not
-                 * going to understand it.  If it is '*' or
-                 * '<', we are going to skip over it.  None of
-                 * these are likely, I hope.
-                 */
-                /* skip over '*' and '<' */
-                while (tcp2 == '*' || tcp2 == '<')
-                    tcp2 = *maskp++;
-
-                /* skip over characters that don't match tcp2 */
-                while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
-                        ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
-                          (!casefold && tcn1 != tcp2)))
-                    tcn1 = *++namep;
-
-                /* No match */
-                if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
-                    return 0;
-
-                /* Remember where we are */
-                sawStar = 1;
-                starMaskp = maskp;
-                starNamep = namep;
-
-                namep++;
-                continue;
-            }
-        }
-        else {
-            /* tcp1 is not a wildcard */
-            if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
-                 (!casefold && tcn1 == tcp1)) {
-                /* they match */
-                namep++;
-                continue;
-            }
-            /* if trying to match a star pattern, go back */
-            if (sawStar) {
-                maskp = starMaskp - 2;
-                namep = starNamep + 1;
-                sawStar = 0;
-                continue;
-            }
-            /* that's all */
-            return 0;
-        }
-    }
-}
-#endif /* USE_OLD_MATCHING */
 
 /* smb_ReceiveTran2SearchDir implements both 
  * Tran2_Find_First and Tran2_Find_Next
@@ -4210,7 +4273,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     int attribute;
     long nextCookie;
     long code = 0, code2 = 0;
-    char *pathp;
+    char *pathp = 0;
     int maxCount;
     smb_dirListPatch_t *dirListPatchesp;
     smb_dirListPatch_t *curPatchp;
@@ -4231,18 +4294,19 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     int searchFlags;
     int eos;
     smb_tran2Packet_t *outp;           /* response packet */
-    char *tidPathp;
+    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;
 
     cm_InitReq(&req);
 
     eos = 0;
-    osi_assert(p->opcode == 1);
+    osi_assertx(p->opcode == 1, "invalid opcode");
 
     /* find first; obtain basic parameters from request */
 
@@ -4361,9 +4425,10 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
        cm_ReleaseSCache(scp);
        cm_ReleaseUser(userp);
-       if ( WANTS_DFS_PATHNAMES(p) )
+        if ( WANTS_DFS_PATHNAMES(p) || pnc )
            code = CM_ERROR_PATH_NOT_COVERED;
        else
            code = CM_ERROR_BADSHARENAME;
@@ -4476,7 +4541,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
         ohbytes += 4;           /* EASIZE */
 
     /* add header to name & term. null */
-    onbytes = strlen(maskp);
+    onbytes = (int)strlen(maskp);
     orbytes = ohbytes + onbytes + 1;
 
     /* now, we round up the record to a 4 byte alignment, and we make
@@ -4548,13 +4613,14 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
             curPatchp->flags = 0;
         }
 
-        curPatchp->fid.cell = targetscp->fid.cell;
-        curPatchp->fid.volume = targetscp->fid.volume;
-        curPatchp->fid.vnode = targetscp->fid.vnode;
-        curPatchp->fid.unique = targetscp->fid.unique;
+        cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
 
         /* temp */
-        curPatchp->dep = NULL;
+        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) {
@@ -4573,7 +4639,7 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
     }
 
     /* apply the patches */
-    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
+    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->data, infoLevel, userp, &req);
 
     outp->parmsp[0] = 0;
     outp->parmsp[1] = 1;        /* number of names returned */
@@ -4597,6 +4663,9 @@ long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op
 
  skip_file:
     smb_FreeTran2Packet(outp);
+    if (dep)
+        free(dep);
+    if (scp)
     cm_ReleaseSCache(scp);
     cm_ReleaseSCache(targetscp);
     cm_ReleaseUser(userp);
@@ -4612,10 +4681,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     char *tp;
     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 */
@@ -4690,9 +4759,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             /* we only failover if we see a CM_ERROR_NOSUCHFILE */
             if (code != CM_ERROR_NOSUCHFILE) {
 #ifdef USE_BPLUS
+                /* unless we are using the BPlusTree */
                 if (code == CM_ERROR_BPLUS_NOMATCH)
                     code = CM_ERROR_NOSUCHFILE;
-#endif
+#endif /* USE_BPLUS */
                 return code;
             }
         }
@@ -4704,7 +4774,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         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]);
         maxCount = p->parmsp[1];
@@ -4823,6 +4893,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             smb_ReleaseDirSearch(dsp);
             return 0;
         }
+
+        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);
@@ -4831,9 +4905,10 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         if (code == 0) {
 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+                int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
                 cm_ReleaseSCache(scp);
                 cm_ReleaseUser(userp);
-                if ( WANTS_DFS_PATHNAMES(p) )
+                if ( WANTS_DFS_PATHNAMES(p) || pnc )
                     code = CM_ERROR_PATH_NOT_COVERED;
                 else
                     code = CM_ERROR_BADSHARENAME;
@@ -4854,13 +4929,13 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
              * and so we do another hold now.
              */
             cm_HoldSCache(scp);
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
                  LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
                 dsp->flags |= SMB_DIRSEARCH_BULKST;
             }
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
         } 
     }
     lock_ReleaseMutex(&dsp->mx);
@@ -4873,11 +4948,11 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     }
 
     /* get the directory size */
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) {
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         smb_FreeTran2Packet(outp);
@@ -4959,20 +5034,17 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 buf_Release(bufferp);
                 bufferp = NULL;
             }       
-            lock_ReleaseMutex(&scp->mx);
-            lock_ObtainRead(&scp->bufCreateLock);
+            lock_ReleaseWrite(&scp->rw);
             code = buf_Get(scp, &thyper, &bufferp);
-            lock_ReleaseRead(&scp->bufCreateLock);
             lock_ObtainMutex(&dsp->mx);
 
             /* now, if we're doing a star match, do bulk fetching
              * of all of the status info for files in the dir.
              */
             if (starPattern) {
-                smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
-                                           infoLevel, userp,
-                                           &req);
-                lock_ObtainMutex(&scp->mx);
+                code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, infoLevel, userp, &req);
+                
+                lock_ObtainWrite(&scp->rw);
                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
                     LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
                     /* Don't bulk stat if risking timeout */
@@ -4985,7 +5057,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                         code = cm_TryBulkStat(scp, &thyper, userp, &req);
                 }
             } else {
-                lock_ObtainMutex(&scp->mx);
+                lock_ObtainWrite(&scp->rw);
             }
             lock_ReleaseMutex(&dsp->mx);
             if (code) {
@@ -5071,51 +5143,49 @@ 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 == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
-             && 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),
+                  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)) {
                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
                 goto nextEntry; /* no hidden files */
             }
+        
             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
             {
                 /* We have already done the cm_TryBulkStat above */
-                fid.cell = scp->fid.cell;
-                fid.volume = scp->fid.volume;
-                fid.vnode = ntohl(dep->fid.vnode);
-                fid.unique = ntohl(dep->fid.unique);
+                cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
                 fileType = cm_FindFileType(&fid);
-                /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
-                 "has filetype %d", dep->name,
-                 fileType);*/
-                if (fileType == CM_SCACHETYPE_DIRECTORY ||
-                    fileType == CM_SCACHETYPE_MOUNTPOINT ||
-                    fileType == CM_SCACHETYPE_DFSLINK ||
-                    fileType == CM_SCACHETYPE_INVALID)
+                /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
+                 * "has filetype %d", dep->name, fileType);
+                 */
+                if ( fileType == CM_SCACHETYPE_DIRECTORY ||
+                     fileType == CM_SCACHETYPE_MOUNTPOINT ||
+                     fileType == CM_SCACHETYPE_DFSLINK ||
+                     fileType == CM_SCACHETYPE_INVALID)
                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
-                    goto nextEntry;
+                goto nextEntry;
             }
 
             /* finally check if this name will fit */
@@ -5135,9 +5205,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 ohbytes += 4;  /* if resume key required */
             }   
 
-            if (infoLevel != SMB_INFO_STANDARD
-                 && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
-                 && infoLevel != SMB_FIND_FILE_NAMES_INFO)
+            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 */
@@ -5146,7 +5216,7 @@ 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 >= SMB_FIND_FILE_DIRECTORY_INFO)
@@ -5156,8 +5226,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             if (orbytes + bytesInBuffer + align > maxReturnData) {
                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
                           maxReturnData);
-                break;
-            }
+                break;      
+            }       
 
             /* this is one of the entries to use: it is not deleted
              * and it matches the star pattern we're looking for.
@@ -5211,8 +5281,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
              */
             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 >= SMB_FIND_FILE_DIRECTORY_INFO)
                     curPatchp->dptr += 8;
@@ -5223,10 +5292,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 else    
                     curPatchp->flags = 0;
 
-                curPatchp->fid.cell = scp->fid.cell;
-                curPatchp->fid.volume = scp->fid.volume;
-                curPatchp->fid.vnode = ntohl(dep->fid.vnode);
-                curPatchp->fid.unique = ntohl(dep->fid.unique);
+                cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
 
                 /* temp */
                 curPatchp->dep = dep;
@@ -5247,13 +5313,12 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             }
         }      /* if we're including this name */
         else if (!starPattern &&
-                 !foundInexact &&
-                 dep->fid.vnode != 0 &&
-                 smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
+                  !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;
@@ -5273,7 +5338,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     }
 
     /* release the mutex */
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     if (bufferp) {
         buf_Release(bufferp);
        bufferp = NULL;
@@ -5282,9 +5347,9 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     /* 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.
      */
-    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
-                              &req);
-        
+    code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath, 
+                                      dsp->relPath, infoLevel, userp, &req);
+
     /* now put out the final parameters */
     if (returnedNames == 0) 
         eos = 1;
@@ -5424,7 +5489,11 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+    if (lastNamep && 
+         (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
+           stricmp(lastNamep, "\\srvsvc") == 0 ||
+           stricmp(lastNamep, "\\wkssvc") == 0 ||
+           stricmp(lastNamep, "ipc$") == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
@@ -5487,9 +5556,10 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
 #ifdef DFS_SUPPORT
     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
-        if ( WANTS_DFS_PATHNAMES(inp) )
+        if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
             return CM_ERROR_BADSHARENAME;
@@ -5507,9 +5577,10 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
 #ifdef DFS_SUPPORT
         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
             cm_ReleaseSCache(dscp);
             cm_ReleaseUser(userp);
-            if ( WANTS_DFS_PATHNAMES(inp) )
+            if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
                 return CM_ERROR_BADSHARENAME;
@@ -5571,7 +5642,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_NOSUCHFILE;
     }
     else {
-        osi_assert(dscp != NULL);
+        osi_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 */
@@ -5626,15 +5697,15 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* now all we have to do is open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
        
     cm_HoldUser(userp);
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
     fidp->scp = scp;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
     /* also the user */
     fidp->userp = userp;
@@ -5660,7 +5731,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* copy out remainder of the parms */
     parmSlot = 2;
     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainRead(&scp->rw);
     if (extraInfo) {
         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
@@ -5678,7 +5749,7 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseRead(&scp->rw);
     smb_SetSMBDataLength(outp, 0);
 
     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
@@ -5723,7 +5794,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_scache_t *scp;
     unsigned char LockType;
     unsigned short NumberOfUnlocks, NumberOfLocks;
-    long Timeout;
+    afs_uint32 Timeout;
     char *op;
     char *op_locks;
     LARGE_INTEGER LOffset, LLength;
@@ -5743,6 +5814,12 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
@@ -5761,7 +5838,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     userp = smb_GetUserFromVCP(vcp, inp);
 
 
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK
                         | CM_SCACHESYNC_GETSTATUS
@@ -5784,18 +5861,9 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LockType |= LOCKING_ANDX_SHARED_LOCK;
     }
 
-    if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
-        (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
-
-        /* We don't support these requests.  Apparently, we can safely
-           not deal with them too. */
-        osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
-                 ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
-                  "LOCKING_ANDX_CANCEL_LOCK":
-                  "LOCKING_ANDX_CHANGE_LOCKTYPE")); 
-        /* No need to call osi_LogSaveString since these are string
-           constants.*/
-
+    if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
+        /* AFS does not support atomic changes of lock types from read or write and vice-versa */
+        osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]"); 
         code = CM_ERROR_BADOP;
         goto done;
 
@@ -5803,6 +5871,35 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     op = smb_GetSMBData(inp, NULL);
 
+    if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
+        /* Cancel outstanding lock requests */
+        smb_waitingLock_t * wl;
+
+        for (i=0; i<NumberOfLocks; i++) {
+            smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
+
+            key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
+
+            lock_ObtainWrite(&smb_globalLock);
+            for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
+            {
+                for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
+                    if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) && 
+                        LargeIntegerEqualTo(wl->LLength, LLength)) {
+                        wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
+                        goto found_lock_request;
+                    }
+                }
+            }
+          found_lock_request:
+            lock_ReleaseWrite(&smb_globalLock);
+        }
+        code = 0;
+        smb_SetSMBDataLength(outp, 0);
+        goto done;
+    }
+
+
     for (i=0; i<NumberOfUnlocks; i++) {
         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
 
@@ -5843,7 +5940,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
 
-                osi_assert(wlRequest != NULL);
+                osi_assertx(wlRequest != NULL, "null wlRequest");
 
                 wlRequest->vcp = vcp;
                 smb_HoldVC(vcp);
@@ -5853,7 +5950,8 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                 wlRequest->inp = smb_CopyPacket(inp);
                 wlRequest->outp = smb_CopyPacket(outp);
                 wlRequest->lockType = LockType;
-                wlRequest->timeRemaining = Timeout;
+                wlRequest->msTimeout = Timeout;
+                wlRequest->start_t = osi_Time();
                 wlRequest->locks = NULL;
 
                 /* The waiting lock request needs to have enough
@@ -5874,7 +5972,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
                     wLock = malloc(sizeof(smb_waitingLock_t));
 
-                    osi_assert(wLock != NULL);
+                    osi_assertx(wLock != NULL, "null smb_waitingLock_t");
 
                     wLock->key = tkey;
                     wLock->LOffset = tOffset;
@@ -5888,7 +5986,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
             wLock = malloc(sizeof(smb_waitingLock_t));
 
-            osi_assert(wLock != NULL);
+            osi_assertx(wLock != NULL, "null smb_waitingLock_t");
 
             wLock->key = key;
             wLock->LOffset = LOffset;
@@ -5973,7 +6071,7 @@ long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
 
   doneSync:
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
@@ -5990,6 +6088,7 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     afs_uint32 searchTime;
     cm_user_t *userp;
     cm_req_t req;
+    int readlock = 0;
 
     cm_InitReq(&req);
 
@@ -6000,6 +6099,12 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -6015,7 +6120,7 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         
         
     /* otherwise, stat the file */
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) 
@@ -6023,6 +6128,8 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
+    lock_ConvertWToR(&scp->rw);
+
     /* decode times.  We need a search time, but the response to this
      * call provides the date first, not the time, as returned in the
      * searchTime variable.  So we take the high-order bits first.
@@ -6049,7 +6156,10 @@ long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     code = 0;
 
   done:
-    lock_ReleaseMutex(&scp->mx);
+    if (readlock) 
+        lock_ReleaseRead(&scp->rw);
+    else
+        lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     smb_ReleaseFID(fidp);
@@ -6077,6 +6187,12 @@ long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -6126,6 +6242,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     unsigned short fd;
     unsigned pid;
     smb_fid_t *fidp;
+    smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
     char *op;
@@ -6163,6 +6280,12 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!fidp)
         return CM_ERROR_BADFD;
         
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -6184,7 +6307,7 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LARGE_INTEGER LLength;
         cm_scache_t * scp;
 
-        pid = ((smb_t *) inp)->pid;
+        pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
         LOffset.HighPart = offset.HighPart;
@@ -6193,9 +6316,9 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.LowPart = count;
 
         scp = fidp->scp;
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
 
         if (code)
             goto done;
@@ -6231,8 +6354,6 @@ long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         written = 0;
     }
 
- done_writing:
-    
     /* slots 0 and 1 are reserved for request chaining and will be
        filled in when we return. */
     smb_SetSMBParm(outp, 2, total_written);
@@ -6256,6 +6377,7 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     unsigned short fd;
     unsigned pid;
     smb_fid_t *fidp;
+    smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
     cm_key_t key;
@@ -6296,7 +6418,13 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADFD;
     }
 
-    pid = ((smb_t *) inp)->pid;
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
+    pid = smbp->pid;
     key = cm_GenerateKey(vcp->vcID, pid, fd);
     {
         LARGE_INTEGER LOffset, LLength;
@@ -6308,9 +6436,9 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.LowPart = count;
 
         scp = fidp->scp;
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_LockCheckRead(scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
     }
 
     if (code) {
@@ -6506,7 +6634,11 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
 
-    if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+       if (lastNamep && 
+             (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
+               stricmp(lastNamep, "\\srvsvc") == 0 ||
+               stricmp(lastNamep, "\\wkssvc") == 0 ||
+               stricmp(lastNamep, "ipc$") == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
@@ -6585,6 +6717,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;
     }
@@ -6595,7 +6736,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     fidflags = 0;
     if (desiredAccess & DELETE)
         fidflags |= SMB_FID_OPENDELETE;
-    if (desiredAccess & AFS_ACCESS_READ)
+    if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
         fidflags |= SMB_FID_OPENREAD_LISTDIR;
     if (desiredAccess & AFS_ACCESS_WRITE)
         fidflags |= SMB_FID_OPENWRITE;
@@ -6605,6 +6746,8 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        fidflags |= SMB_FID_SEQUENTIAL;
     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
        fidflags |= SMB_FID_RANDOM;
+    if (smb_IsExecutableFileName(lastNamep))
+        fidflags |= SMB_FID_EXECUTABLE;
 
     /* and the share mode */
     if (shareAccess & FILE_SHARE_READ)
@@ -6624,12 +6767,13 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         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) )
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
                     return CM_ERROR_BADSHARENAME;
@@ -6657,12 +6801,13 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                         userp, tidPathp, &req, &scp);
 #ifdef DFS_SUPPORT
         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
            if (baseFidp) 
                smb_ReleaseFID(baseFidp);
-            if ( WANTS_DFS_PATHNAMES(inp) )
+            if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
                 return CM_ERROR_BADSHARENAME;
@@ -6693,6 +6838,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
 #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);
@@ -6700,7 +6846,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                     free(realPathp);
                    if (baseFidp) 
                        smb_ReleaseFID(baseFidp);
-                    if ( WANTS_DFS_PATHNAMES(inp) )
+                    if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                         return CM_ERROR_PATH_NOT_COVERED;
                     else
                         return CM_ERROR_BADSHARENAME;
@@ -6837,7 +6983,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             code = 0;
             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
                 targetScp = 0;
-                osi_assert(dscp != NULL);
+                osi_assertx(dscp != NULL, "null cm_scache_t");
                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
                 if (code == 0) {
                     /* we have a more accurate file to use (the
@@ -6877,7 +7023,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         free(realPathp);
         return CM_ERROR_NOSUCHFILE;
     } else if (realDirFlag == 0 || realDirFlag == -1) {
-        osi_assert(dscp != NULL);
+        osi_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 */
@@ -6935,7 +7081,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         /* create directory */
         if ( !treeCreate ) 
             treeStartp = lastNamep;
-        osi_assert(dscp != NULL);
+        osi_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 */
@@ -7071,7 +7217,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
 
     /* save a reference to the user */
     cm_HoldUser(userp);
@@ -7091,7 +7237,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
 
         /* If we are not opening the file for writing, then we don't
-           try to get an exclusive lock.  Noone else should be able to
+           try to get an exclusive lock.  No one else should be able to
            get an exclusive lock on the file anyway, although someone
            else can get a shared lock. */
         if ((fidflags & SMB_FID_SHARE_READ) ||
@@ -7103,9 +7249,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
         
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
 
         if (code) {
            if (ldp)
@@ -7129,9 +7275,9 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
 
     fidp->flags = fidflags;
@@ -7164,7 +7310,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* out parms */
     parmSlot = 2;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainRead(&scp->rw);
     smb_SetSMBParmByte(outp, parmSlot, 0);     /* oplock */
     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
     smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
@@ -7183,9 +7329,17 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                         (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
                         scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
                         scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
-    lock_ReleaseMutex(&scp->mx);
     smb_SetSMBDataLength(outp, 0);
 
+    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_ReleaseRead(&scp->rw);
+
     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
               osi_LogSaveString(smb_logp, realPathp));
 
@@ -7367,8 +7521,17 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
            osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
             free(realPathp);
             cm_ReleaseUser(userp);
-            return CM_ERROR_INVAL;
+            return CM_ERROR_BADFD;
         }       
+
+        if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+            free(realPathp);
+            cm_ReleaseUser(userp);
+           smb_CloseFID(vcp, baseFidp, NULL, 0);
+            smb_ReleaseFID(baseFidp);
+            return CM_ERROR_NOSUCHPATH;
+        }
+
         baseDirp = baseFidp->scp;
         tidPathp = NULL;
     }
@@ -7377,7 +7540,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     fidflags = 0;
     if (desiredAccess & DELETE)
         fidflags |= SMB_FID_OPENDELETE;
-    if (desiredAccess & AFS_ACCESS_READ)
+    if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
         fidflags |= SMB_FID_OPENREAD_LISTDIR;
     if (desiredAccess & AFS_ACCESS_WRITE)
         fidflags |= SMB_FID_OPENWRITE;
@@ -7387,6 +7550,8 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
        fidflags |= SMB_FID_SEQUENTIAL;
     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
        fidflags |= SMB_FID_RANDOM;
+    if (smb_IsExecutableFileName(lastNamep))
+        fidflags |= SMB_FID_EXECUTABLE;
 
     /* And the share mode */
     if (shareAccess & FILE_SHARE_READ)
@@ -7404,12 +7569,13 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         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) )
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
                     return CM_ERROR_BADSHARENAME;
@@ -7437,12 +7603,13 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                         userp, tidPathp, &req, &scp);
 #ifdef DFS_SUPPORT
         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
+            int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
             cm_ReleaseSCache(scp);
             cm_ReleaseUser(userp);
             free(realPathp);
            if (baseFidp)
                smb_ReleaseFID(baseFidp);
-            if ( WANTS_DFS_PATHNAMES(inp) )
+            if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                 return CM_ERROR_PATH_NOT_COVERED;
             else
                 return CM_ERROR_BADSHARENAME;
@@ -7461,12 +7628,13 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                              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) )
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
                     return CM_ERROR_BADSHARENAME;
@@ -7590,7 +7758,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         return CM_ERROR_NOSUCHFILE;
     }
     else if (realDirFlag == 0 || realDirFlag == -1) {
-        osi_assert(dscp != NULL);
+        osi_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 */
@@ -7641,7 +7809,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         }
     } else {
         /* create directory */
-        osi_assert(dscp != NULL);
+        osi_assertx(dscp != NULL, "null cm_scache_t");
         osi_Log1(smb_logp,
                   "smb_ReceiveNTTranCreate creating directory %s",
                   osi_LogSaveString(smb_logp, lastNamep));
@@ -7719,7 +7887,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
     /* open the file itself */
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
 
     /* save a reference to the user */
     cm_HoldUser(userp);
@@ -7749,9 +7917,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
         
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
 
         if (code) {
            if (ldp)
@@ -7773,9 +7941,9 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     lock_ObtainMutex(&fidp->mx);
     /* save a pointer to the vnode */
     fidp->scp = scp;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
 
     fidp->flags = fidflags;
@@ -7832,7 +8000,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
         smb_SetSMBDataLength(outp, 70);
 
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainRead(&scp->rw);
         outData = smb_GetSMBData(outp, NULL);
         outData++;                     /* round to get to parmOffset */
         *outData = 0; outData++;       /* oplock */
@@ -7854,7 +8022,6 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                                scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
                                scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
         outData += 2;  /* is a dir? */
-        lock_ReleaseMutex(&scp->mx);
     } else {
         /* out parms */
         parmOffset = 8*4 + 39;
@@ -7882,7 +8049,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         smb_SetSMBParmByte(outp, parmSlot, 0); /* Setup Count */
         smb_SetSMBDataLength(outp, 105);
         
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainRead(&scp->rw);
         outData = smb_GetSMBData(outp, NULL);
         outData++;                     /* round to get to parmOffset */
         *outData = 0; outData++;       /* oplock */
@@ -7907,9 +8074,17 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
-        lock_ReleaseMutex(&scp->mx);
     }
 
+    if ((fidp->flags & SMB_FID_EXECUTABLE) && 
+         LargeIntegerGreaterThanZero(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_ReleaseRead(&scp->rw);
+
     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
 
     cm_ReleaseUser(userp);
@@ -7940,6 +8115,12 @@ 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.
      */
@@ -7985,12 +8166,12 @@ long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
     if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
        osi_Log0(smb_logp, "      Notify Change Stream Write");
 
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     if (watchtree)
         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
     else
         scp->flags |= CM_SCACHEFLAG_WATCHED;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     smb_ReleaseFID(fidp);
 
     outp->flags |= SMB_PACKETFLAG_NOSEND;
@@ -8108,6 +8289,12 @@ long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        break;
     case 6:
         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
+    case 7:
+        osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
+        break;
+    case 8:
+        osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
+        break;
     }
     return CM_ERROR_INVAL;
 }
@@ -8181,10 +8368,13 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             lastWatch = watch;
             watch = watch->nextp;
             continue;
-        }       
-        if (fidp->scp != dscp
-             || (filter & notifyFilter) == 0
-             || (!isDirectParent && !wtree)) {
+        }      
+
+        if (fidp->scp != dscp ||
+            fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
+            (filter & notifyFilter) == 0 ||
+            (!isDirectParent && !wtree)) 
+        {
             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
             smb_ReleaseFID(fidp);
             lastWatch = watch;
@@ -8229,15 +8419,18 @@ void smb_NotifyChange(DWORD action, DWORD notifyFilter,
             lastWatch->nextp = nextWatch;
 
         /* Turn off WATCHED flag in dscp */
-        lock_ObtainMutex(&dscp->mx);
+        lock_ObtainWrite(&dscp->rw);
         if (wtree)
             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
         else
             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
-        lock_ReleaseMutex(&dscp->mx);
+        lock_ReleaseWrite(&dscp->rw);
 
         /* Convert to response packet */
-        ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
+        ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
+#ifdef SEND_CANONICAL_PATHNAMES
+        ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
+#endif
         ((smb_t *) watch)->wct = 0;
 
         /* out parms */
@@ -8376,12 +8569,12 @@ long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
                 scp = fidp->scp;
                osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
-                lock_ObtainMutex(&scp->mx);
+                lock_ObtainWrite(&scp->rw);
                 if (watchtree)
                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
                 else
                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
-                lock_ReleaseMutex(&scp->mx);
+                lock_ReleaseWrite(&scp->rw);
                 smb_ReleaseFID(fidp);
             } else {
                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);