windows-afs-execute-only-20080309
[openafs.git] / src / WINNT / afsd / smb3.c
index ca6f2c0..27c6e1a 100644 (file)
@@ -73,10 +73,10 @@ afs_uint32 smb_IsExecutableFileName(const char *name)
     if ( smb_ExecutableExtensions == NULL || name == NULL)
         return 0;
 
-    len = strlen(name);
+    len = (int)strlen(name);
 
     for ( i=0; smb_ExecutableExtensions[i]; i++) {
-        j = len - strlen(smb_ExecutableExtensions[i]);
+        j = len - (int)strlen(smb_ExecutableExtensions[i]);
         if (_stricmp(smb_ExecutableExtensions[i], &name[j]) == 0)
             return 1;
     }
@@ -168,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);
             }
@@ -189,7 +189,7 @@ void OutputDebugHexDump(unsigned char * buffer, int len) {
         buf[j] = (k>32 && k<127)?k:'.';
     }    
     if(i) {
-        osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
+        osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
         strcat(buf,"\r\n");
         OutputDebugString(buf);
     }   
@@ -1061,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 {
@@ -1087,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;
@@ -1457,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;
@@ -1678,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 */
@@ -1697,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);
@@ -1716,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;
@@ -2122,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).
          */
@@ -2216,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;
@@ -2245,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;
@@ -2383,9 +2415,9 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     /* 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;
@@ -2409,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);
@@ -2431,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 */
 
@@ -2621,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 */
@@ -2764,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;
@@ -2810,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;
@@ -2822,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);
@@ -2830,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.
      */
@@ -2848,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);
 
@@ -2888,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;
@@ -2926,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);
     }
@@ -2934,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) {
@@ -2976,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;
     }
 
@@ -3034,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;
@@ -3106,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;
@@ -3145,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 */
@@ -3156,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:
@@ -3187,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);
@@ -3245,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) 
@@ -3253,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.
      */
@@ -3282,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
@@ -3298,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);
@@ -3400,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;
@@ -3445,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 */
@@ -3569,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);
@@ -3587,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) 
@@ -3653,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 */
 }
 
@@ -3673,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;
@@ -3691,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;
@@ -3710,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;
 
@@ -3833,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,
@@ -3845,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) {
@@ -3878,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
@@ -3948,7 +4110,7 @@ smb_ApplyV3DirListPatches(cm_scache_t *dscp,
             *dptr++ = (attr >> 8) & 0xff;
         }
 
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseRead(&scp->rw);
         cm_ReleaseSCache(scp);
     }
         
@@ -4111,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;
@@ -4132,11 +4294,12 @@ 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;
 
@@ -4262,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;
@@ -4377,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
@@ -4449,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) {
@@ -4474,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 */
@@ -4498,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);
@@ -4513,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 */
@@ -4725,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);
@@ -4733,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;
@@ -4756,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);
@@ -4775,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);
@@ -4861,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 */
@@ -4887,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) {
@@ -5005,10 +5175,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             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);
@@ -5125,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;
@@ -5174,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;
@@ -5183,8 +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;
@@ -5324,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).
          */
@@ -5387,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;
@@ -5407,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;
@@ -5532,9 +5703,9 @@ long smb_ReceiveV3OpenX(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;
-    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;
@@ -5560,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);
@@ -5578,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);
@@ -5623,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;
@@ -5667,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
@@ -5690,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;
 
@@ -5709,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);
 
@@ -5759,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
@@ -5879,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);
@@ -5896,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);
 
@@ -5927,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) 
@@ -5935,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.
@@ -5961,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);
@@ -6044,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;
@@ -6108,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;
@@ -6117,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;
@@ -6155,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);
@@ -6180,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;
@@ -6226,7 +6424,7 @@ long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_NOSUCHFILE;
     }
 
-    pid = ((smb_t *) inp)->pid;
+    pid = smbp->pid;
     key = cm_GenerateKey(vcp->vcID, pid, fd);
     {
         LARGE_INTEGER LOffset, LLength;
@@ -6238,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) {
@@ -6436,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).
          */
@@ -6534,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;
@@ -6565,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;
@@ -6598,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;
@@ -6634,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);
@@ -6641,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;
@@ -7032,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) ||
@@ -7044,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)
@@ -7070,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;
@@ -7105,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;
@@ -7133,7 +7338,7 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
                            fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
                            userp);
     }
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseRead(&scp->rw);
 
     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
               osi_LogSaveString(smb_logp, realPathp));
@@ -7335,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;
@@ -7364,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;
@@ -7397,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;
@@ -7421,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;
@@ -7709,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)
@@ -7733,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;
@@ -7792,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 */
@@ -7814,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;
@@ -7842,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 */
@@ -7867,10 +8074,8 @@ 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);
     }
 
-    lock_ObtainMutex(&scp->mx);
     if ((fidp->flags & SMB_FID_EXECUTABLE) && 
          LargeIntegerGreaterThanZero(fidp->scp->length) && 
          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
@@ -7878,7 +8083,7 @@ long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
                            fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
                            userp);
     }
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseRead(&scp->rw);
 
     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
 
@@ -7961,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;
@@ -8084,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;
 }
@@ -8208,12 +8419,12 @@ 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;
@@ -8358,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);