windows-do-not-discard-badtickets-20080218
[openafs.git] / src / WINNT / afsd / smb.c
index 3941150..c4a2534 100644 (file)
 #include <afs/param.h>
 #include <afs/stds.h>
 
-#ifndef DJGPP
 #include <windows.h>
+#pragma warning(push)
+#pragma warning(disable: 4005)
 #include <ntstatus.h>
-#else
-#include <sys/timeb.h>
-#include <tzfile.h>
-#endif /* !DJGPP */
+#pragma warning(pop)
 #include <stddef.h>
 #include <stdlib.h>
 #include <malloc.h>
 #include <stdio.h>
 #include <time.h>
 
+#include "afsd.h"
 #include <osi.h>
 #include <rx\rx.h>
 #include <rx/rx_prototypes.h>
-
-#include "afsd.h"
 #include <WINNT\afsreg.h>
 
 #include "smb.h"
 
 /* These characters are illegal in Windows filenames */
 static char *illegalChars = "\\/:*?\"<>|";
-BOOL isWindows2000 = FALSE;
 
-smb_vc_t *active_vcp = NULL;
-
-int smbShutdownFlag = 0;
+static int smbShutdownFlag = 0;
+static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
 
 int smb_LogoffTokenTransfer;
 time_t smb_LogoffTransferTimeout;
@@ -55,6 +50,7 @@ unsigned int sessionGen = 0;
 
 extern void afsi_log(char *pattern, ...);
 extern HANDLE afsi_file;
+extern int powerStateSuspended;
 
 osi_hyper_t hzero = {0, 0};
 osi_hyper_t hones = {0xFFFFFFFF, -1};
@@ -63,9 +59,13 @@ osi_log_t *  smb_logp;
 osi_rwlock_t smb_globalLock;
 osi_rwlock_t smb_rctLock;
 osi_mutex_t  smb_ListenerLock;
+osi_mutex_t  smb_StartedLock;
  
-char smb_LANadapter;
+unsigned char smb_LANadapter = LANA_INVALID;
 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
+int  smb_LanAdapterChangeDetected = 0;
+
+BOOL isGateway = FALSE;
 
 /* for debugging */
 long smb_maxObsConcurrentCalls=0;
@@ -93,6 +93,7 @@ EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
 EVENT_HANDLE **NCBreturns;
 EVENT_HANDLE **NCBShutdown;
 EVENT_HANDLE *smb_ServerShutdown;
+EVENT_HANDLE ListenerShutdown[256];
 DWORD NCBsessions[NCB_MAX];
 NCB *NCBs[NCB_MAX];
 struct smb_packet *bufs[NCB_MAX];
@@ -103,16 +104,9 @@ unsigned short LSNs[SESSION_MAX];
 int lanas[SESSION_MAX];
 BOOL dead_sessions[SESSION_MAX];
 LANA_ENUM lana_list;
-
 /* for raw I/O */
 osi_mutex_t smb_RawBufLock;
-#ifdef DJGPP
-#define SMB_RAW_BUFS 4
-dos_ptr smb_RawBufs;
-int smb_RawBufSel[SMB_RAW_BUFS];
-#else
 char *smb_RawBufs;
-#endif /* DJGPP */
 
 #define SMB_MASKFLAG_TILDE 1
 #define SMB_MASKFLAG_CASEFOLD 2
@@ -124,11 +118,7 @@ typedef struct raw_write_cont {
        long code;
        osi_hyper_t offset;
        long count;
-#ifndef DJGPP
        char *buf;
-#else
-       dos_ptr buf;
-#endif /* DJGPP */
        int writeMode;
        long alreadyWritten;
 } raw_write_cont_t;
@@ -144,11 +134,9 @@ int smb_hideDotFiles;
 /* global state about V3 protocols */
 int smb_useV3;         /* try to negotiate V3 */
 
-#ifndef DJGPP
-static showErrors = 1;
+static showErrors = 0;
 /* MessageBox or something like it */
 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
-#endif /* DJGPP */
 
 /* GMT time info:
  * Time in Unix format of midnight, 1/1/1970 local time.
@@ -172,25 +160,12 @@ smb_username_t *usernamesp = NULL;
 
 smb_waitingLockRequest_t *smb_allWaitingLocks;
 
+DWORD smb_TlsRequestSlot = -1;
+
 /* forward decl */
 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                        NCB *ncbp, raw_write_cont_t *rwcp);
-void smb_NetbiosInit();
-#ifdef DJGPP
-#ifndef AFS_WIN95_ENV
-DWORD smb_ServerExceptionFilter(void);
-#endif
-
-extern char cm_HostName[];
-extern char cm_confDir[];
-#endif
-
-#ifdef DJGPP
-#define LPTSTR char *
-#define GetComputerName(str, sizep) \
-       strcpy((str), cm_HostName); \
-       *(sizep) = strlen(cm_HostName)
-#endif /* DJGPP */
+int smb_NetbiosInit(int);
 
 #ifdef LOG_PACKET
 void smb_LogPacket(smb_packet_t *packet);
@@ -206,6 +181,42 @@ int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
 /* Faux server GUID. This is never checked. */
 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
 
+void smb_ResetServerPriority()
+{
+    void * p = TlsGetValue(smb_TlsRequestSlot);
+    if (p) {
+       free(p);
+       TlsSetValue(smb_TlsRequestSlot, NULL);
+       SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+    }
+}
+
+void smb_SetRequestStartTime()
+{
+    time_t * tp = TlsGetValue(smb_TlsRequestSlot);
+    if (!tp)
+       tp = malloc(sizeof(time_t));
+    if (tp) {
+       *tp = osi_Time();
+
+       if (!TlsSetValue(smb_TlsRequestSlot, tp))
+           free(tp);
+    }  
+}
+
+void smb_UpdateServerPriority()
+{      
+    time_t *tp = TlsGetValue(smb_TlsRequestSlot);
+
+    if (tp) {
+       time_t now = osi_Time();
+
+       /* Give one priority boost for each 15 seconds */
+       SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
+    }
+}
+
+
 const char * ncb_error_string(int code)
 {
     const char * s;
@@ -317,6 +328,8 @@ char * myCrt_Dispatch(int i)
         return "(2d)ReceiveV3OpenX";
     case 0x2e:
         return "(2e)ReceiveV3ReadX";
+    case 0x2f:
+        return "(2f)ReceiveV3WriteX";
     case 0x32:
         return "(32)ReceiveV3Tran2A";
     case 0x33:
@@ -381,25 +394,25 @@ char * myCrt_2Dispatch(int i)
     default:
         return "unknown SMB op-2";
     case 0:
-        return "S(00)CreateFile";
+        return "S(00)CreateFile_ReceiveTran2Open";
     case 1:
-        return "S(01)FindFirst";
+        return "S(01)FindFirst_ReceiveTran2SearchDir";
     case 2:
-        return "S(02)FindNext";        /* FindNext */
+        return "S(02)FindNext_ReceiveTran2SearchDir";  /* FindNext */
     case 3:
         return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
     case 4:
-        return "S(04)??";
+        return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
     case 5:
-        return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
+        return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
     case 6:
-        return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
+        return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
     case 7:
-        return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
+        return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
     case 8:
-        return "S(08)??_ReceiveTran2SetFileInfo";
+        return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
     case 9:
-        return "S(09)??_ReceiveTran2FSCTL";
+        return "S(09)_ReceiveTran2FSCTL";
     case 10:
         return "S(0a)_ReceiveTran2IOCTL";
     case 11:
@@ -410,6 +423,8 @@ char * myCrt_2Dispatch(int i)
         return "S(0d)_ReceiveTran2CreateDirectory";
     case 14:
         return "S(0e)_ReceiveTran2SessionSetup";
+    case 15:
+       return "S(0f)_QueryFileSystemInformationFid";
     case 16:
         return "S(10)_ReceiveTran2GetDfsReferral";
     case 17:
@@ -505,7 +520,6 @@ static int ExtractBits(WORD bits, short start, short len)
     return (int)num;
 }
 
-#ifndef DJGPP
 void ShowUnixTime(char *FuncName, time_t unixTime)
 {
     FILETIME ft;
@@ -531,9 +545,7 @@ void ShowUnixTime(char *FuncName, time_t unixTime)
         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
     }
 }       
-#endif /* DJGPP */
 
-#ifndef DJGPP
 /* Determine if we are observing daylight savings time */
 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
 {
@@ -576,18 +588,6 @@ void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
      */
     *pDST = localDST.wHour != local.wHour;
 }       
-#else
-/* Determine if we are observing daylight savings time */
-void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
-{
-    struct timeb t;
-
-    ftime(&t);
-    *pDST = t.dstflag;
-    *pDstBias = -60;    /* where can this be different? */
-    *pBias = t.timezone;
-}       
-#endif /* DJGPP */
  
 
 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
@@ -651,7 +651,6 @@ smb_CalculateNowTZ()
 }
 #endif /* USE_NUMERIC_TIME_CONV */
 
-#ifndef DJGPP
 #ifdef USE_NUMERIC_TIME_CONV
 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
 {
@@ -703,29 +702,7 @@ void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
     SystemTimeToFileTime(&stm, largeTimep);
 }
 #endif /* USE_NUMERIC_TIME_CONV */
-#else /* DJGPP */
-void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
-{
-    /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
-    /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
-    LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
-    LARGE_INTEGER ut;
-    int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
-
-    /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
-    *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
-                                     * 24 * 60);
-    *ft = LargeIntegerMultiplyByLong(*ft, 60);
-    *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
-
-    /* add unix time */
-    ut = ConvertLongToLargeInteger(unixTime);
-    ut = LargeIntegerMultiplyByLong(ut, 10000000);
-    *ft = LargeIntegerAdd(*ft, ut);
-}       
-#endif /* !DJGPP */
 
-#ifndef DJGPP
 #ifdef USE_NUMERIC_TIME_CONV
 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
 {
@@ -765,27 +742,6 @@ void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
     _timezone = save_timezone;
 }       
 #endif /* USE_NUMERIC_TIME_CONV */
-#else /* DJGPP */
-void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
-{
-    /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
-    /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
-    LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
-    LARGE_INTEGER a;
-    int leap_years = 89;
-
-    /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
-    a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
-    a = LargeIntegerMultiplyByLong(a, 60);
-    a = LargeIntegerMultiplyByLong(a, 10000000);
-
-    /* subtract it from ft */
-    a = LargeIntegerSubtract(*ft, a);
-
-    /* divide down to seconds */
-    *unixTimep = LargeIntegerDivideByLong(a, 10000000);
-}       
-#endif /* !DJGPP */
 
 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
 {
@@ -795,7 +751,7 @@ void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
     struct tm localJunk;
     time_t t = unixTime;
 
-    ltp = localtime((time_t*) &t);
+    ltp = localtime(&t);
 
     /* if we fail, make up something */
     if (!ltp) {
@@ -837,28 +793,29 @@ void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
 {
     time_t diff_t = unixTime - smb_localZero;
 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
-    osi_assert(diff_t < _UI32_MAX);
+    osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
 #endif
     *dosUTimep = (afs_uint32)diff_t;
 }
 
 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
 {
-#ifndef DJGPP
     *unixTimep = dosTime + smb_localZero;
-#else /* DJGPP */
-    /* dosTime seems to be already adjusted for GMT */
-    *unixTimep = dosTime;
-#endif /* !DJGPP */
 }
 
 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
 {
     smb_vc_t *vcp;
 
+       lock_ObtainWrite(&smb_globalLock);      /* for numVCs */
     lock_ObtainWrite(&smb_rctLock);
     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
-        if (lsn == vcp->lsn && lana == vcp->lana) {
+       if (vcp->magic != SMB_VC_MAGIC)
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+                      __FILE__, __LINE__);
+
+        if (lsn == vcp->lsn && lana == vcp->lana &&
+           !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
             smb_HoldVCNoLock(vcp);
             break;
         }
@@ -866,9 +823,8 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
     if (!vcp && (flags & SMB_FLAG_CREATE)) {
         vcp = malloc(sizeof(*vcp));
         memset(vcp, 0, sizeof(*vcp));
-       lock_ObtainWrite(&smb_globalLock);
         vcp->vcID = ++numVCs;
-       lock_ReleaseWrite(&smb_globalLock);
+       vcp->magic = SMB_VC_MAGIC;
         vcp->refCount = 2;     /* smb_allVCsp and caller */
         vcp->tidCounter = 1;
         vcp->fidCounter = 1;
@@ -886,7 +842,7 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
              */
             NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
-            PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp;
+            PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
             ULONG lsaRespSize = 0;
 
             lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
@@ -898,25 +854,36 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
                                                 &lsaResp,
                                                 &lsaRespSize,
                                                 &ntsEx);
-            if (nts != STATUS_SUCCESS)
+            if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
                 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
                          nts, ntsEx, sizeof(lsaReq), lsaRespSize);
-            osi_assert(nts == STATUS_SUCCESS); /* this had better work! */
+                    afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
+                         nts, ntsEx, lsaRespSize);
+            }
+            osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
 
-            memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
-            LsaFreeReturnBuffer(lsaResp);
+            if (ntsEx == STATUS_SUCCESS) {
+                memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
+                LsaFreeReturnBuffer(lsaResp);
+            } else {
+                /* 
+                 * This will cause the subsequent authentication to fail but
+                 * that is better than us dereferencing a NULL pointer and 
+                 * crashing.
+                 */
+                memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
+            }
         }
         else
             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
 
         if (numVCs >= CM_SESSION_RESERVED) {
-           lock_ObtainWrite(&smb_globalLock);
             numVCs = 0;
-           lock_ReleaseWrite(&smb_globalLock);
             osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
         }
     }
     lock_ReleaseWrite(&smb_rctLock);
+       lock_ReleaseWrite(&smb_globalLock);
     return vcp;
 }
 
@@ -936,24 +903,40 @@ int smb_IsStarMask(char *maskp)
 void smb_ReleaseVCInternal(smb_vc_t *vcp)
 {
     smb_vc_t **vcpp;
+    smb_vc_t * avcp;
 
-#ifdef DEBUG
-    osi_assert(vcp->refCount-- != 0);
-#else
     vcp->refCount--;
-#endif
 
     if (vcp->refCount == 0) {
+      if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
        /* remove VCP from smb_deadVCsp */
        for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
-           if (*vcpp == vcp) {
-               *vcpp = vcp->nextp;
-               break;
-           }
+         if (*vcpp == vcp) {
+           *vcpp = vcp->nextp;
+           break;
+         }
        } 
        lock_FinalizeMutex(&vcp->mx);
        memset(vcp,0,sizeof(smb_vc_t));
        free(vcp);
+      } else {
+       for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
+         if (avcp == vcp)
+           break;
+       }
+       osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
+                avcp?"not ":"",vcp, vcp->refCount);
+#ifdef DEBUG
+       GenerateMiniDump(NULL);
+#endif
+       /* This is a wrong.  However, I suspect that there is an undercount
+        * and I don't want to release 1.4.1 in a state that will allow
+        * smb_vc_t objects to be deallocated while still in the
+        * smb_allVCsp list.  The list is supposed to keep a reference
+        * to the smb_vc_t.  Put it back.
+        */
+       vcp->refCount++;
+      }
     }
 }
 
@@ -997,13 +980,36 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
     smb_user_t *uidpNext;
     smb_vc_t **vcpp;
 
+
+    lock_ObtainMutex(&vcp->mx);
+    if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
+       lock_ReleaseMutex(&vcp->mx);
+       osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
+       return;
+    }
+    vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
+    lock_ReleaseMutex(&vcp->mx);
     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
 
     lock_ObtainWrite(&smb_rctLock);
+    /* remove VCP from smb_allVCsp */
+    for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
+       if ((*vcpp)->magic != SMB_VC_MAGIC)
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+                      __FILE__, __LINE__);
+        if (*vcpp == vcp) {
+            *vcpp = vcp->nextp;
+            vcp->nextp = smb_deadVCsp;
+            smb_deadVCsp = vcp;
+           /* Hold onto the reference until we are done with this function */
+            break;
+        }
+    }
+
     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
 
-        if (fidpIter->flags & SMB_FID_DELETE)
+        if (fidpIter->delete)
             continue;
 
         fid = fidpIter->fid;
@@ -1012,7 +1018,6 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
        smb_HoldFIDNoLock(fidpIter);
         lock_ReleaseWrite(&smb_rctLock);
 
-       /* smb_CloseFID sets SMB_FID_DELETE on Success */
         smb_CloseFID(vcp, fidpIter, NULL, 0);
        smb_ReleaseFID(fidpIter);
 
@@ -1022,9 +1027,9 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
 
     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
        tidpNext = tidpIter->nextp;
-
-       if (tidpIter->flags & SMB_TIDFLAG_DELETE)
+       if (tidpIter->delete)
            continue;
+       tidpIter->delete = 1;
 
        tid = tidpIter->tid;
        osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
@@ -1032,10 +1037,6 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
        smb_HoldTIDNoLock(tidpIter);
        lock_ReleaseWrite(&smb_rctLock);
 
-       lock_ObtainMutex(&tidpIter->mx);
-       tidpIter->flags |= SMB_TIDFLAG_DELETE;
-       lock_ReleaseMutex(&tidpIter->mx);
-
        smb_ReleaseTID(tidpIter);
 
        lock_ObtainWrite(&smb_rctLock);
@@ -1044,38 +1045,24 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
 
     for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
        uidpNext = uidpIter->nextp;
-
-       if (uidpIter->flags & SMB_USERFLAG_DELETE)
+       if (uidpIter->delete)
            continue;
+       uidpIter->delete = 1;
 
        /* do not add an additional reference count for the smb_user_t
         * as the smb_vc_t already is holding a reference */
        lock_ReleaseWrite(&smb_rctLock);
 
-       lock_ObtainMutex(&uidpIter->mx);
-       uidpIter->flags |= SMB_USERFLAG_DELETE;
-       lock_ReleaseMutex(&uidpIter->mx);
-
        smb_ReleaseUID(uidpIter);
 
        lock_ObtainWrite(&smb_rctLock);
        uidpNext = vcp->usersp;
     }
 
-    /* remove VCP from smb_allVCsp */
-    for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
-       if (*vcpp == vcp) {
-           *vcpp = vcp->nextp;
-           vcp->nextp = smb_deadVCsp;
-           smb_deadVCsp = vcp;
-           /* We intentionally do not keep a reference to the 
-            * vcp once it is placed on the deadVCsp list.  This
-            * allows the refcount to reach 0 so we can delete
-            * it. */
-           smb_ReleaseVCNoLock(vcp);
-           break;
-       }
-    } 
+    /* The vcp is now on the deadVCsp list.  We intentionally drop the
+     * reference so that the refcount can reach 0 and we can delete it */
+    smb_ReleaseVCNoLock(vcp);
+    
     lock_ReleaseWrite(&smb_rctLock);
     osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
 }
@@ -1085,7 +1072,16 @@ smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
     smb_tid_t *tidp;
 
     lock_ObtainWrite(&smb_rctLock);
+  retry:
     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
+       if (tidp->refCount == 0 && tidp->delete) {
+           tidp->refCount++;
+           lock_ReleaseWrite(&smb_rctLock);
+           smb_ReleaseTID(tidp);
+           lock_ObtainWrite(&smb_rctLock);
+           goto retry;
+       }
+
         if (tid == tidp->tid) {
             tidp->refCount++;
             break;
@@ -1119,14 +1115,14 @@ void smb_ReleaseTID(smb_tid_t *tidp)
 
     userp = NULL;
     lock_ObtainWrite(&smb_rctLock);
-    osi_assert(tidp->refCount-- > 0);
-    if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
+    osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
+    if (tidp->refCount == 0 && (tidp->delete)) {
         ltpp = &tidp->vcp->tidsp;
         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
             if (tp == tidp) 
                 break;
         }
-        osi_assert(tp != NULL);
+        osi_assertx(tp != NULL, "null smb_tid_t");
         *ltpp = tp->nextp;
         lock_FinalizeMutex(&tidp->mx);
         userp = tidp->userp;   /* remember to drop ref later */
@@ -1228,7 +1224,7 @@ void smb_ReleaseUsername(smb_username_t *unp)
     time_t     now = osi_Time();
 
     lock_ObtainWrite(&smb_rctLock);
-    osi_assert(unp->refCount-- > 0);
+    osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
     if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
        (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
         lupp = &usernamesp;
@@ -1236,7 +1232,7 @@ void smb_ReleaseUsername(smb_username_t *unp)
             if (up == unp) 
                 break;
         }
-        osi_assert(up != NULL);
+        osi_assertx(up != NULL, "null smb_username_t");
         *lupp = up->nextp;
        up->nextp = NULL;                       /* do not remove this */
         lock_FinalizeMutex(&unp->mx);
@@ -1264,14 +1260,14 @@ void smb_ReleaseUID(smb_user_t *uidp)
     smb_username_t *unp = NULL;
 
     lock_ObtainWrite(&smb_rctLock);
-    osi_assert(uidp->refCount-- > 0);
+    osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
     if (uidp->refCount == 0) {
         lupp = &uidp->vcp->usersp;
         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
             if (up == uidp) 
                 break;
         }
-        osi_assert(up != NULL);
+        osi_assertx(up != NULL, "null smb_user_t");
         *lupp = up->nextp;
         lock_FinalizeMutex(&uidp->mx);
        unp = uidp->unp;
@@ -1288,11 +1284,29 @@ void smb_ReleaseUID(smb_user_t *uidp)
     }
 }      
 
+cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
+{
+    cm_user_t *up = NULL;
+
+    if (!uidp)
+       return NULL;
+    
+    lock_ObtainMutex(&uidp->mx);
+    if (uidp->unp) {
+       up = uidp->unp->userp;
+       cm_HoldUser(up);
+    }
+    lock_ReleaseMutex(&uidp->mx);
+
+    return up;
+}
+
+
 /* retrieve a held reference to a user structure corresponding to an incoming
  * request.
  * corresponding release function is cm_ReleaseUser.
  */
-cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
+cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
 {
     smb_user_t *uidp;
     cm_user_t *up = NULL;
@@ -1303,12 +1317,7 @@ cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
     if (!uidp)
        return NULL;
     
-    lock_ObtainMutex(&uidp->mx);
-    if (uidp->unp) {
-       up = uidp->unp->userp;
-       cm_HoldUser(up);
-    }
-    lock_ReleaseMutex(&uidp->mx);
+    up = smb_GetUserFromUID(uidp);
 
     smb_ReleaseUID(uidp);
     return up;
@@ -1377,6 +1386,13 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
 
   retry:
     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
+       if (fidp->refCount == 0 && fidp->delete) {
+           fidp->refCount++;
+           lock_ReleaseWrite(&smb_rctLock);
+           smb_ReleaseFID(fidp);
+           lock_ObtainWrite(&smb_rctLock);
+           goto retry;
+       }
         if (fid == fidp->fid) {
             if (newFid) {
                 fid++;
@@ -1420,7 +1436,7 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
         fidp->raw_write_event = event;
         if (newFid) {
             vcp->fidCounter = fid+1;
-            if (vcp->fidCounter == 0) {
+            if (vcp->fidCounter == 0xFFFF) {
                osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
                         vcp);
                 vcp->fidCounter = 1;
@@ -1432,11 +1448,33 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
     return fidp;
 }
 
+smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
+{
+    smb_fid_t *fidp = NULL;
+    int newFid = 0;
+        
+    if (!scp)
+        return NULL;
+
+    lock_ObtainWrite(&smb_rctLock);
+    for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
+        if (scp == fidp->scp) {
+            fidp->refCount++;
+            break;
+        }
+    }
+    lock_ReleaseWrite(&smb_rctLock);
+    return fidp;
+}
+
 void smb_HoldFIDNoLock(smb_fid_t *fidp)
 {
     fidp->refCount++;
 }
 
+
+/* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
+/* the sm_fid_t->mx and smb_rctLock must not be held */
 void smb_ReleaseFID(smb_fid_t *fidp)
 {
     cm_scache_t *scp = NULL;
@@ -1444,18 +1482,25 @@ void smb_ReleaseFID(smb_fid_t *fidp)
     smb_vc_t *vcp = NULL;
     smb_ioctl_t *ioctlp;
 
-    lock_ObtainWrite(&smb_rctLock);
-    osi_assert(fidp->refCount-- > 0);
     lock_ObtainMutex(&fidp->mx);
-    if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
+    lock_ObtainWrite(&smb_rctLock);
+    osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
+    if (fidp->refCount == 0 && (fidp->delete)) {
         vcp = fidp->vcp;
         fidp->vcp = NULL;
         scp = fidp->scp;    /* release after lock is released */
-        fidp->scp = NULL;
+       if (scp) {
+           lock_ObtainMutex(&scp->mx);
+           scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
+           lock_ReleaseMutex(&scp->mx);
+           osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
+           fidp->scp = NULL;
+       }
         userp = fidp->userp;
         fidp->userp = NULL;
 
-        osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
+       if (vcp->fidsp) 
+           osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
         thrd_CloseHandle(fidp->raw_write_event);
 
         /* and see if there is ioctl stuff to free */
@@ -1469,7 +1514,6 @@ void smb_ReleaseFID(smb_fid_t *fidp)
                 free(ioctlp->outAllocp);
             free(ioctlp);
         }       
-
        lock_ReleaseMutex(&fidp->mx);
        lock_FinalizeMutex(&fidp->mx);
         free(fidp);
@@ -1524,71 +1568,6 @@ char VNLCUserName[] = "%LCUSERNAME%";
 char VNComputerName[] = "%COMPUTERNAME%";
 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
 
-#ifdef DJGPP
-/* List available shares */
-int smb_ListShares()
-{
-    char sbmtpath[256];
-    char pathName[256];
-    char shareBuf[4096];
-    int num_shares=0;
-    char *this_share;
-    int len;
-    char *p;
-    int print_afs = 0;
-    int code;
-
-    /*strcpy(shareNameList[num_shares], "all");
-      strcpy(pathNameList[num_shares++], "/afs");*/
-    fprintf(stderr, "The following shares are available:\n");
-    fprintf(stderr, "Share Name (AFS Path)\n");
-    fprintf(stderr, "---------------------\n");
-    fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
-
-#ifndef DJGPP
-    code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
-    if (code == 0 || code > sizeof(sbmtpath)) return -1;
-#else
-    strcpy(sbmtpath, cm_confDir);
-#endif /* !DJGPP */
-    strcat(sbmtpath, "/afsdsbmt.ini");
-    len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
-                                   shareBuf, sizeof(shareBuf),
-                                   sbmtpath);
-    if (len == 0) {
-        return num_shares;
-    }
-
-    this_share = shareBuf;
-    do
-    {
-        print_afs = 0;
-        /*strcpy(shareNameList[num_shares], this_share);*/
-        len = GetPrivateProfileString("AFS Submounts", this_share,
-                                       NULL,
-                                       pathName, 256,
-                                       sbmtpath);
-        if (!len) 
-            return num_shares;
-        p = pathName;
-        if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
-            print_afs = 1;
-        while (*p) {
-            if (*p == '\\') *p = '/';    /* change to / */
-            p++;
-        }
-
-        fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
-                 smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
-                 pathName);
-        num_shares++;
-        while (*this_share != 0) this_share++;  /* find next NUL */
-        this_share++;   /* skip past the NUL */
-    } while (*this_share != 0);  /* stop at final NUL */
-
-    return num_shares;
-}
-#endif /* DJGPP */
 
 typedef struct smb_findShare_rock {
     char * shareName;
@@ -1629,9 +1608,6 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
     char *var;
     char temp[1024];
     DWORD sizeTemp;
-#ifdef DJGPP
-    char sbmtpath[MAX_PATH];
-#endif
     char *p, *q;
     HKEY parmKey;
     DWORD code;
@@ -1668,6 +1644,8 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
     }
 
     if (_stricmp(shareName, "IPC$") == 0 ||
+        _stricmp(shareName, "srvsvc") == 0 ||
+        _stricmp(shareName, "wkssvc") == 0 ||
         _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
         _stricmp(shareName, "DESKTOP.INI") == 0
          ) {
@@ -1675,7 +1653,36 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
         return 0;
     }
 
-#ifndef DJGPP
+    /* Check for volume references
+     * 
+     * They look like <cell>{%,#}<volume>
+     */
+    if (strchr(shareName, '%') != NULL ||
+        strchr(shareName, '#') != NULL) {
+        char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
+                                /* make room for '/@vol:' + mountchar + NULL terminator*/
+
+        osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
+                 osi_LogSaveString(smb_logp, shareName));
+
+        snprintf(pathstr, sizeof(pathstr)/sizeof(char),
+                 "/" CM_PREFIX_VOL "%s", shareName);
+        pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
+        len = strlen(pathstr) + 1;
+
+        *pathNamep = malloc(len);
+        if (*pathNamep) {
+            strcpy(*pathNamep, pathstr);
+            strlwr(*pathNamep);
+            osi_Log1(smb_logp, "   returning pathname [%s]",
+                     osi_LogSaveString(smb_logp, *pathNamep));
+
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
                          0, KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
@@ -1688,12 +1695,6 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
     } else {
         len = 0;
     }   
-#else /* DJGPP */
-    strcpy(sbmtpath, cm_confDir);
-    strcat(sbmtpath, "/afsdsbmt.ini");
-    len = GetPrivateProfileString("AFS Submounts", shareName, "",
-                                   pathName, sizeof(pathName), sbmtpath);
-#endif /* !DJGPP */
     if (len != 0 && len != sizeof(pathName) - 1) {
         /* We can accept either unix or PC style AFS pathnames.  Convert
          * Unix-style to PC style here for internal use. 
@@ -1885,13 +1886,15 @@ void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
 {
     lock_ObtainWrite(&smb_globalLock);
     lock_ObtainMutex(&dsp->mx);
+    osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
+             dsp->cookie, dsp, dsp->scp);
     dsp->flags |= SMB_DIRSEARCH_DELETE;
     if (dsp->scp != NULL) {
         lock_ObtainMutex(&dsp->scp->mx);
         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
-            dsp->scp->bulkStatProgress = hones;
+            dsp->scp->bulkStatProgress = hzero;
         }      
         lock_ReleaseMutex(&dsp->scp->mx);
     }  
@@ -1905,7 +1908,7 @@ void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
     cm_scache_t *scp = NULL;
 
     lock_ObtainMutex(&dsp->mx);
-    osi_assert(dsp->refCount-- > 0);
+    osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
@@ -1913,6 +1916,8 @@ void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
         lock_ReleaseMutex(&dsp->mx);
         lock_FinalizeMutex(&dsp->mx);
         scp = dsp->scp;
+       osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
+                dsp->cookie, dsp, scp);
         free(dsp);
     } else {
         lock_ReleaseMutex(&dsp->mx);
@@ -2000,6 +2005,8 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
     counter = 0;
 
     /* what's the biggest ID allowed in this version of the protocol */
+    /* TODO: do we really want a non v3 dir search request to wrap
+       smb_dirSearchCounter? */
     maxAllowed = isV3 ? 65535 : 255;
     if (smb_dirSearchCounter > maxAllowed)
         smb_dirSearchCounter = 1;
@@ -2043,7 +2050,10 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
         if (!smb_lastDirSearchp) 
             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
-        break;
+    
+       osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
+                dsp->cookie, dsp);
+       break;
     }  
     lock_ReleaseWrite(&smb_globalLock);
     return dsp;
@@ -2052,9 +2062,6 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
 static smb_packet_t *GetPacket(void)
 {
     smb_packet_t *tbp;
-#ifdef DJGPP
-    unsigned int npar, seg, tb_sel;
-#endif
 
     lock_ObtainWrite(&smb_globalLock);
     tbp = smb_packetFreeListp;
@@ -2062,11 +2069,7 @@ static smb_packet_t *GetPacket(void)
         smb_packetFreeListp = tbp->nextp;
     lock_ReleaseWrite(&smb_globalLock);
     if (!tbp) {
-#ifndef DJGPP
         tbp = calloc(65540,1);
-#else /* DJGPP */
-        tbp = malloc(sizeof(smb_packet_t));
-#endif /* !DJGPP */
         tbp->magic = SMB_PACKETMAGIC;
         tbp->ncbp = NULL;
         tbp->vcp = NULL;
@@ -2080,27 +2083,8 @@ static smb_packet_t *GetPacket(void)
         tbp->flags = 0;
         tbp->spacep = NULL;
         
-#ifdef DJGPP
-        npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
-        {
-            signed int retval =
-                __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
-            if (retval == -1) {
-                osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS memory",
-                          npar);
-                osi_panic("",__FILE__,__LINE__);
-            }
-            else {
-                osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X",
-                          npar, retval);
-                seg = retval;
-            }
-        }
-        tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
-        tbp->dos_pkt_sel = tb_sel;
-#endif /* DJGPP */
     }
-    osi_assert(tbp->magic == SMB_PACKETMAGIC);
+    osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
 
     return tbp;
 }
@@ -2120,9 +2104,6 @@ static NCB *GetNCB(void)
 {
     smb_ncb_t *tbp;
     NCB *ncbp;
-#ifdef DJGPP
-    unsigned int npar, seg, tb_sel;
-#endif /* DJGPP */
 
     lock_ObtainWrite(&smb_globalLock);
     tbp = smb_ncbFreeListp;
@@ -2130,44 +2111,21 @@ static NCB *GetNCB(void)
         smb_ncbFreeListp = tbp->nextp;
     lock_ReleaseWrite(&smb_globalLock);
     if (!tbp) {
-#ifndef DJGPP
         tbp = calloc(sizeof(*tbp),1);
-#else /* DJGPP */
-        tbp = malloc(sizeof(*tbp));
-        npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
-        {
-            signed int retval =
-                __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
-            if (retval == -1) {
-                osi_Log1(smb_logp, "Cannot allocate %d paragraphs of DOS mem in GetNCB",
-                          npar);
-                osi_panic("",__FILE__,__LINE__);
-            } else {
-                osi_Log2(smb_logp, "Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
-                          npar, retval);
-                seg = retval;
-            }
-        }
-        tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
-        tbp->dos_ncb_sel = tb_sel;
-#endif /* !DJGPP */
         tbp->magic = SMB_NCBMAGIC;
     }
         
-    osi_assert(tbp->magic == SMB_NCBMAGIC);
+    osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
 
     memset(&tbp->ncb, 0, sizeof(NCB));
     ncbp = &tbp->ncb;
-#ifdef DJGPP
-    dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
-#endif /* DJGPP */
     return ncbp;
 }
 
 void smb_FreePacket(smb_packet_t *tbp)
 {
     smb_vc_t * vcp = NULL;
-    osi_assert(tbp->magic == SMB_PACKETMAGIC);
+    osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
         
     lock_ObtainWrite(&smb_globalLock);
     tbp->nextp = smb_packetFreeListp;
@@ -2195,7 +2153,7 @@ static void FreeNCB(NCB *bufferp)
     smb_ncb_t *tbp;
         
     tbp = (smb_ncb_t *) bufferp;
-    osi_assert(tbp->magic == SMB_NCBMAGIC);
+    osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
         
     lock_ObtainWrite(&smb_globalLock);
     tbp->nextp = smb_ncbFreeListp;
@@ -2237,7 +2195,7 @@ void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
 }       
 
 /* return the parm'th parameter in the smbp packet */
-unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
+unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
 {
     int parmCount;
     unsigned char *parmDatap;
@@ -2251,10 +2209,8 @@ unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
                 parm, parmCount, smbp->ncb_length);
        osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
                  parm, parmCount, smbp->ncb_length);
-#ifndef DJGPP
        LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
                 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
-#endif /* !DJGPP */
         osi_panic(s, __FILE__, __LINE__);
     }
     parmDatap = smbp->wctp + (2*parm) + 1;
@@ -2263,6 +2219,54 @@ unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
 }
 
 /* return the parm'th parameter in the smbp packet */
+unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
+{
+    int parmCount;
+    unsigned char *parmDatap;
+
+    parmCount = *smbp->wctp;
+
+    if (parm >= parmCount) {
+       char s[100];
+
+       sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
+                parm, parmCount, smbp->ncb_length);
+       osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
+                 parm, parmCount, smbp->ncb_length);
+       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
+                __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
+        osi_panic(s, __FILE__, __LINE__);
+    }
+    parmDatap = smbp->wctp + (2*parm) + 1;
+        
+    return parmDatap[0];
+}
+
+/* return the parm'th parameter in the smbp packet */
+unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
+{
+    int parmCount;
+    unsigned char *parmDatap;
+
+    parmCount = *smbp->wctp;
+
+    if (parm + 1 >= parmCount) {
+       char s[100];
+
+       sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
+                parm, parmCount, smbp->ncb_length);
+       osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
+                 parm, parmCount, smbp->ncb_length);
+       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
+                __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
+        osi_panic(s, __FILE__, __LINE__);
+    }
+    parmDatap = smbp->wctp + (2*parm) + 1;
+        
+    return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
+}
+
+/* return the parm'th parameter in the smbp packet */
 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
 {
     int parmCount;
@@ -2275,10 +2279,8 @@ unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
 
         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
                 parm, offset, parmCount, smbp->ncb_length);
-#ifndef DJGPP
        LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
                 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
-#endif /* !DJGPP */
         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
                 parm, offset, parmCount, smbp->ncb_length);
         osi_panic(s, __FILE__, __LINE__);
@@ -2313,7 +2315,7 @@ void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
     *parmDatap++ = parmValue & 0xff;
     *parmDatap++ = (parmValue>>8) & 0xff;
     *parmDatap++ = (parmValue>>16) & 0xff;
-    *parmDatap++ = (parmValue>>24) & 0xff;
+    *parmDatap   = (parmValue>>24) & 0xff;
 }
 
 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
@@ -2424,7 +2426,10 @@ void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op
         outp->res[1] = inSmbp->res[1];
         op->inCom = inSmbp->com;
     }
-    outp->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
+    outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
+#ifdef SEND_CANONICAL_PATHNAMES
+    outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
+#endif
     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
 
     /* copy fields in generic packet area */
@@ -2441,18 +2446,12 @@ void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
     long code = 0;
     unsigned char *tp;
     int localNCB = 0;
-#ifdef DJGPP
-    dos_ptr dos_ncb;
-#endif /* DJGPP */
         
     ncbp = inp->ncbp;
     if (ncbp == NULL) {
         ncbp = GetNCB();
         localNCB = 1;
     }
-#ifdef DJGPP
-    dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
-#endif /* DJGPP */
  
     memset((char *)ncbp, 0, sizeof(NCB));
 
@@ -2466,35 +2465,27 @@ void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
     ncbp->ncb_lsn = (unsigned char) vcp->lsn;  /* vc to use */
     ncbp->ncb_lana_num = vcp->lana;
     ncbp->ncb_command = NCBSEND;       /* op means send data */
-#ifndef DJGPP
     ncbp->ncb_buffer = (char *) inp;/* packet */
     code = Netbios(ncbp);
-#else /* DJGPP */
-    ncbp->ncb_buffer = inp->dos_pkt;/* packet */
-    ((smb_ncb_t*)ncbp)->orig_pkt = inp;
-
-    /* copy header information from virtual to DOS address space */
-    dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
-    code = Netbios(ncbp, dos_ncb);
-#endif /* !DJGPP */
         
     if (code != 0) {
        const char * s = ncb_error_string(code);
         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
-#ifndef DJGPP
        LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
-#endif /* !DJGPP */
 
-       osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
-                vcp, vcp->usersp);
-
-       lock_ObtainWrite(&smb_globalLock);
-       lock_ObtainMutex(&vcp->mx);
-       vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-       dead_sessions[vcp->session] = TRUE;
-       lock_ReleaseMutex(&vcp->mx);
-       lock_ReleaseWrite(&smb_globalLock);
-       smb_CleanupDeadVC(vcp);
+       lock_ObtainMutex(&vcp->mx);
+       if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
+           osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
+                     vcp, vcp->usersp);
+           vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
+           lock_ReleaseMutex(&vcp->mx);
+           lock_ObtainWrite(&smb_globalLock);
+           dead_sessions[vcp->session] = TRUE;
+           lock_ReleaseWrite(&smb_globalLock);
+           smb_CleanupDeadVC(vcp);
+       } else {
+           lock_ReleaseMutex(&vcp->mx);
+       }
     }
 
     if (localNCB)
@@ -2529,7 +2520,8 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     else if (code == CM_ERROR_READONLY) {
         NTStatus = 0xC00000A2L;        /* Write protected */
     }
-    else if (code == CM_ERROR_NOSUCHFILE) {
+    else if (code == CM_ERROR_NOSUCHFILE ||
+             code == CM_ERROR_BPLUS_NOMATCH) {
         NTStatus = 0xC000000FL;        /* No such file */
     }
     else if (code == CM_ERROR_NOSUCHPATH) {
@@ -2590,11 +2582,7 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
         NTStatus = 0xC09820FBL;        /* SMB use standard */
     }
     else if (code == CM_ERROR_QUOTA) {
-#ifdef COMMENT
         NTStatus = 0xC0000044L;        /* Quota exceeded */
-#else
-        NTStatus = 0xC000007FL;        /* Disk full */
-#endif
     }
     else if (code == CM_ERROR_SPACE) {
         NTStatus = 0xC000007FL;        /* Disk full */
@@ -2642,26 +2630,22 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     else if (code == CM_ERROR_PATH_NOT_COVERED) {
         NTStatus = 0xC0000257L; /* Path Not Covered */
     } 
-#ifdef COMMENT
     else if (code == CM_ERROR_ALLBUSY) {
-        NTStatus = 0xC00000BFL; /* Network Busy */
+        NTStatus = 0xC000022DL; /* Retry */
     } 
     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
-        NTStatus = 0xC0000350L; /* Remote Host Down */
-    } 
-#else
-    /* we do not want to be telling the SMB/CIFS client that
-     * the AFS Client Service is busy or down.  
-     */
-    else if (code == CM_ERROR_ALLBUSY || 
-             code == CM_ERROR_ALLOFFLINE ||
-            code == CM_ERROR_ALLDOWN) {
         NTStatus = 0xC00000BEL; /* Bad Network Path */
-    }
-#endif
-    else if (code == RXKADUNKNOWNKEY) {
-       NTStatus = 0xC0000322L; /* Bad Kerberos key */
-    } else {
+    } 
+    else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
+       NTStatus = 0xC0000322L; /* No Kerberos key */
+    } 
+    else if (code == CM_ERROR_BAD_LEVEL) {
+       NTStatus = 0xC0000148L; /* Invalid Level */
+    } 
+    else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
+       NTStatus = 0xC000007EL; /* Range Not Locked */
+    } 
+    else {
         NTStatus = 0xC0982001L;        /* SMB non-specific error */
     }
 
@@ -2700,7 +2684,8 @@ void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
         class = 3;
         error = 19;    /* read only */
     }
-    else if (code == CM_ERROR_NOSUCHFILE) {
+    else if (code == CM_ERROR_NOSUCHFILE ||
+             code == CM_ERROR_BPLUS_NOMATCH) {
         class = 1;
         error = 2;     /* ENOENT! */
     }
@@ -2876,12 +2861,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     cm_user_t *userp = NULL;
     NCB *ncbp;
     int rc;
-#ifndef DJGPP
     char *rawBuf = NULL;
-#else
-    dos_ptr rawBuf = NULL;
-    dos_ptr dos_ncb;
-#endif /* DJGPP */
 
     rawBuf = NULL;
     finalCount = 0;
@@ -2889,16 +2869,44 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     fd = smb_GetSMBParm(inp, 0);
     count = smb_GetSMBParm(inp, 3);
     minCount = smb_GetSMBParm(inp, 4);
-    offset.HighPart = 0;       /* too bad */
     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
 
-    osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
-             fd, offset.LowPart, count);
+    if (*inp->wctp == 10) {
+        /* we were sent a request with 64-bit file offsets */
+#ifdef AFS_LARGEFILES
+        offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
+
+        if (LargeIntegerLessThanZero(offset)) {
+            osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
+            goto send1;
+        }
+#else
+        if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
+            osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
+            goto send1;
+        } else {
+            offset.HighPart = 0;
+        }
+#endif
+    } else {
+        /* we were sent a request with 32-bit file offsets */
+        offset.HighPart = 0;
+    }
+
+    osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
+             fd, offset.HighPart, offset.LowPart, count);
 
     fidp = smb_FindFID(vcp, fd, 0);
     if (!fidp)
         goto send1;
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        code = CM_ERROR_NOSUCHFILE;
+        goto send1a;
+    }
+
+
     pid = ((smb_t *) inp)->pid;
     {
         LARGE_INTEGER LOffset, LLength;
@@ -2906,7 +2914,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
 
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
-        LOffset.HighPart = 0;
+        LOffset.HighPart = offset.HighPart;
         LOffset.LowPart = offset.LowPart;
         LLength.HighPart = 0;
         LLength.LowPart = count;
@@ -2923,11 +2931,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     if (smb_RawBufs) {
         /* Get a raw buf, from head of list */
         rawBuf = smb_RawBufs;
-#ifndef DJGPP
         smb_RawBufs = *(char **)smb_RawBufs;
-#else /* DJGPP */
-        smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
-#endif /* !DJGPP */
     }
     lock_ReleaseMutex(&smb_RawBufLock);
     if (!rawBuf)
@@ -2937,19 +2941,11 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     if (fidp->flags & SMB_FID_IOCTL)
     {
        lock_ReleaseMutex(&fidp->mx);
-#ifndef DJGPP
         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
-#else
-        rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
-#endif
         if (rawBuf) {
             /* Give back raw buffer */
             lock_ObtainMutex(&smb_RawBufLock);
-#ifndef DJGPP
             *((char **) rawBuf) = smb_RawBufs;
-#else /* DJGPP */
-            _farpokel(_dos_ds, rawBuf, smb_RawBufs);
-#endif /* !DJGPP */
             
             smb_RawBufs = rawBuf;
             lock_ReleaseMutex(&smb_RawBufLock);
@@ -2960,15 +2956,9 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     }
     lock_ReleaseMutex(&fidp->mx);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
-#ifndef DJGPP
     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
-#else /* DJGPP */
-    /* have to give ReadData flag so it will treat buffer as DOS mem. */
-    code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
-                        userp, &finalCount, TRUE /* rawFlag */);
-#endif /* !DJGPP */
 
     if (code != 0)
         goto send;
@@ -2981,9 +2971,6 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
 
   send1:
     ncbp = outp->ncbp;
-#ifdef DJGPP
-    dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
-#endif /* DJGPP */
     memset((char *)ncbp, 0, sizeof(NCB));
 
     ncbp->ncb_length = (unsigned short) finalCount;
@@ -2992,22 +2979,14 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     ncbp->ncb_command = NCBSEND;
     ncbp->ncb_buffer = rawBuf;
 
-#ifndef DJGPP
     code = Netbios(ncbp);
-#else /* DJGPP */
-    code = Netbios(ncbp, dos_ncb);
-#endif /* !DJGPP */
     if (code != 0)
         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
 
     if (rawBuf) {
         /* Give back raw buffer */
         lock_ObtainMutex(&smb_RawBufLock);
-#ifndef DJGPP
         *((char **) rawBuf) = smb_RawBufs;
-#else /* DJGPP */
-        _farpokel(_dos_ds, rawBuf, smb_RawBufs);
-#endif /* !DJGPP */
 
         smb_RawBufs = rawBuf;
         lock_ReleaseMutex(&smb_RawBufLock);
@@ -3037,6 +3016,7 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     int coreProtoIndex;
     int v3ProtoIndex;
     int NTProtoIndex;
+    int VistaProtoIndex;
     int protoIndex;                            /* index we're using */
     int namex;
     int dbytes;
@@ -3057,6 +3037,7 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     coreProtoIndex = -1;               /* not found */
     v3ProtoIndex = -1;
     NTProtoIndex = -1;
+    VistaProtoIndex = -1;
     while(namex < dbytes) {
         osi_Log1(smb_logp, "Protocol %s",
                   osi_LogSaveString(smb_logp, namep+1));
@@ -3074,6 +3055,9 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
             NTProtoIndex = tcounter;
         }
+        else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
+            VistaProtoIndex = tcounter;
+        }
 
         /* compute size of protocol entry */
         entryLength = (int)strlen(namep+1);
@@ -3086,7 +3070,13 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 
     lock_ObtainMutex(&vcp->mx);
-    if (NTProtoIndex != -1) {
+#if 0
+    if (VistaProtoIndex != -1) {
+        protoIndex = VistaProtoIndex;
+        vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
+    } else 
+#endif 
+       if (NTProtoIndex != -1) {
         protoIndex = NTProtoIndex;
         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
     }
@@ -3103,7 +3093,7 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     if (protoIndex == -1)
         return CM_ERROR_INVAL;
-    else if (NTProtoIndex != -1) {
+    else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
         smb_SetSMBParm(outp, 0, protoIndex);
         if (smb_authType != SMB_AUTH_NONE) {
             smb_SetSMBParmByte(outp, 1,
@@ -3143,6 +3133,9 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #ifdef DFS_SUPPORT
                NTNEGOTIATE_CAPABILITY_DFS |
 #endif
+#ifdef AFS_LARGEFILES
+               NTNEGOTIATE_CAPABILITY_LARGEFILES |
+#endif
                NTNEGOTIATE_CAPABILITY_NTFIND |
                NTNEGOTIATE_CAPABILITY_RAWMODE |
                NTNEGOTIATE_CAPABILITY_NTSMB;
@@ -3244,15 +3237,25 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
 void smb_CheckVCs(void)
 {
-    smb_vc_t * vcp;
+    smb_vc_t * vcp, *nextp;
     smb_packet_t * outp = GetPacket();
     smb_t *smbp;
             
-    for ( vcp=smb_allVCsp; vcp; vcp = vcp->nextp ) 
+    lock_ObtainWrite(&smb_rctLock);
+    for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
     {
+       if (vcp->magic != SMB_VC_MAGIC)
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+                      __FILE__, __LINE__);
+
+       nextp = vcp->nextp;
+
        if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
            continue;
 
+       smb_HoldVCNoLock(vcp);
+       if (nextp)
+           smb_HoldVCNoLock(nextp);
        smb_FormatResponsePacket(vcp, NULL, outp);
         smbp = (smb_t *)outp;
        outp->inCom = smbp->com = 0x2b /* Echo */;
@@ -3265,10 +3268,16 @@ void smb_CheckVCs(void)
 
        smb_SetSMBParm(outp, 0, 0);
        smb_SetSMBDataLength(outp, 0);
+       lock_ReleaseWrite(&smb_rctLock);
 
        smb_SendPacket(vcp, outp);
-    }
 
+       lock_ObtainWrite(&smb_rctLock);
+       smb_ReleaseVCNoLock(vcp);
+       if (nextp)
+           smb_ReleaseVCNoLock(nextp);
+    }
+    lock_ReleaseWrite(&smb_rctLock);
     smb_FreePacket(outp);
 }
 
@@ -3393,7 +3402,7 @@ void smb_WaitingLocksDaemon()
                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
                     continue;
 
-                osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
+                osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
                 
                 /* wl->state is either _DONE or _WAITING.  _ERROR
                    would no longer be on the queue. */
@@ -3428,6 +3437,7 @@ void smb_WaitingLocksDaemon()
                          wlRequest);
 
                 scp = wlRequest->scp;
+               osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
 
                 cm_InitReq(&req);
 
@@ -3510,7 +3520,7 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     smb_tid_t *tidp;
     smb_user_t *uidp;
     unsigned short newTid;
-    char shareName[256];
+    char shareName[AFSPATHMAX];
     char *sharePath;
     int shareFound;
     char *tp;
@@ -3531,14 +3541,13 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
         return CM_ERROR_BADSMB;
     strcpy(shareName, tp+1);
 
-    userp = smb_GetUser(vcp, inp);
-
     lock_ObtainMutex(&vcp->mx);
     newTid = vcp->tidCounter++;
     lock_ReleaseMutex(&vcp->mx);
 
     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+    userp = smb_GetUserFromUID(uidp);
     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
     if (uidp)
         smb_ReleaseUID(uidp);
@@ -3595,23 +3604,31 @@ int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
 
     /* mask starts out all blanks */
     memset(maskp, ' ', 11);
+    maskp[11] = '\0';
 
     /* find last backslash, or use whole thing if there is none */
     tp = strrchr(pathp, '\\');
-    if (!tp) tp = pathp;
-    else tp++; /* skip slash */
+    if (!tp) 
+        tp = pathp;
+    else 
+        tp++;  /* skip slash */
         
     up = maskp;
 
     /* names starting with a dot are illegal */
-    if (*tp == '.') valid8Dot3 = 0;
+    if (*tp == '.') 
+        valid8Dot3 = 0;
 
     for(i=0;; i++) {
         tc = *tp++;
-        if (tc == 0) return valid8Dot3;
-        if (tc == '.' || tc == '"') break;
-        if (i < 8) *up++ = tc;
-        else valid8Dot3 = 0;
+        if (tc == 0) 
+            return valid8Dot3;
+        if (tc == '.' || tc == '"') 
+            break;
+        if (i < 8) 
+            *up++ = tc;
+        else
+            valid8Dot3 = 0;
     }
         
     /* if we get here, tp point after the dot */
@@ -3690,7 +3707,7 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
 {
     unsigned char *pathp;
     unsigned char *tp;
-    unsigned char mask[11];
+    unsigned char mask[12];
     unsigned char *statBlockp;
     unsigned char initStatBlock[21];
     int statLen;
@@ -3700,11 +3717,11 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     /* pull pathname and stat block out of request */
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
-    osi_assert(pathp != NULL);
+    osi_assertx(pathp != NULL, "null path");
     if (smb_StoreAnsiFilenames)
         OemToChar(pathp,pathp);
     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
-    osi_assert(statBlockp != NULL);
+    osi_assertx(statBlockp != NULL, "null statBlock");
     if (statLen == 0) {
         statBlockp = initStatBlock;
         statBlockp[0] = 8;
@@ -3756,8 +3773,10 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     return 0;
 }       
 
-long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
-                             cm_user_t *userp, cm_req_t *reqp)
+static long 
+smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
+                        char * tidPathp, char * relPathp,
+                        cm_user_t *userp, cm_req_t *reqp)
 {
     long code = 0;
     cm_scache_t *scp;
@@ -3767,13 +3786,20 @@ long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
     char attr;
     smb_dirListPatch_t *patchp;
     smb_dirListPatch_t *npatchp;
+    char path[AFSPATHMAX];
 
     for (patchp = *dirPatchespp; patchp; patchp =
          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
 
         dptr = patchp->dptr;
 
+        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) {
             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
                 *dptr++ = SMB_ATTR_HIDDEN;
@@ -3790,6 +3816,8 @@ long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
             continue;
         }
 
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
         attr = smb_Attributes(scp);
         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
@@ -3835,7 +3863,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     char *tp;
     long code = 0;
     char *pathp;
-    cm_dirEntry_t *dep;
+    cm_dirEntry_t *dep = 0;
     int maxCount;
     smb_dirListPatch_t *dirListPatchesp;
     smb_dirListPatch_t *curPatchp;
@@ -3858,7 +3886,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     char shortName[13];
     char *actualName;
     char *shortNameEnd;
-    char mask[11];
+    char mask[12];
     int returnedNames;
     long nextEntryCookie;
     int numDirChunks;          /* # of 32 byte dir chunks in this entry */
@@ -3869,7 +3897,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     int starPattern;
     int rootPath = 0;
     int caseFold;
-    char *tidPathp;
+    char *tidPathp = 0;
     cm_req_t req;
     cm_fid_t fid;
     int fileType;
@@ -3920,7 +3948,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         dsp = smb_NewDirSearch(0);
         dsp->attribute = attribute;
         smb_Get8Dot3MaskFromPath(mask, pathp);
-        memcpy(dsp->mask, mask, 11);
+        memcpy(dsp->mask, mask, 12);
 
         /* track if this is likely to match a lot of entries */
         if (smb_IsStarMask(mask)) 
@@ -3946,7 +3974,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
          */
         memcpy(&clientCookie, &inCookiep[17], 4);
 
-        memcpy(mask, dsp->mask, 11);
+        memcpy(mask, dsp->mask, 12);
 
         /* assume we're doing a star match if it has continued for more
          * than one call.
@@ -3957,12 +3985,13 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
              nextCookie, dsp->cookie, attribute);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /* try to get the vnode for the path name next */
     lock_ObtainMutex(&dsp->mx);
     if (dsp->scp) {
         scp = dsp->scp;
+       osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
         cm_HoldSCache(scp);
         code = 0;
     } else {
@@ -3976,17 +4005,21 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             smb_ReleaseDirSearch(dsp);
             return CM_ERROR_NOFILES;
         }
+        strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
+        strcpy(dsp->relPath, spacep->data);
+
         code = cm_NameI(cm_data.rootSCachep, spacep->data,
                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
         if (code == 0) {
 #ifdef DFS_SUPPORT
             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+                int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
                 cm_ReleaseSCache(scp);
                 lock_ReleaseMutex(&dsp->mx);
                 cm_ReleaseUser(userp);
                 smb_DeleteDirSearch(dsp);
                 smb_ReleaseDirSearch(dsp);
-                if ( WANTS_DFS_PATHNAMES(inp) )
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
                     return CM_ERROR_BADSHARENAME;
@@ -3994,6 +4027,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 #endif /* DFS_SUPPORT */
 
             dsp->scp = scp;
+           osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
             /* we need one hold for the entry we just stored into,
              * and one for our own processing.  When we're done with this
              * function, we'll drop the one for our own processing.
@@ -4006,6 +4040,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                  && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
                 dsp->flags |= SMB_DIRSEARCH_BULKST;
+               dsp->scp->bulkStatProgress = hzero;
             }
             lock_ReleaseMutex(&scp->mx);
         }
@@ -4037,6 +4072,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         return code;
     }
         
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     dirLength = scp->length;
     bufferp = NULL;
     bufferOffset.LowPart = bufferOffset.HighPart = 0;
@@ -4106,19 +4143,20 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
              * the status info for files in the dir.
              */
             if (starPattern) {
-                smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
+                smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
                 lock_ObtainMutex(&scp->mx);
                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
                      LargeIntegerGreaterThanOrEqualTo(thyper, 
                                                       scp->bulkStatProgress)) {
                     /* Don't bulk stat if risking timeout */
                     int now = GetTickCount();
-                    if (now - req.startTime > 5000) {
+                    if (now - req.startTime > RDRtimeout * 1000) {
                         scp->bulkStatProgress = thyper;
                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
+                       dsp->scp->bulkStatProgress = hzero;
                     } else
-                        cm_TryBulkStat(scp, &thyper, userp, &req);
+                        code = cm_TryBulkStat(scp, &thyper, userp, &req);
                 }
             } else {
                 lock_ObtainMutex(&scp->mx);
@@ -4142,6 +4180,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                     break;
                 }
                                 
+               cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
                 if (cm_HaveBuffer(scp, bufferp, 0)) {
                     osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
                     break;
@@ -4238,6 +4278,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
                           fileType);
                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
+                    fileType == CM_SCACHETYPE_MOUNTPOINT ||
                     fileType == CM_SCACHETYPE_DFSLINK ||
                     fileType == CM_SCACHETYPE_INVALID)
                     osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
@@ -4317,12 +4358,15 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 
     /* release the mutex */
     lock_ReleaseMutex(&scp->mx);
-    if (bufferp) buf_Release(bufferp);
+    if (bufferp) {
+       buf_Release(bufferp);
+       bufferp = NULL;
+    }
 
     /* apply and free last set of patches; if not doing a star match, this
      * will be empty, but better safe (and freeing everything) than sorry.
      */
-    smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
+    smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
 
     /* special return code for unsuccessful search */
     if (code == 0 && dataLength < 21 && returnedNames == 0)
@@ -4350,7 +4394,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
      * Deduct for them and fill in the length field.
      */
     temp -= 3;         /* deduct vbl block info */
-    osi_assert(temp == (43 * returnedNames));
+    osi_assertx(temp == (43 * returnedNames), "unexpected data length");
     origOp[1] = (char)(temp & 0xff);
     origOp[2] = (char)((temp>>8) & 0xff);
     if (returnedNames == 0) 
@@ -4389,7 +4433,7 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         
     rootScp = cm_data.rootSCachep;
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -4409,9 +4453,10 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         
 #ifdef DFS_SUPPORT
     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
         cm_ReleaseSCache(newScp);
         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;
@@ -4422,11 +4467,15 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     lock_ObtainMutex(&newScp->mx);
     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
-    if (code && code != CM_ERROR_NOACCESS) {
-        lock_ReleaseMutex(&newScp->mx);
-        cm_ReleaseSCache(newScp);
-        cm_ReleaseUser(userp);
-        return code;
+    if (code) {
+       if (code != CM_ERROR_NOACCESS) {
+           lock_ReleaseMutex(&newScp->mx);
+           cm_ReleaseSCache(newScp);
+           cm_ReleaseUser(userp);
+           return code;
+       }
+    } else {
+       cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     }
 
     attrs = smb_Attributes(newScp);
@@ -4473,7 +4522,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 
     rootScp = cm_data.rootSCachep;
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -4489,12 +4538,13 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         cm_ReleaseUser(userp);
         return code;
     }
-       
+
 #ifdef DFS_SUPPORT
     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
         cm_ReleaseSCache(newScp);
         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;
@@ -4515,6 +4565,8 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         return code;
     }
 
+    cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
     /* Check for RO volume */
     if (newScp->flags & CM_SCACHEFLAG_RO) {
         lock_ReleaseMutex(&newScp->mx);
@@ -4529,12 +4581,12 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
     }
-    if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
+    if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
         /* we're told to make a writable file read-only */
         attr.unixModeBits = newScp->unixModeBits & ~0222;
         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
     }
-    else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
+    else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
         /* we're told to make a read-only file writable */
         attr.unixModeBits = newScp->unixModeBits | 0222;
         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
@@ -4586,7 +4638,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 
     rootScp = cm_data.rootSCachep;
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /* we shouldn't need this for V3 requests, but we seem to */
     caseFold = CM_FLAG_CASEFOLD;
@@ -4624,7 +4676,8 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         if (code == 0) {
 #ifdef DFS_SUPPORT
             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-                if ( WANTS_DFS_PATHNAMES(inp) )
+                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
                     return CM_ERROR_BADSHARENAME;
@@ -4634,9 +4687,10 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
                 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);
-                else
+                   bp = NULL;
+               } else
                     code = CM_ERROR_NOSUCHFILE;
             }
             cm_ReleaseSCache(dscp);
@@ -4657,9 +4711,10 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         
 #ifdef DFS_SUPPORT
     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
         cm_ReleaseSCache(newScp);
         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;
@@ -4677,12 +4732,15 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         return code;
     }
 
+    cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+
 #ifdef undef
     /* use smb_Attributes instead.   Also the fact that a file is 
      * in a readonly volume doesn't mean it shojuld be marked as RO 
      */
     if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
-        newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
+        newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
+       newScp->fileType == CM_SCACHETYPE_INVALID)
         attrs = SMB_ATTR_DIRECTORY;
     else
         attrs = 0;
@@ -4722,9 +4780,9 @@ long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_
     /* find the tree and free it */
     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
     if (tidp) {
-        lock_ObtainMutex(&tidp->mx);
-        tidp->flags |= SMB_TIDFLAG_DELETE;
-        lock_ReleaseMutex(&tidp->mx);
+       lock_ObtainWrite(&smb_rctLock);
+        tidp->delete = 1;
+        lock_ReleaseWrite(&smb_rctLock);
         smb_ReleaseTID(tidp);
     }
 
@@ -4790,7 +4848,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return 0;
     }
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -4809,9 +4867,10 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
 #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(inp) )
+        if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
             return CM_ERROR_BADSHARENAME;
@@ -4836,21 +4895,26 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
-    osi_assert(fidp);
+    osi_assertx(fidp, "null smb_fid_t");
 
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
+    lock_ObtainMutex(&scp->mx);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseMutex(&scp->mx);
+
     /* and the user */
     cm_HoldUser(userp);
     fidp->userp = userp;
 
     lock_ObtainMutex(&fidp->mx);
     if ((share & 0xf) == 0)
-        fidp->flags |= SMB_FID_OPENREAD;
+        fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     else if ((share & 0xf) == 1)
         fidp->flags |= SMB_FID_OPENWRITE;
     else 
-        fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
+        fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
     lock_ReleaseMutex(&fidp->mx);
 
     lock_ObtainMutex(&scp->mx);
@@ -4884,6 +4948,7 @@ typedef struct smb_unlinkRock {
     char *maskp;               /* pointer to the star pattern */
     int flags;
     int any;
+    cm_dirEntryList_t * matches;
 } smb_unlinkRock_t;
 
 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
@@ -4912,20 +4977,18 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
     }
     if (match) {
-        osi_Log1(smb_logp, "Unlinking %s",
+        osi_Log1(smb_logp, "Found match %s",
                  osi_LogSaveString(smb_logp, matchName));
-        code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
-        if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-            smb_NotifyChange(FILE_ACTION_REMOVED,
-                             FILE_NOTIFY_CHANGE_FILE_NAME,
-                             dscp, dep->name, NULL, TRUE);
-        if (code == 0) {
-            rockp->any = 1;
 
-            /* If we made a case sensitive exact match, we might as well quit now. */
-            if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
-                code = CM_ERROR_STOPNOW;
-        }
+        cm_DirEntryListAdd(dep->name, &rockp->matches);
+
+        rockp->any = 1;
+
+        /* If we made a case sensitive exact match, we might as well quit now. */
+        if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
+            code = CM_ERROR_STOPNOW;
+        else
+            code = 0;
     }
     else code = 0;
 
@@ -4963,7 +5026,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
 
@@ -4981,9 +5044,10 @@ long smb_ReceiveCoreUnlink(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;
@@ -5006,6 +5070,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     rock.reqp = &req;
     rock.dscp = dscp;
     rock.vcp = vcp;
+    rock.matches = NULL;
 
     /* Now, if we aren't dealing with a wildcard match, we first try an exact 
      * match.  If that fails, we do a case insensitve match. 
@@ -5026,6 +5091,24 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (code == CM_ERROR_STOPNOW) 
         code = 0;
 
+    if (code == 0 && rock.matches) {
+        cm_dirEntryList_t * entry;
+
+        for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
+
+            osi_Log1(smb_logp, "Unlinking %s",
+                     osi_LogSaveString(smb_logp, entry->name));
+            code = cm_Unlink(dscp, entry->name, userp, &req);
+
+            if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
+                smb_NotifyChange(FILE_ACTION_REMOVED,
+                                 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
+                                 dscp, entry->name, NULL, TRUE);
+        }
+    }
+
+    cm_DirEntryListFree(&rock.matches);
+
     cm_ReleaseUser(userp);
         
     cm_ReleaseSCache(dscp);
@@ -5044,6 +5127,8 @@ typedef struct smb_renameRock {
     char *maskp;               /* pointer to star pattern of old file name */
     int flags;             /* tilde, casefold, etc */
     char *newNamep;            /* ptr to the new file's name */
+    char oldName[MAX_PATH];
+    int any;
 } smb_renameRock_t;
 
 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
@@ -5052,7 +5137,7 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     smb_renameRock_t *rockp;
     int caseFold;
     int match;
-    char shortName[13];
+    char shortName[13]="";
 
     rockp = (smb_renameRock_t *) vrockp;
 
@@ -5067,17 +5152,15 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
         cm_Gen8Dot3Name(dep, shortName, NULL);
         match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
     }
+
     if (match) {
-        code = cm_Rename(rockp->odscp, dep->name,
-                         rockp->ndscp, rockp->newNamep, rockp->userp,
-                         rockp->reqp); 
-        /* if the call worked, stop doing the search now, since we
-         * really only want to rename one file.
-         */
-        if (code == 0) 
+       rockp->any = 1;
+        strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
+        rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
             code = CM_ERROR_STOPNOW;
-    }       
-    else code = 0;
+    } else {
+       code = 0;
+    }
 
     return code;
 }
@@ -5102,7 +5185,7 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     DWORD filter;
     cm_req_t req;
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
     if (code) {
         cm_ReleaseUser(userp);
@@ -5123,9 +5206,10 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
         
 #ifdef DFS_SUPPORT
     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
         cm_ReleaseSCache(oldDscp);
         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;
@@ -5144,10 +5228,11 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
 
 #ifdef DFS_SUPPORT
     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
         cm_ReleaseSCache(oldDscp);
         cm_ReleaseSCache(newDscp);
         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;
@@ -5182,12 +5267,16 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     rock.maskp = oldLastNamep;
     rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
     rock.newNamep = newLastNamep;
+    rock.oldName[0] = '\0';
+    rock.any = 0;
 
     /* Check if the file already exists; if so return error */
     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
-    if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
+    if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
+        (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
+    {
         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
-                 osi_LogSaveString(afsd_logp, newLastNamep));
+                 osi_LogSaveString(smb_logp, newLastNamep));
 
         /* Check if the old and the new names differ only in case. If so return
          * success, else return CM_ERROR_EXISTS 
@@ -5225,33 +5314,48 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     thyper.HighPart = 0;
 
     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
+    if (code == 0 && !rock.any) {
+       thyper.LowPart = 0;
+       thyper.HighPart = 0;
+        rock.flags |= SMB_MASKFLAG_CASEFOLD;
+       code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
+    }
     osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
 
-    if (code == CM_ERROR_STOPNOW)
-        code = 0;
-    else if (code == 0)
+    if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
+       code = cm_Rename(rock.odscp, rock.oldName,
+                         rock.ndscp, rock.newNamep, rock.userp,
+                         rock.reqp);   
+        /* if the call worked, stop doing the search now, since we
+         * really only want to rename one file.
+         */
+       osi_Log1(smb_logp, "cm_Rename returns %ld", code);
+    } else if (code == 0) {
         code = CM_ERROR_NOSUCHFILE;
+    }
 
     /* Handle Change Notification */
     /*
     * Being lazy, not distinguishing between files and dirs in this
     * filter, since we'd have to do a lookup.
     */
-    filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
-    if (oldDscp == newDscp) {
-        if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
-            smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
-                             filter, oldDscp, oldLastNamep,
-                             newLastNamep, TRUE);
-    } else {
-        if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
-            smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
-                             filter, oldDscp, oldLastNamep,
-                             NULL, TRUE);
-        if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
-            smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
-                             filter, newDscp, newLastNamep,
-                             NULL, TRUE);
+    if (code == 0) {
+        filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
+        if (oldDscp == newDscp) {
+            if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
+                smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
+                                  filter, oldDscp, oldLastNamep,
+                                  newLastNamep, TRUE);
+        } else {
+            if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
+                smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
+                                  filter, oldDscp, oldLastNamep,
+                                  NULL, TRUE);
+            if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
+                smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
+                                  filter, newDscp, newLastNamep,
+                                  NULL, TRUE);
+        }
     }
 
     if (tmpscp != NULL) 
@@ -5280,7 +5384,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     DWORD filter;
     cm_req_t req;
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
     if (code) {
@@ -5304,9 +5408,10 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
         
 #ifdef DFS_SUPPORT
     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
         cm_ReleaseSCache(oldDscp);
         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;
@@ -5324,10 +5429,11 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
 
 #ifdef DFS_SUPPORT
     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
         cm_ReleaseSCache(newDscp);
         cm_ReleaseSCache(oldDscp);
         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;
@@ -5368,9 +5474,11 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
 
     /* Check if the file already exists; if so return error */
     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
-    if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
+    if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) && 
+        (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
+    {
         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
-                 osi_LogSaveString(afsd_logp, newLastNamep));
+                 osi_LogSaveString(smb_logp, newLastNamep));
 
         /* if the existing link is to the same file, then we return success */
         if (!code) {
@@ -5394,7 +5502,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     /* now create the hardlink */
     osi_Log1(smb_logp,"  Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
-    osi_Log1(smb_logp,"  Link returns %d", code);
+    osi_Log1(smb_logp,"  Link returns 0x%x", code);
 
     /* Handle Change Notification */
     if (code == 0) {
@@ -5420,6 +5528,7 @@ smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     char *oldPathp;
     char *newPathp;
     char *tp;
+    long code;
 
     tp = smb_GetSMBData(inp, NULL);
     oldPathp = smb_ParseASCIIBlock(tp, &tp);
@@ -5430,10 +5539,13 @@ smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         OemToChar(newPathp,newPathp);
 
     osi_Log2(smb_logp, "smb rename [%s] to [%s]",
-              osi_LogSaveString(smb_logp, oldPathp),
-              osi_LogSaveString(smb_logp, newPathp));
+             osi_LogSaveString(smb_logp, oldPathp),
+             osi_LogSaveString(smb_logp, newPathp));
 
-    return smb_Rename(vcp,inp,oldPathp,newPathp,0);
+    code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
+
+    osi_Log1(smb_logp, "smb rename returns 0x%x", code);
+    return code;
 }
 
 
@@ -5445,6 +5557,7 @@ typedef struct smb_rmdirRock {
     char *maskp;               /* pointer to the star pattern */
     int flags;
     int any;
+    cm_dirEntryList_t * matches;
 } smb_rmdirRock_t;
 
 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
@@ -5469,20 +5582,13 @@ int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper
         matchName = shortName;
         match = (cm_stricmp(matchName, rockp->maskp) == 0);
     }       
+
     if (match) {
-        osi_Log1(smb_logp, "Removing directory %s",
-                 osi_LogSaveString(smb_logp, matchName));
-        code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
-        if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-            smb_NotifyChange(FILE_ACTION_REMOVED,
-                             FILE_NOTIFY_CHANGE_DIR_NAME,
-                             dscp, dep->name, NULL, TRUE);
-        if (code == 0)
             rockp->any = 1;
+        cm_DirEntryListAdd(dep->name, &rockp->matches);
     }
-    else code = 0;
 
-    return code;
+    return 0;
 }
 
 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
@@ -5510,7 +5616,7 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -5529,9 +5635,10 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         
 #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;
@@ -5553,6 +5660,8 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     rock.userp = userp;
     rock.reqp = &req;
     rock.dscp = dscp;
+    rock.matches = NULL;
+
     /* First do a case sensitive match, and if that fails, do a case insensitive match */
     code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
     if (code == 0 && !rock.any) {
@@ -5562,6 +5671,24 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
     }
 
+    if (code == 0 && rock.matches) {
+        cm_dirEntryList_t * entry;
+
+        for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
+            osi_Log1(smb_logp, "Removing directory %s",
+                     osi_LogSaveString(smb_logp, entry->name));
+
+            code = cm_RemoveDir(dscp, entry->name, userp, &req);
+
+            if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
+                smb_NotifyChange(FILE_ACTION_REMOVED,
+                                 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
+                                 dscp, entry->name, NULL, TRUE);
+        }
+    }
+
+    cm_DirEntryListFree(&rock.matches);
+
     cm_ReleaseUser(userp);
         
     cm_ReleaseSCache(dscp);
@@ -5590,6 +5717,12 @@ long smb_ReceiveCoreFlush(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);
@@ -5598,14 +5731,19 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
     lock_ReleaseMutex(&fidp->mx);
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
-    if (fidp->flags & SMB_FID_OPENWRITE)
-        code = cm_FSync(fidp->scp, userp, &req);
-    else 
+    if (fidp->flags & SMB_FID_OPENWRITE) {
+       cm_scache_t * scp = fidp->scp;
+       cm_HoldSCache(scp);
+       lock_ReleaseMutex(&fidp->mx);
+        code = cm_FSync(scp, userp, &req);
+       cm_ReleaseSCache(scp);
+    } else {
         code = 0;
-    lock_ReleaseMutex(&fidp->mx);
+       lock_ReleaseMutex(&fidp->mx);
+    }
         
     smb_ReleaseFID(fidp);
         
@@ -5665,11 +5803,15 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                   afs_uint32 dosTime) {
     long code = 0;
     cm_req_t req;
-    cm_scache_t *dscp = fidp->NTopen_dscp;
-    char *pathp = fidp->NTopen_pathp;
+    cm_scache_t *dscp = NULL;
+    char *pathp = NULL;
+    cm_scache_t * scp = NULL;
+    cm_scache_t *delscp = NULL;
+    int deleted = 0;
+    int nullcreator = 0;
 
-    osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
-             fidp, fidp->fid, vcp);
+    osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
+             fidp, fidp->fid, scp, vcp);
 
     if (!userp) {
        lock_ObtainMutex(&fidp->mx);
@@ -5686,16 +5828,30 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
     cm_InitReq(&req);
 
-    lock_ObtainMutex(&fidp->mx);
-
-    if (fidp->flags & SMB_FID_DELETE) {
+    lock_ObtainWrite(&smb_rctLock);
+    if (fidp->delete) {
        osi_Log0(smb_logp, "  Fid already closed.");
-       lock_ReleaseMutex(&fidp->mx);
+       lock_ReleaseWrite(&smb_rctLock);
        return CM_ERROR_BADFD;
     }
+    fidp->delete = 1;
+    lock_ReleaseWrite(&smb_rctLock);
+
+    lock_ObtainMutex(&fidp->mx);
+    if (fidp->NTopen_dscp) {
+       dscp = fidp->NTopen_dscp;
+       cm_HoldSCache(dscp);
+    }
+
+    if (fidp->NTopen_pathp) {
+       pathp = strdup(fidp->NTopen_pathp);
+    }
+
+    if (fidp->scp) {
+       scp = fidp->scp;
+       cm_HoldSCache(scp);
+    }
 
-    fidp->flags |= SMB_FID_DELETE;
-        
     /* Don't jump the gun on an async raw write */
     while (fidp->raw_writers) {
         lock_ReleaseMutex(&fidp->mx);
@@ -5704,32 +5860,33 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     }
 
     /* watch for ioctl closes, and read-only opens */
-    if (fidp->scp != NULL &&
+    if (scp != NULL &&
         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
          == SMB_FID_OPENWRITE) {
         if (dosTime != 0 && dosTime != -1) {
-            fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
+            scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
             /* This fixes defect 10958 */
             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
             smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
         }
-        code = cm_FSync(fidp->scp, userp, &req);
+       lock_ReleaseMutex(&fidp->mx);
+        code = cm_FSync(scp, userp, &req);
+       lock_ObtainMutex(&fidp->mx);
     }
     else 
         code = 0;
 
     /* unlock any pending locks */
-    if (!(fidp->flags & SMB_FID_IOCTL) && fidp->scp &&
-        fidp->scp->fileType == CM_SCACHETYPE_FILE) {
+    if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
+        scp->fileType == CM_SCACHETYPE_FILE) {
         cm_key_t key;
-        cm_scache_t * scp;
         long tcode;
 
-        /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
+       lock_ReleaseMutex(&fidp->mx);
+
+       /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
            in zero. */
         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
-        scp = fidp->scp;
-        cm_HoldSCache(scp);
         lock_ObtainMutex(&scp->mx);
 
         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
@@ -5745,49 +5902,100 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
         cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
 
-        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
 
     post_syncopdone:
 
         lock_ReleaseMutex(&scp->mx);
-        cm_ReleaseSCache(scp);
+       lock_ObtainMutex(&fidp->mx);
     }
 
     if (fidp->flags & SMB_FID_DELONCLOSE) {
         char *fullPathp;
 
-        smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
-        if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
+       lock_ReleaseMutex(&fidp->mx);
+
+        code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
+        if (code) {
+            cm_HoldSCache(scp);
+            delscp = scp;
+        }
+        smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
+        if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
             code = cm_RemoveDir(dscp, fullPathp, userp, &req);
-            if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-                smb_NotifyChange(FILE_ACTION_REMOVED,
-                                 FILE_NOTIFY_CHANGE_DIR_NAME,
-                                 dscp, fullPathp, NULL, TRUE);
+           if (code == 0) {
+               deleted = 1;
+               if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+                   smb_NotifyChange(FILE_ACTION_REMOVED,
+                                     FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
+                                     dscp, fullPathp, NULL, TRUE);
+           }
         } else {
             code = cm_Unlink(dscp, fullPathp, userp, &req);
-            if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-                smb_NotifyChange(FILE_ACTION_REMOVED,
-                                 FILE_NOTIFY_CHANGE_FILE_NAME,
-                                 dscp, fullPathp, NULL, TRUE);
+           if (code == 0) {                            
+               deleted = 1;
+               if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+                   smb_NotifyChange(FILE_ACTION_REMOVED,
+                                     FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
+                                     dscp, fullPathp, NULL, TRUE);
+           }
         }
         free(fullPathp);
+       lock_ObtainMutex(&fidp->mx);
        fidp->flags &= ~SMB_FID_DELONCLOSE;
     }
 
+    /* if this was a newly created file, then clear the creator
+     * in the stat cache entry. */
+    if (fidp->flags & SMB_FID_CREATED) {
+       nullcreator = 1;
+       fidp->flags &= ~SMB_FID_CREATED;
+    }
+
     if (fidp->flags & SMB_FID_NTOPEN) {
+       cm_ReleaseSCache(fidp->NTopen_dscp);
        fidp->NTopen_dscp = NULL;
+       free(fidp->NTopen_pathp);
         fidp->NTopen_pathp = NULL;
        fidp->flags &= ~SMB_FID_NTOPEN;
+    } else {
+       osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
+       osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
     }
+
     if (fidp->NTopen_wholepathp) {
-        free(fidp->NTopen_wholepathp);
-        fidp->NTopen_wholepathp = NULL;
+       free(fidp->NTopen_wholepathp);
+       fidp->NTopen_wholepathp = NULL;
+    }
+
+    if (fidp->scp) {
+       cm_ReleaseSCache(fidp->scp);
+       fidp->scp = NULL;
     }
     lock_ReleaseMutex(&fidp->mx);
 
     if (dscp)
        cm_ReleaseSCache(dscp);
 
+    if (delscp) {
+       if (deleted) {
+           lock_ObtainMutex(&delscp->mx);
+           if (deleted)
+               delscp->flags |= CM_SCACHEFLAG_DELETED;
+           lock_ReleaseMutex(&delscp->mx);
+       }
+        cm_ReleaseSCache(delscp);
+    }
+
+    if (scp) {
+       lock_ObtainMutex(&scp->mx);
+        if (nullcreator && scp->creator == userp)
+            scp->creator = NULL;
+       scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
+       lock_ReleaseMutex(&scp->mx);
+       cm_ReleaseSCache(scp);
+    }
+
     if (pathp)
        free(pathp);
 
@@ -5813,7 +6021,7 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return CM_ERROR_BADFD;
     }
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     code = smb_CloseFID(vcp, fidp, userp, dosTime);
     
@@ -5825,13 +6033,8 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 /*
  * smb_ReadData -- common code for Read, Read And X, and Raw Read
  */
-#ifndef DJGPP
 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
        cm_user_t *userp, long *readp)
-#else /* DJGPP */
-long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
-       cm_user_t *userp, long *readp, int dosflag)
-#endif /* !DJGPP */
 {
     osi_hyper_t offset;
     long code = 0;
@@ -5843,7 +6046,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     osi_hyper_t bufferOffset;
     long bufIndex, nbytes;
     int chunk;
-    int sequential = 0;
+    int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
     cm_req_t req;
 
     cm_InitReq(&req);
@@ -5853,6 +6056,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
     lock_ObtainMutex(&fidp->mx);
     scp = fidp->scp;
+    cm_HoldSCache(scp);
     lock_ObtainMutex(&scp->mx);
 
     if (offset.HighPart == 0) {
@@ -5861,14 +6065,18 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
             fidp->prev_chunk = fidp->curr_chunk;
             fidp->curr_chunk = chunk;
         }
-        if (fidp->curr_chunk == fidp->prev_chunk + 1)
+        if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
             sequential = 1;
     }
+    lock_ReleaseMutex(&fidp->mx);
 
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-    if (code) goto done;
+    if (code) 
+       goto done;
+
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
     /* now we have the entry locked, look up the length */
     fileLength = scp->length;
@@ -5924,8 +6132,11 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
                                  CM_SCACHESYNC_NEEDCALLBACK |
                                  CM_SCACHESYNC_READ);
-                if (code) goto done;
-                                
+                if (code) 
+                   goto done;
+                    
+               cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
+
                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
 
                 /* otherwise, load the buffer and try again */
@@ -5949,12 +6160,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
         if (nbytes > count) nbytes = count;    /* don't go past EOF */
 
         /* now copy the data */
-#ifdef DJGPP
-        if (dosflag)
-            dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
-        else
-#endif /* DJGPP */
-            memcpy(op, bufferp->datap + bufIndex, nbytes);
+       memcpy(op, bufferp->datap + bufIndex, nbytes);
                 
         /* adjust counters, pointers, etc. */
         op += nbytes;
@@ -5966,26 +6172,22 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
   done:
     lock_ReleaseMutex(&scp->mx);
-    lock_ReleaseMutex(&fidp->mx);
-    if (bufferp) 
+    if (bufferp)
         buf_Release(bufferp);
 
     if (code == 0 && sequential)
         cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
 
+    cm_ReleaseSCache(scp);
+
     return code;
 }
 
 /*
  * smb_WriteData -- common code for Write and Raw Write
  */
-#ifndef DJGPP
 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
        cm_user_t *userp, long *writtenp)
-#else /* DJGPP */
-long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
-       cm_user_t *userp, long *writtenp, int dosflag)
-#endif /* !DJGPP */
 {
     osi_hyper_t offset;
     long code = 0;
@@ -5993,11 +6195,11 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     cm_scache_t *scp;
     osi_hyper_t fileLength;    /* file's length at start of write */
     osi_hyper_t minLength;     /* don't read past this */
-    long nbytes;               /* # of bytes to transfer this iteration */
+    afs_uint32 nbytes;         /* # of bytes to transfer this iteration */
     cm_buf_t *bufferp;
     osi_hyper_t thyper;                /* hyper tmp variable */
     osi_hyper_t bufferOffset;
-    long bufIndex;             /* index in buffer where our data is */
+    afs_uint32 bufIndex;               /* index in buffer where our data is */
     int doWriteBack;
     osi_hyper_t writeBackOffset;/* offset of region to write back when
                                  * I/O is done */
@@ -6016,9 +6218,20 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     offset = *offsetp;
 
     lock_ObtainMutex(&fidp->mx);
+    /* make sure we have a writable FD */
+    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
+       osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
+                 fidp->fid, fidp->flags);
+       lock_ReleaseMutex(&fidp->mx);
+        code = CM_ERROR_BADFDOP;
+        goto done;
+    }
+    
     scp = fidp->scp;
-    lock_ObtainMutex(&scp->mx);
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
 
+    lock_ObtainMutex(&scp->mx);
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK
@@ -6027,12 +6240,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     if (code) 
         goto done;
         
-    /* make sure we have a writable FD */
-    if (!(fidp->flags & SMB_FID_OPENWRITE)) {
-       lock_ReleaseMutex(&fidp->mx);
-        code = CM_ERROR_BADFDOP;
-        goto done;
-    }
+    cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
 
     /* now we have the entry locked, look up the length */
     fileLength = scp->length;
@@ -6111,6 +6319,11 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 if (code) 
                     goto done;
 
+               cm_SyncOpDone(scp, bufferp, 
+                              CM_SCACHESYNC_NEEDCALLBACK 
+                              | CM_SCACHESYNC_WRITE 
+                              | CM_SCACHESYNC_BUFLOCKED);
+
                 /* If we're overwriting the entire buffer, or
                  * if we're writing at or past EOF, mark the
                  * buffer as current so we don't call
@@ -6167,13 +6380,8 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
             nbytes = count;    /* don't go past end of request */
 
         /* now copy the data */
-#ifdef DJGPP
-        if (dosflag)
-            dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
-        else
-#endif /* DJGPP */
-            memcpy(bufferp->datap + bufIndex, op, nbytes);
-        buf_SetDirty(bufferp);
+       memcpy(bufferp->datap + bufIndex, op, nbytes);
+        buf_SetDirty(bufferp, bufIndex, nbytes);
 
         /* and record the last writer */
         if (bufferp->userp != userp) {
@@ -6200,6 +6408,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
         buf_Release(bufferp);
     }
 
+    lock_ObtainMutex(&fidp->mx);
     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
@@ -6214,23 +6423,28 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
         osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
                   fidp->fid);
         code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
-        osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns %d",
-                  fidp->fid,code2);
+        osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
+                  fidp->fid, code2);
         lock_ReleaseMutex(&scp->mx);
         cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
                             writeBackOffset.HighPart, cm_chunkSize, 0, userp);
+       /* cm_SyncOpDone is called at the completion of cm_BkgStore */
     }
 
-    osi_Log3(smb_logp, "smb_WriteData fid %d returns %d written %d",
+    cm_ReleaseSCache(scp);
+
+    osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
               fidp->fid, code, *writtenp);
     return code;
 }
 
 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    osi_hyper_t offset;
-    long count, written = 0, total_written = 0;
     unsigned short fd;
+    unsigned short count;
+    osi_hyper_t offset;
+    unsigned short hint;
+    long written = 0, total_written = 0;
     unsigned pid;
     smb_fid_t *fidp;
     long code = 0;
@@ -6242,7 +6456,8 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     fd = smb_GetSMBParm(inp, 0);
     count = smb_GetSMBParm(inp, 1);
     offset.HighPart = 0;       /* too bad */
-    offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
+    offset.LowPart = smb_GetSMBParmLong(inp, 2);
+    hint = smb_GetSMBParm(inp, 4);
 
     op = smb_GetSMBData(inp, NULL);
     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
@@ -6252,36 +6467,27 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
-    if (!fidp)
+    if (!fidp) {
+       osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
         return CM_ERROR_BADFD;
+    }
         
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
         code = smb_IoctlWrite(fidp, vcp, inp, outp);
        smb_ReleaseFID(fidp);
+       osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
        return code;
     }
     lock_ReleaseMutex(&fidp->mx);
-    userp = smb_GetUser(vcp, inp);
-
-    /* special case: 0 bytes transferred means truncate to this position */
-    if (count == 0) {
-        cm_req_t req;
-
-        cm_InitReq(&req);
-
-        truncAttr.mask = CM_ATTRMASK_LENGTH;
-        truncAttr.length.LowPart = offset.LowPart;
-        truncAttr.length.HighPart = 0;
-        lock_ObtainMutex(&fidp->mx);
-        code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
-       fidp->flags |= SMB_FID_LENGTHSETDONE;
-        lock_ReleaseMutex(&fidp->mx);
-        smb_SetSMBParm(outp, 0, /* count */ 0);
-        smb_SetSMBDataLength(outp, 0);
-        goto done;
-    }
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     {
         cm_key_t key;
@@ -6300,8 +6506,30 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
         lock_ReleaseMutex(&fidp->scp->mx);
 
-        if (code)
+        if (code) {
+           osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
             goto done;
+       }
+    }
+
+    /* special case: 0 bytes transferred means truncate to this position */
+    if (count == 0) {
+        cm_req_t req;
+
+       osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
+        
+        cm_InitReq(&req);
+
+        truncAttr.mask = CM_ATTRMASK_LENGTH;
+        truncAttr.length.LowPart = offset.LowPart;
+        truncAttr.length.HighPart = 0;
+        lock_ObtainMutex(&fidp->mx);
+        code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
+       fidp->flags |= SMB_FID_LENGTHSETDONE;
+        lock_ReleaseMutex(&fidp->mx);
+       smb_SetSMBParm(outp, 0, 0 /* count */);
+       smb_SetSMBDataLength(outp, 0);
+       goto done;
     }
 
     /*
@@ -6323,24 +6551,26 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     code = 0;
     while ( code == 0 && count > 0 ) {
-#ifndef DJGPP
        code = smb_WriteData(fidp, &offset, count, op, userp, &written);
-#else /* DJGPP */
-       code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
-#endif /* !DJGPP */
        if (code == 0 && written == 0)
             code = CM_ERROR_PARTIALWRITE;
 
-        offset.LowPart += written;
-        count -= written;
+        offset = LargeIntegerAdd(offset,
+                                 ConvertLongToLargeInteger(written));
+        count -= (unsigned short)written;
         total_written += written;
         written = 0;
     }
     
+    osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
+             total_written, code);
+        
     /* set the packet data length to 3 bytes for the data block header,
      * plus the size of the data.
      */
     smb_SetSMBParm(outp, 0, total_written);
+    smb_SetSMBParmLong(outp, 1, offset.LowPart);
+    smb_SetSMBParm(outp, 3, hint);
     smb_SetSMBDataLength(outp, 0);
 
   done:
@@ -6356,33 +6586,27 @@ void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
     unsigned short fd;
     smb_fid_t *fidp;
     cm_user_t *userp;
-#ifndef DJGPP
     char *rawBuf;
-#else /* DJGPP */
-    dos_ptr rawBuf;
-#endif /* !DJGPP */
     long written = 0;
     long code = 0;
 
     fd = smb_GetSMBParm(inp, 0);
     fidp = smb_FindFID(vcp, fd, 0);
 
-    osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
-             rwcp->offset.LowPart, rwcp->count);
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return;
+    }
+
+    osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
+             rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
-#ifndef DJGPP
     rawBuf = rwcp->buf;
     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
                                                 &written);
-#else /* DJGPP */
-    rawBuf = (dos_ptr) rwcp->buf;
-    code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
-                         (unsigned char *) rawBuf, userp,
-                         &written, TRUE);
-#endif /* !DJGPP */
-
     if (rwcp->writeMode & 0x1) {       /* synchronous */
         smb_t *op;
 
@@ -6404,11 +6628,7 @@ void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
 
     /* Give back raw buffer */
     lock_ObtainMutex(&smb_RawBufLock);
-#ifndef DJGPP
     *((char **)rawBuf) = smb_RawBufs;
-#else /* DJGPP */
-    _farpokel(_dos_ds, rawBuf, smb_RawBufs);
-#endif /* !DJGPP */
     smb_RawBufs = rawBuf;
     lock_ReleaseMutex(&smb_RawBufLock);
 
@@ -6432,32 +6652,61 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     cm_user_t *userp;
     char *op;
     unsigned short writeMode;
-#ifndef DJGPP
     char *rawBuf;
-#else /* DJGPP */
-    dos_ptr rawBuf;
-#endif /* !DJGPP */
-
     fd = smb_GetSMBParm(inp, 0);
     totalCount = smb_GetSMBParm(inp, 1);
     count = smb_GetSMBParm(inp, 10);
-    offset.HighPart = 0;       /* too bad */
-    offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
     writeMode = smb_GetSMBParm(inp, 7);
 
     op = (char *) inp->data;
     op += smb_GetSMBParm(inp, 11);
 
-    osi_Log4(smb_logp,
-             "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
-             fd, offset.LowPart, count, writeMode);
-        
+    offset.HighPart = 0;
+    offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
+
+    if (*inp->wctp == 14) {
+        /* we received a 64-bit file offset */
+#ifdef AFS_LARGEFILES
+        offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
+
+        if (LargeIntegerLessThanZero(offset)) {
+            osi_Log2(smb_logp,
+                     "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
+                     offset.HighPart, offset.LowPart);
+            return CM_ERROR_BADSMB;
+        }
+#else
+        if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
+            osi_Log0(smb_logp,
+                     "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
+            return CM_ERROR_BADSMB;
+        }
+
+        offset.HighPart = 0;
+#endif
+    } else {
+        offset.HighPart = 0;    /* 32-bit file offset */
+    }
+    
+    osi_Log4(smb_logp,
+             "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
+             fd, offset.HighPart, offset.LowPart, count);
+    osi_Log1(smb_logp,
+             "               WriteRaw WriteMode 0x%x",
+             writeMode);
+        
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
     if (!fidp) {
         return CM_ERROR_BADFD;
     }
 
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     {
         unsigned pid;
         cm_key_t key;
@@ -6482,7 +6731,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         }
     }
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /*
      * Work around bug in NT client
@@ -6503,15 +6752,13 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
     code = 0;
     while ( code == 0 && count > 0 ) {
-#ifndef DJGPP
        code = smb_WriteData(fidp, &offset, count, op, userp, &written);
-#else /* DJGPP */
-       code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
-#endif /* !DJGPP */
        if (code == 0 && written == 0)
             code = CM_ERROR_PARTIALWRITE;
 
-        offset.LowPart += written;
+        offset = LargeIntegerAdd(offset,
+                                 ConvertLongToLargeInteger(written));
+
         count -= written;
         total_written += written;
         written = 0;
@@ -6524,11 +6771,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         if (smb_RawBufs) {
             /* Get a raw buf, from head of list */
             rawBuf = smb_RawBufs;
-#ifndef DJGPP
             smb_RawBufs = *(char **)smb_RawBufs;
-#else /* DJGPP */
-            smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
-#endif /* !DJGPP */
         }
         else
             code = CM_ERROR_USESTD;
@@ -6555,10 +6798,13 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         return code;
     }
 
+    offset = LargeIntegerAdd(offset,
+                             ConvertLongToLargeInteger(count));
+
     rwcp->code = 0;
     rwcp->buf = rawBuf;
-    rwcp->offset.HighPart = 0;
-    rwcp->offset.LowPart = offset.LowPart + count;
+    rwcp->offset.HighPart = offset.HighPart;
+    rwcp->offset.LowPart = offset.LowPart;
     rwcp->count = totalCount - count;
     rwcp->writeMode = writeMode;
     rwcp->alreadyWritten = total_written;
@@ -6596,6 +6842,12 @@ long smb_ReceiveCoreRead(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);
@@ -6626,7 +6878,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         return code;
     }
         
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     /* remember this for final results */
     smb_SetSMBParm(outp, 0, count);
@@ -6650,11 +6902,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     *op++ = (unsigned char) (count & 0xff);
     *op++ = (unsigned char) ((count >> 8) & 0xff);
                 
-#ifndef DJGPP
     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
-#else /* DJGPP */
-    code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
-#endif /* !DJGPP */
 
     /* fix some things up */
     smb_SetSMBParm(outp, 0, finalCount);
@@ -6700,7 +6948,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -6721,9 +6969,10 @@ long smb_ReceiveCoreMakeDir(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;
@@ -6739,7 +6988,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         lastNamep++;
     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
     if (scp) cm_ReleaseSCache(scp);
-    if (code != CM_ERROR_NOSUCHFILE) {
+    if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
         if (code == 0) code = CM_ERROR_EXISTS;
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
@@ -6803,6 +7052,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     afs_uint32 dosTime;
     char *tidPathp;
     cm_req_t req;
+    int created = 0;                   /* the file was new */
 
     cm_InitReq(&req);
 
@@ -6814,7 +7064,8 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         
     /* compute initial mode bits based on read-only flag in attributes */
     initialModeBits = 0666;
-    if (attributes & 1) initialModeBits &= ~0222;
+    if (attributes & SMB_ATTR_READONLY) 
+       initialModeBits &= ~0222;
         
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(tp, &tp);
@@ -6824,7 +7075,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     caseFold = CM_FLAG_CASEFOLD;
 
@@ -6843,9 +7094,10 @@ long smb_ReceiveCoreCreate(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;
@@ -6874,7 +7126,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 #endif    
 
     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
-    if (code && code != CM_ERROR_NOSUCHFILE) {
+    if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         return code;
@@ -6902,11 +7154,13 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
                          &req);
-        if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
-            smb_NotifyChange(FILE_ACTION_ADDED,
-                             FILE_NOTIFY_CHANGE_FILE_NAME,
-                             dscp, lastNamep, NULL, TRUE);
-        if (!excl && code == CM_ERROR_EXISTS) {
+        if (code == 0) {
+           created = 1;
+           if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
+               smb_NotifyChange(FILE_ACTION_ADDED,     
+                                FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
+                                dscp, lastNamep, NULL, TRUE);
+       } else if (!excl && code == CM_ERROR_EXISTS) {
             /* not an exclusive create, and someone else tried
              * creating it already, then we open it anyway.  We
              * don't bother retrying after this, since if this next
@@ -6943,16 +7197,26 @@ long smb_ReceiveCoreCreate(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);
     /* always create it open for read/write */
-    fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
+    fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
+
+    /* remember that the file was newly created */
+    if (created)
+       fidp->flags |= SMB_FID_CREATED;
+
+    osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
 
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    lock_ObtainMutex(&scp->mx);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseMutex(&scp->mx);
+    
     /* and the user */
     fidp->userp = userp;
     lock_ReleaseMutex(&fidp->mx);
@@ -6971,6 +7235,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     long code = 0;
+    osi_hyper_t new_offset;
     long offset;
     int whence;
     unsigned short fd;
@@ -6988,10 +7253,15 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* try to find the file descriptor */
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
-
     if (!fidp)
        return CM_ERROR_BADFD;
     
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL) {
        lock_ReleaseMutex(&fidp->mx);
@@ -7000,30 +7270,38 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
     lock_ReleaseMutex(&fidp->mx);
        
-    userp = smb_GetUser(vcp, inp);
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
     scp = fidp->scp;
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
     lock_ObtainMutex(&scp->mx);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code == 0) {
+       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         if (whence == 1) {
             /* offset from current offset */
-            offset += fidp->offset;
+            new_offset = LargeIntegerAdd(fidp->offset,
+                                         ConvertLongToLargeInteger(offset));
         }
         else if (whence == 2) {
             /* offset from current EOF */
-            offset += scp->length.LowPart;
+            new_offset = LargeIntegerAdd(scp->length,
+                                         ConvertLongToLargeInteger(offset));
+        } else {
+            new_offset = ConvertLongToLargeInteger(offset);
         }
-        fidp->offset = offset;
-        smb_SetSMBParm(outp, 0, offset & 0xffff);
-        smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
+
+        fidp->offset = new_offset;
+        smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
+        smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
         smb_SetSMBDataLength(outp, 0);
     }
     lock_ReleaseMutex(&scp->mx);
-    lock_ReleaseMutex(&fidp->mx);
     smb_ReleaseFID(fidp);
+    cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
     return code;
 }
@@ -7065,10 +7343,8 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
     /* Sanity check */
     if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
         /* log it and discard it */
-#ifndef DJGPP
        LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT, 
                 __FILE__, __LINE__, ncbp->ncb_length);
-#endif /* !DJGPP */
        osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
         return;
     }
@@ -7141,10 +7417,8 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
 
             if (oldGen != sessionGen) {
                 newTime = GetTickCount();
-#ifndef DJGPP
                LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
                         newTime - oldTime, ncbp->ncb_length);
-#endif /* !DJGPP */
                osi_Log2(smb_logp, "Pkt straddled session startup, "
                           "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
             }
@@ -7156,7 +7430,6 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
             smb_LogPacket(inp);
 #endif  /* LOG_PACKET */
 
-#ifndef DJGPP
             if (showErrors) {
                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
@@ -7164,16 +7437,13 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                 if (code == IDCANCEL) 
                     showErrors = 0;
             }
-#endif /* DJGPP */
             code = CM_ERROR_BADOP;
         }
 
         /* catastrophic failure:  log as much as possible */
         if (code == CM_ERROR_BADSMB) {
-#ifndef DJGPP
            LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID, 
                     ncbp->ncb_length);
-#endif /* !DJGPP */
 #ifdef LOG_PACKET
             smb_LogPacket(inp);
 #endif /* LOG_PACKET */
@@ -7281,29 +7551,9 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
         smb_SendPacket(vcp, outp);
     thrd_Decrement(&ongoingOps);
 
-    if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
-        if (active_vcp != vcp) {
-            if (active_vcp) {
-                osi_Log2(smb_logp,
-                      "Replacing active_vcp %x with %x", active_vcp, vcp);
-                smb_ReleaseVC(active_vcp);
-            }
-            smb_HoldVC(vcp);
-           lock_ObtainWrite(&smb_globalLock);
-            active_vcp = vcp;
-           lock_ReleaseWrite(&smb_globalLock);
-        }
-        last_msg_time = GetTickCount();
-    } else if (active_vcp == vcp) {    /* the vcp is dead */
-        smb_ReleaseVC(active_vcp);
-       lock_ObtainWrite(&smb_globalLock);
-        active_vcp = NULL;
-       lock_ReleaseWrite(&smb_globalLock);
-    }
     return;
 }
 
-#ifndef DJGPP
 /* Wait for Netbios() calls to return, and make the results available to server
  * threads.  Note that server threads can't wait on the NCBevents array
  * themselves, because NCB events are manual-reset, and the servers would race
@@ -7350,14 +7600,13 @@ void smb_ClientWaiter(void *parmp)
         {
             /* this is fatal - log as much as possible */
             osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
-            osi_assert(0);
+            osi_assertx(0, "invalid index");
         }
         
         thrd_ResetEvent(NCBevents[idx]);
         thrd_SetEvent(NCBreturns[0][idx]);
     }
 }
-#endif /* !DJGPP */
 
 /*
  * Try to have one NCBRECV request waiting for every live session.  Not more
@@ -7368,9 +7617,6 @@ void smb_ServerWaiter(void *parmp)
     DWORD code;
     int idx_session, idx_NCB;
     NCB *ncbp;
-#ifdef DJGPP
-    dos_ptr dos_ncb;
-#endif /* DJGPP */
 
     while (smbShutdownFlag == 0) {
         /* Get a session */
@@ -7408,7 +7654,7 @@ void smb_ServerWaiter(void *parmp)
         {
             /* this is fatal - log as much as possible */
             osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
-            osi_assert(0);
+            osi_assertx(0, "invalid index");
         }
 
                /* Get an NCB */
@@ -7452,7 +7698,7 @@ void smb_ServerWaiter(void *parmp)
         {
             /* this is fatal - log as much as possible */
             osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
-            osi_assert(0);
+            osi_assertx(0, "invalid index");
         }
 
         /* Link them together */
@@ -7463,19 +7709,10 @@ void smb_ServerWaiter(void *parmp)
         ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
         ncbp->ncb_command = NCBRECV | ASYNCH;
         ncbp->ncb_lana_num = lanas[idx_session];
-#ifndef DJGPP
         ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
         ncbp->ncb_event = NCBevents[idx_NCB];
         ncbp->ncb_length = SMB_PACKETSIZE;
         Netbios(ncbp);
-#else /* DJGPP */
-        ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
-        ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
-        ncbp->ncb_event = NCBreturns[0][idx_NCB];
-        ncbp->ncb_length = SMB_PACKETSIZE;
-        dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
-        Netbios(ncbp, dos_ncb);
-#endif /* !DJGPP */
     }
 }
 
@@ -7501,9 +7738,6 @@ void smb_Server(VOID *parmp)
     UCHAR rc;
     smb_vc_t *vcp = NULL;
     smb_t *smbp;
-#ifdef DJGPP
-    dos_ptr dos_ncb;
-#endif /* DJGPP */
 
     rx_StartClientThread();
 
@@ -7516,6 +7750,9 @@ void smb_Server(VOID *parmp)
            smb_ReleaseVC(vcp);
            vcp = NULL;
        }
+
+       smb_ResetServerPriority();
+
         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
                                                  FALSE, INFINITE);
 
@@ -7558,13 +7795,10 @@ void smb_Server(VOID *parmp)
         {
             /* this is fatal - log as much as possible */
             osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
-            osi_assert(0);
+            osi_assertx(0, "invalid index");
         }
 
         ncbp = NCBs[idx_NCB];
-#ifdef DJGPP
-        dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
-#endif /* DJGPP */
         idx_session = NCBsessions[idx_NCB];
         rc = ncbp->ncb_retcode;
 
@@ -7583,36 +7817,34 @@ void smb_Server(VOID *parmp)
 
         case NRC_SNUMOUT:
        case NRC_SABORT:
-#ifndef DJGPP
            LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
            /* fallthrough */
-#endif /* !DJGPP */
        case NRC_SCLOSED:
             /* Client closed session */
             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
             if (vcp) {
-               lock_ObtainWrite(&smb_globalLock);
+               lock_ObtainMutex(&vcp->mx);
                if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
                     osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
                              vcp, vcp->usersp);
-                   lock_ObtainMutex(&vcp->mx);
                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-                   dead_sessions[vcp->session] = TRUE;
                    lock_ReleaseMutex(&vcp->mx);
+                   lock_ObtainWrite(&smb_globalLock);
+                   dead_sessions[vcp->session] = TRUE;
                    lock_ReleaseWrite(&smb_globalLock);
                    smb_CleanupDeadVC(vcp);
                    smb_ReleaseVC(vcp);
                    vcp = NULL;
-                }
+                } else {
+                   lock_ReleaseMutex(&vcp->mx);
+               }
             }
             goto doneWithNCB;
 
         case NRC_INCOMP:
             /* Treat as transient error */
-#ifndef DJGPP
            LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE, 
                     ncbp->ncb_length);
-#endif /* !DJGPP */
            osi_Log1(smb_logp,
                     "dispatch smb recv failed, message incomplete, ncb_length %d",
                     ncbp->ncb_length);
@@ -7632,28 +7864,33 @@ void smb_Server(VOID *parmp)
         default:
             /* A weird error code.  Log it, sleep, and continue. */
             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
+           if (vcp) 
+               lock_ObtainMutex(&vcp->mx);
             if (vcp && vcp->errorCount++ > 3) {
                 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
-               lock_ObtainWrite(&smb_globalLock);
                if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
                    osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
                             vcp, vcp->usersp);
-                   lock_ObtainMutex(&vcp->mx);
                    vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-                   dead_sessions[vcp->session] = TRUE;
                    lock_ReleaseMutex(&vcp->mx);
+                   lock_ObtainWrite(&smb_globalLock);
+                   dead_sessions[vcp->session] = TRUE;
                    lock_ReleaseWrite(&smb_globalLock);
                    smb_CleanupDeadVC(vcp);
                    smb_ReleaseVC(vcp);
                    vcp = NULL;
-               }
+               } else {
+                   lock_ReleaseMutex(&vcp->mx);
+               }
                goto doneWithNCB;
             }
             else {
+               if (vcp)
+                   lock_ReleaseMutex(&vcp->mx);
                 thrd_Sleep(1000);
-                thrd_SetEvent(SessionEvents[idx_session]);
+               thrd_SetEvent(SessionEvents[idx_session]);
             }
-            continue;
+           continue;
         }
 
         /* Success, so now dispatch on all the data in the packet */
@@ -7667,6 +7904,8 @@ void smb_Server(VOID *parmp)
          * then we are in big trouble. This means either :
          *   a) we have the wrong NCB.
          *   b) Netbios screwed up the call.
+        *   c) The VC was already marked dead before we were able to
+        *      process the call
          * Obviously this implies that 
          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
          *   lanas[idx_session] != ncbp->ncb_lana_num )
@@ -7681,7 +7920,7 @@ void smb_Server(VOID *parmp)
                      ncbp->ncb_lana_num);
 
             /* Also log in the trace log. */
-            osi_Log4(smb_logp, "Server: BAD VCP!"
+            osi_Log4(smb_logp, "Server: VCP does not exist!"
                       "LSNs[idx_session]=[%d],"
                       "lanas[idx_session]=[%d],"
                       "ncbp->ncb_lsn=[%d],"
@@ -7697,24 +7936,15 @@ void smb_Server(VOID *parmp)
             continue;
         }
 
+       smb_SetRequestStartTime();
+
         vcp->errorCount = 0;
         bufp = (struct smb_packet *) ncbp->ncb_buffer;
-#ifdef DJGPP
-        bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
-        /* copy whole packet to virtual memory */
-        /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
-        "bufp=0x%x\n",
-        bufp->dos_pkt / 16, bufp);*/
-        fflush(stderr);
-        dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
-#endif /* DJGPP */
         smbp = (smb_t *)bufp->data;
         outbufp->flags = 0;
 
-#if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
         __try
         {
-#endif
             if (smbp->com == 0x1d) {
                 /* Special handling for Write Raw */
                 raw_write_cont_t rwc;
@@ -7732,11 +7962,7 @@ void smb_Server(VOID *parmp)
                     ncbp->ncb_buffer = rwc.buf;
                     ncbp->ncb_length = 65535;
                     ncbp->ncb_event = rwevent;
-#ifndef DJGPP
                     Netbios(ncbp);
-#else
-                    Netbios(ncbp, dos_ncb);
-#endif /* !DJGPP */
                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
                     thrd_CloseHandle(rwevent);
                 }
@@ -7756,11 +7982,9 @@ void smb_Server(VOID *parmp)
                 /* TODO: what else needs to be serialized? */
                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
             }
-#if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
         }
         __except( smb_ServerExceptionFilter() ) {
         }
-#endif
 
         smb_concurrentCalls--;
 
@@ -7777,7 +8001,6 @@ void smb_Server(VOID *parmp)
  * force trace and give control to upstream exception handlers. Useful for
  * debugging.
  */
-#if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
 DWORD smb_ServerExceptionFilter(void) {
     /* While this is not the best time to do a trace, if it succeeds, then
      * we have a trace (assuming tracing was enabled). Otherwise, this should
@@ -7788,7 +8011,6 @@ DWORD smb_ServerExceptionFilter(void) {
     buf_ForceTrace(TRUE);
     return EXCEPTION_CONTINUE_SEARCH;
 }       
-#endif
 
 /*
  * Create a new NCB and associated events, packet buffer, and "space" buffer.
@@ -7803,19 +8025,17 @@ void InitNCBslot(int idx)
     int i;
     char eventName[MAX_PATH];
 
-    osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
+    osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
 
     NCBs[idx] = GetNCB();
     sprintf(eventName,"NCBavails[%d]", idx);
     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
     if ( GetLastError() == ERROR_ALREADY_EXISTS )
         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
-#ifndef DJGPP
     sprintf(eventName,"NCBevents[%d]", idx);
     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
     if ( GetLastError() == ERROR_ALREADY_EXISTS )
         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
-#endif /* !DJGPP */
     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
     if ( GetLastError() == ERROR_ALREADY_EXISTS )
@@ -7840,22 +8060,21 @@ void smb_Listener(void *parmp)
     char rname[NCBNAMSZ+1];
     char cname[MAX_COMPUTERNAME_LENGTH+1];
     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
-#ifdef DJGPP
-    dos_ptr dos_ncb;
-    time_t now;
-#endif /* DJGPP */
     INT_PTR lana = (INT_PTR) parmp;
+    char eventName[MAX_PATH];
+
+    sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
+    ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
+    if ( GetLastError() == ERROR_ALREADY_EXISTS )
+        thrd_ResetEvent(ListenerShutdown[lana]);
 
     ncbp = GetNCB();
-#ifdef DJGPP
-    dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
-#endif /* DJGPP */
 
     /* retrieve computer name */
     GetComputerName(cname, &cnamelen);
     _strupr(cname);
 
-    while (1) {
+    while (smb_ListenerState == SMB_LISTENER_STARTED) {
         memset(ncbp, 0, sizeof(NCB));
         flags = 0;
 
@@ -7873,52 +8092,84 @@ void smb_Listener(void *parmp)
         
         ncbp->ncb_lana_num = (UCHAR)lana;
 
-#ifndef DJGPP
         code = Netbios(ncbp);
-#else /* DJGPP */
-        code = Netbios(ncbp, dos_ncb);
-#endif
 
-        if (code != 0)
-        {
-#ifndef DJGPP
-            char tbuffer[256];
+        if (code == NRC_NAMERR) {
+         /* An smb shutdown or Vista resume must have taken place */
+         osi_Log2(smb_logp,
+                  "NCBLISTEN lana=%d failed with NRC_NAMERR.",
+                  ncbp->ncb_lana_num, code);
+
+            if (lock_TryMutex(&smb_StartedLock)) {
+                lana_list.lana[i] = LANA_INVALID;
+               lock_ReleaseMutex(&smb_StartedLock);
+           }
+            break;
+        } else if (code ==  NRC_BRIDGE || code != 0) {
+            int lanaRemaining = 0;
+
+            while (!lock_TryMutex(&smb_StartedLock)) {
+                if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
+                    goto exit_thread;
+                Sleep(50);
+            }
+            osi_Log2(smb_logp,
+                      "NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
+                      ncbp->ncb_lana_num, ncb_error_string(code));
+
+           for (i = 0; i < lana_list.length; i++) {
+               if (lana_list.lana[i] == lana) {
+                   smb_StopListener(ncbp, lana_list.lana[i], FALSE);
+                   lana_list.lana[i] = LANA_INVALID;
+               }
+               if (lana_list.lana[i] != LANA_INVALID)
+                   lanaRemaining++;
+           }
+
+           if (lanaRemaining == 0) {
+                cm_VolStatus_Network_Stopped(cm_NetbiosName
+#ifdef _WIN64
+                                             ,cm_NetbiosName
 #endif
+                                              );
+               smb_ListenerState = SMB_LISTENER_STOPPED;
+               smb_LANadapter = LANA_INVALID;
+               lana_list.length = 0;
+           }
+            lock_ReleaseMutex(&smb_StartedLock);
+           break;
+       }
+#if 0
+        else if (code != 0) {
+            char tbuffer[AFSPATHMAX];
 
             /* terminate silently if shutdown flag is set */
-            if (smbShutdownFlag == 1) {
-#ifndef DJGPP
-                ExitThread(1);
-#else
-                thrd_Exit(1);
-#endif
+            while (!lock_TryMutex(&smb_StartedLock)) {
+                if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
+                    goto exit_thread;
+                Sleep(50);
             }
 
-            osi_Log2(smb_logp, 
-                     "NCBLISTEN lana=%d failed with code %d",
-                     ncbp->ncb_lana_num, code);
+            osi_Log3(smb_logp, 
+                     "NCBLISTEN lana=%d failed with code %d [%s]",
+                     ncbp->ncb_lana_num, code, ncb_error_string(code));
             osi_Log0(smb_logp, 
                      "Client exiting due to network failure. Please restart client.\n");
 
-#ifndef DJGPP
             sprintf(tbuffer, 
                      "Client exiting due to network failure.  Please restart client.\n"
-                     "NCBLISTEN lana=%d failed with code %d",
-                     ncbp->ncb_lana_num, code);
+                     "NCBLISTEN lana=%d failed with code %d [%s]",
+                     ncbp->ncb_lana_num, code, ncb_error_string(code));
             if (showErrors)
                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
                                       MB_OK|MB_SERVICE_NOTIFICATION);
-            osi_assert(tbuffer);
-            ExitThread(1);
-#else
-            fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
-                     ncbp->ncb_lana_num, code);
-            fprintf(stderr, "\nClient exiting due to network failure "
-                     "(possibly due to power-saving mode)\n");
-            fprintf(stderr, "Please restart client.\n");
-            afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
-#endif /* !DJGPP */
+            osi_panic(tbuffer, __FILE__, __LINE__);
+
+            lock_ReleaseMutex(&smb_StartedLock);
+            break;
         }
+#endif /* 0 */
 
         /* check for remote conns */
         /* first get remote name and insert null terminator */
@@ -7957,14 +8208,7 @@ void smb_Listener(void *parmp)
                     ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
 
            if (reportSessionStartups) {
-#ifndef DJGPP
                LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
-#else /* DJGPP */
-               time(&now);
-               fprintf(stderr, "%s: New session %d starting from host %s\n",
-                       asctime(localtime(&now)), ncbp->ncb_lsn, rname);
-               fflush(stderr);
-#endif /* !DJGPP */
            }
            
            lock_ObtainMutex(&vcp->mx);
@@ -8000,14 +8244,7 @@ void smb_Listener(void *parmp)
                     ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
 
            if (reportSessionStartups) {
-#ifndef DJGPP
                LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
-#else /* DJGPP */
-               time(&now);
-               fprintf(stderr, "%s: Re-using session %d starting from host %s\n",
-                       asctime(localtime(&now)), ncbp->ncb_lsn, rname);
-               fflush(stderr);
-#endif /* !DJGPP */
            }
        }
 
@@ -8050,16 +8287,25 @@ void smb_Listener(void *parmp)
             smb_FreePacket(outp);
 
            lock_ObtainMutex(&vcp->mx);
-           vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-           lock_ReleaseMutex(&vcp->mx);
-           smb_CleanupDeadVC(vcp);
+           if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
+               osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
+                         vcp, vcp->usersp);
+               vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
+               lock_ReleaseMutex(&vcp->mx);
+               lock_ObtainWrite(&smb_globalLock);
+               dead_sessions[vcp->session] = TRUE;
+               lock_ReleaseWrite(&smb_globalLock);
+               smb_CleanupDeadVC(vcp);
+           } else {
+               lock_ReleaseMutex(&vcp->mx);
+           }
         } else {
             /* assert that we do not exceed the maximum number of sessions or NCBs.
              * we should probably want to wait for a session to be freed in case
              * we run out.
              */
-            osi_assert(session < SESSION_MAX - 1);
-            osi_assert(numNCBs < NCB_MAX - 1);   /* if we pass this test we can allocate one more */
+            osi_assertx(session < SESSION_MAX - 1, "invalid session");
+            osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs");   /* if we pass this test we can allocate one more */
 
            lock_ObtainMutex(&vcp->mx);
            vcp->session   = session;
@@ -8102,35 +8348,151 @@ void smb_Listener(void *parmp)
         /* unlock */
         lock_ReleaseMutex(&smb_ListenerLock);
     }  /* dispatch while loop */
+
+exit_thread:
+    FreeNCB(ncbp);
+    thrd_SetEvent(ListenerShutdown[lana]);
+    return;
+}
+
+static void
+smb_LanAdapterChangeThread(void *param)
+{
+    /* 
+     * Give the IPAddrDaemon thread a chance
+     * to block before we trigger.
+     */
+    Sleep(30000);
+    smb_LanAdapterChange(0);
+}
+
+void smb_SetLanAdapterChangeDetected(void)
+{
+    int lpid;
+    thread_t phandle;
+
+    lock_ObtainMutex(&smb_StartedLock);
+
+    if (!powerStateSuspended) {
+        phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
+                              NULL, 0, &lpid, "smb_LanAdapterChange");
+        osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
+        thrd_CloseHandle(phandle);
+    }
+
+    smb_LanAdapterChangeDetected = 1;
+    lock_ReleaseMutex(&smb_StartedLock);
+}
+
+void smb_LanAdapterChange(int locked) {
+    lana_number_t lanaNum;
+    BOOL          bGateway;
+    char          NetbiosName[MAX_NB_NAME_LENGTH] = "";
+    int           change = 0;
+    LANA_ENUM     temp_list;           
+    long          code;
+    int           i;
+
+
+    afsi_log("smb_LanAdapterChange");
+
+    if (!locked)
+        lock_ObtainMutex(&smb_StartedLock);
+    
+    smb_LanAdapterChangeDetected = 0;
+
+    if (!powerStateSuspended && 
+        SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway, 
+                                          LANA_NETBIOS_NAME_FULL)) &&
+        lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
+        if ( isGateway != bGateway ||
+             strcmp(cm_NetbiosName, NetbiosName) ) {
+            change = 1;
+        } else {
+            NCB *ncbp = GetNCB();
+            ncbp->ncb_command = NCBENUM;
+            ncbp->ncb_buffer = (PUCHAR)&temp_list;
+            ncbp->ncb_length = sizeof(temp_list);
+            code = Netbios(ncbp);
+            if (code == 0) {
+                if (temp_list.length != lana_list.length)
+                    change = 1;
+                else {
+                    for (i=0; i<lana_list.length; i++) {
+                        if ( temp_list.lana[i] != lana_list.lana[i] ) {
+                            change = 1;
+                            break;
+                        }
+                    }
+                }
+            }
+           FreeNCB(ncbp);
+        }
+    } 
+
+    if (change) {
+        afsi_log("Lan Adapter Change detected");
+        smb_StopListeners(1);
+        smb_RestartListeners(1);
+    }
+    if (!locked)
+        lock_ReleaseMutex(&smb_StartedLock);
 }
 
 /* initialize Netbios */
-void smb_NetbiosInit()
+int smb_NetbiosInit(int locked)
 {
     NCB *ncbp;
-#ifdef DJGPP
-    dos_ptr dos_ncb;
-#endif /* DJGPP */
     int i, lana, code, l;
     char s[100];
     int delname_tried=0;
     int len;
     int lana_found = 0;
-    OSVERSIONINFO Version;
+    lana_number_t lanaNum;
 
-    /* Get the version of Windows */
-    memset(&Version, 0x00, sizeof(Version));
-    Version.dwOSVersionInfoSize = sizeof(Version);
-    GetVersionEx(&Version);
+    if (!locked)
+        lock_ObtainMutex(&smb_StartedLock);
 
+    if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
+         smb_ListenerState != SMB_LISTENER_STOPPED) {
+
+        if (!locked)
+            lock_ReleaseMutex(&smb_StartedLock);
+        return 0;
+    }
     /* setup the NCB system */
     ncbp = GetNCB();
-#ifdef DJGPP
-    dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
-#endif /* DJGPP */
 
-#ifndef DJGPP
-    if (smb_LANadapter == -1) {
+    /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
+    if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
+        smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
+
+        if (smb_LANadapter != LANA_INVALID)
+           afsi_log("LAN adapter number %d", smb_LANadapter);
+        else
+           afsi_log("LAN adapter number not determined");
+
+        if (isGateway)
+           afsi_log("Set for gateway service");
+
+        afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
+    } else {
+        /* something went horribly wrong.  We can't proceed without a netbios name */
+        char buf[128];
+        StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
+        osi_panic(buf, __FILE__, __LINE__);
+    }
+
+    /* remember the name */
+    len = (int)strlen(cm_NetbiosName);
+    if (smb_localNamep)
+        free(smb_localNamep);
+    smb_localNamep = malloc(len+1);
+    strcpy(smb_localNamep, cm_NetbiosName);
+    afsi_log("smb_localNamep is >%s<", smb_localNamep);
+
+
+    if (smb_LANadapter == LANA_INVALID) {
         ncbp->ncb_command = NCBENUM;
         ncbp->ncb_buffer = (PUCHAR)&lana_list;
         ncbp->ncb_length = sizeof(lana_list);
@@ -8158,24 +8520,11 @@ void smb_NetbiosInit()
             code = ncbp->ncb_retcode;
         if (code != 0) {
             afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
-            lana_list.lana[i] = 255;  /* invalid lana */
+            lana_list.lana[i] = LANA_INVALID;  /* invalid lana */
         } else {
             afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
         }
     }
-#else
-    /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset.  so
-       we will just fake the LANA list */
-    if (smb_LANadapter == -1) {
-        for (i = 0; i < 8; i++)
-           lana_list.lana[i] = i;
-        lana_list.length = 8;
-    }
-    else {
-        lana_list.length = 1;
-        lana_list.lana[0] = smb_LANadapter;
-    }
-#endif /* !DJGPP */
 
     /* and declare our name so we can receive connections */
     memset(ncbp, 0, sizeof(*ncbp));
@@ -8191,11 +8540,7 @@ void smb_NetbiosInit()
         ncbp->ncb_command = NCBADDNAME;
         ncbp->ncb_lana_num = lana;
         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
-#ifndef DJGPP
         code = Netbios(ncbp);
-#else /* DJGPP */
-        code = Netbios(ncbp, dos_ncb);
-#endif /* !DJGPP */
           
         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
@@ -8206,19 +8551,16 @@ void smb_NetbiosInit()
             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
         }
 
-        if (code == 0) code = ncbp->ncb_retcode;
+        if (code == 0) 
+           code = ncbp->ncb_retcode;
+
         if (code == 0) {
             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
-#ifdef DJGPP
-            /* we only use one LANA with djgpp */
-            lana_list.lana[0] = lana;
-            lana_list.length = 1;
-#endif   
         }
         else {
             afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
             if (code == NRC_BRIDGE) {    /* invalid LANA num */
-                lana_list.lana[l] = 255;
+                lana_list.lana[l] = LANA_INVALID;
                 continue;
             }
             else if (code == NRC_DUPNAME) {
@@ -8227,18 +8569,14 @@ void smb_NetbiosInit()
                 ncbp->ncb_command = NCBDELNAME;
                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
                 ncbp->ncb_lana_num = lana;
-#ifndef DJGPP
                 code = Netbios(ncbp);
-#else
-                code = Netbios(ncbp, dos_ncb);
-#endif /* DJGPP */
                 if (code == 0) 
                     code = ncbp->ncb_retcode;
                 else {
                     afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
                 }
                 if (code != 0 || delname_tried) {
-                    lana_list.lana[l] = 255;
+                    lana_list.lana[l] = LANA_INVALID;
                 }
                 else if (code == 0) {
                     if (!delname_tried) {
@@ -8250,53 +8588,190 @@ void smb_NetbiosInit()
             }
             else {
                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
-                lana_list.lana[l] = 255;  /* invalid lana */
-                osi_panic(s, __FILE__, __LINE__);
+                lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
             }
         }
         if (code == 0) {
+            smb_LANadapter = lana;
             lana_found = 1;   /* at least one worked */
-#ifdef DJGPP
-            break;
-#endif
         }
     }
 
-    osi_assert(lana_list.length >= 0);
+    osi_assertx(lana_list.length >= 0, "empty lana list");
     if (!lana_found) {
-        osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
+        afsi_log("No valid LANA numbers found!");
+       lana_list.length = 0;
+       smb_LANadapter = LANA_INVALID;
+       smb_ListenerState = SMB_LISTENER_STOPPED;
+        cm_VolStatus_Network_Stopped(cm_NetbiosName
+#ifdef _WIN64
+                                      ,cm_NetbiosName
+#endif
+                                      );
     }
         
     /* we're done with the NCB now */
     FreeNCB(ncbp);
+
+    afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
+    if (lana_list.length > 0)
+        osi_assert(smb_LANadapter != LANA_INVALID);
+
+    if (!locked)
+        lock_ReleaseMutex(&smb_StartedLock);
+
+    return (lana_list.length > 0 ? 1 : 0);
 }
 
-void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
+void smb_StartListeners(int locked)
+{
+    int i;
+    int lpid;
+    thread_t phandle;
+
+    if (!locked)
+        lock_ObtainMutex(&smb_StartedLock);
+
+    if (smb_ListenerState == SMB_LISTENER_STARTED) {
+        if (!locked)
+            lock_ReleaseMutex(&smb_StartedLock);
+       return;
+    }
+
+    afsi_log("smb_StartListeners");
+    smb_ListenerState = SMB_LISTENER_STARTED;
+    cm_VolStatus_Network_Started(cm_NetbiosName
+#ifdef _WIN64
+                                  , cm_NetbiosName
+#endif
+                                  );
+
+    for (i = 0; i < lana_list.length; i++) {
+        if (lana_list.lana[i] == LANA_INVALID) 
+            continue;
+        phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
+                               (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
+        osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
+        thrd_CloseHandle(phandle);
+    }
+    if (!locked)
+        lock_ReleaseMutex(&smb_StartedLock);
+}
+
+void smb_RestartListeners(int locked)
+{
+    if (!locked)
+        lock_ObtainMutex(&smb_StartedLock);
+
+    if (powerStateSuspended)
+        afsi_log("smb_RestartListeners called while suspended");
+
+    if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
+       if (smb_ListenerState == SMB_LISTENER_STOPPED) {
+            if (smb_NetbiosInit(1))
+                smb_StartListeners(1);
+        } else if (smb_LanAdapterChangeDetected) {
+            smb_LanAdapterChange(1);
+        }
+    }
+    if (!locked)
+        lock_ReleaseMutex(&smb_StartedLock);
+}
+
+void smb_StopListener(NCB *ncbp, int lana, int wait)
+{
+    long code;
+
+    memset(ncbp, 0, sizeof(*ncbp));
+    ncbp->ncb_command = NCBDELNAME;
+    ncbp->ncb_lana_num = lana;
+    memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
+    code = Netbios(ncbp);
+          
+    afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
+             lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
+
+    /* and then reset the LANA; this will cause the listener threads to exit */
+    ncbp->ncb_command = NCBRESET;
+    ncbp->ncb_callname[0] = 100;
+    ncbp->ncb_callname[2] = 100;
+    ncbp->ncb_lana_num = lana;
+    code = Netbios(ncbp);
+    if (code == 0) 
+       code = ncbp->ncb_retcode;
+    if (code != 0) {
+       afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
+    } else {
+       afsi_log("Netbios NCBRESET lana %d succeeded", lana);
+    }
+
+    if (wait)
+        thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
+}
+
+void smb_StopListeners(int locked)
+{
+    NCB *ncbp;
+    int lana, l;
+
+    if (!locked)
+        lock_ObtainMutex(&smb_StartedLock);
+
+    if (smb_ListenerState == SMB_LISTENER_STOPPED) {
+        if (!locked)
+            lock_ReleaseMutex(&smb_StartedLock);
+       return;
+    }
+
+    afsi_log("smb_StopListeners");
+    smb_ListenerState = SMB_LISTENER_STOPPED;
+    cm_VolStatus_Network_Stopped(cm_NetbiosName
+#ifdef _WIN64
+                                  , cm_NetbiosName
+#endif
+                                  );
+
+    ncbp = GetNCB();
+
+    /* Unregister the SMB name */
+    for (l = 0; l < lana_list.length; l++) {
+        lana = lana_list.lana[l];
+
+       if (lana != LANA_INVALID) {
+           smb_StopListener(ncbp, lana, TRUE);
+
+           /* mark the adapter invalid */
+           lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
+       }
+    }
+
+    /* force a re-evaluation of the network adapters */
+    lana_list.length = 0;
+    smb_LANadapter = LANA_INVALID;
+    FreeNCB(ncbp);
+    if (!locked)
+        lock_ReleaseMutex(&smb_StartedLock);
+}
+
+void smb_Init(osi_log_t *logp, int useV3,
               int nThreads
-#ifndef DJGPP
               , void *aMBfunc
-#endif
   )
 
 {
     thread_t phandle;
     int lpid;
     INT_PTR i;
-    int len;
     struct tm myTime;
-#ifdef DJGPP
-    int npar, seg, sel;
-    dos_ptr rawBuf;
-#endif /* DJGPP */
     EVENT_HANDLE retHandle;
     char eventName[MAX_PATH];
+    int startListeners = 0;
+
+    smb_TlsRequestSlot = TlsAlloc();
 
-#ifndef DJGPP
     smb_MBfunc = aMBfunc;
-#endif /* DJGPP */
 
     smb_useV3 = useV3;
-    smb_LANadapter = LANadapt;
 
     /* Initialize smb_localZero */
     myTime.tm_isdst = -1;              /* compute whether on DST or not */
@@ -8320,12 +8795,6 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     /* initialize the remote debugging log */
     smb_logp = logp;
         
-    /* remember the name */
-    len = (int)strlen(snamep);
-    smb_localNamep = malloc(len+1);
-    strcpy(smb_localNamep, snamep);
-    afsi_log("smb_localNamep is >%s<", smb_localNamep);
-
     /* and the global lock */
     lock_InitializeRWLock(&smb_globalLock, "smb global lock");
     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
@@ -8334,9 +8803,9 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
 
     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
+    lock_InitializeMutex(&smb_StartedLock, "smb started lock");
        
     /* 4 Raw I/O buffers */
-#ifndef DJGPP
     smb_RawBufs = calloc(65536,1);
     *((char **)smb_RawBufs) = NULL;
     for (i=0; i<3; i++) {
@@ -8344,45 +8813,13 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
         *((char **)rawBuf) = smb_RawBufs;
         smb_RawBufs = rawBuf;
     }
-#else /* DJGPP */
-    npar = 65536 >> 4;  /* number of paragraphs */
-    seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
-    if (seg == -1) {
-        afsi_log("Cannot allocate %d paragraphs of DOS memory",
-                  npar);
-        osi_panic("",__FILE__,__LINE__);
-    }
-    else {
-        afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
-                  npar, seg);
-    }
-    smb_RawBufs = (seg * 16) + 0;  /* DOS physical address */
-        
-    _farpokel(_dos_ds, smb_RawBufs, NULL);
-    for (i=0; i<SMB_RAW_BUFS-1; i++) {
-        npar = 65536 >> 4;  /* number of paragraphs */
-        seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
-        if (seg == -1) {
-            afsi_log("Cannot allocate %d paragraphs of DOS memory",
-                      npar);
-            osi_panic("",__FILE__,__LINE__);
-        }
-        else {
-            afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
-                      npar, seg);
-        }
-        rawBuf = (seg * 16) + 0;  /* DOS physical address */
-        /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
-        _farpokel(_dos_ds, rawBuf, smb_RawBufs);
-        smb_RawBufs = rawBuf;
-    }
-#endif /* !DJGPP */
 
     /* global free lists */
     smb_ncbFreeListp = NULL;
     smb_packetFreeListp = NULL;
 
-    smb_NetbiosInit();
+    lock_ObtainMutex(&smb_StartedLock);
+    startListeners = smb_NetbiosInit(1);
 
     /* Initialize listener and server structures */
     numVCs = 0;
@@ -8467,6 +8904,8 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
+    smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
+    smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;       /* both are same */
     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
@@ -8517,6 +8956,7 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
+    smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
     smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
     smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
 
@@ -8556,6 +8996,7 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
                  * performance by removing the network access and works around a bug
                  * seen at sites which are using a MIT Kerberos principal to login
                  * to machines joined to a non-root domain in a multi-domain forest.
+                * MsV1_0SetProcessOption was added in Windows XP.
                  */
                 PVOID pResponse = NULL;
                 ULONG cbResponse = 0;
@@ -8576,7 +9017,7 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
                                                     );
 
                 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
-                    char message[256];
+                    char message[AFSPATHMAX];
                     sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
                                        nts, ntsEx);
                     OutputDebugString(message);
@@ -8645,58 +9086,43 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     }
 
     /* Start listeners, waiters, servers, and daemons */
+    if (startListeners)
+        smb_StartListeners(1);
 
-    for (i = 0; i < lana_list.length; i++) {
-        if (lana_list.lana[i] == 255) 
-            continue;
-        phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
-                               (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
-        osi_assert(phandle != NULL);
-        thrd_CloseHandle(phandle);
-    }
-
-#ifndef DJGPP
     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
                           NULL, 0, &lpid, "smb_ClientWaiter");
-    osi_assert(phandle != NULL);
+    osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
     thrd_CloseHandle(phandle);
-#endif /* !DJGPP */
 
     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
                           NULL, 0, &lpid, "smb_ServerWaiter");
-    osi_assert(phandle != NULL);
+    osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
     thrd_CloseHandle(phandle);
 
     for (i=0; i<smb_NumServerThreads; i++) {
         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
                               (void *) i, 0, &lpid, "smb_Server");
-        osi_assert(phandle != NULL);
+        osi_assertx(phandle != NULL, "smb_Server thread creation failure");
         thrd_CloseHandle(phandle);
     }
 
     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
                           NULL, 0, &lpid, "smb_Daemon");
-    osi_assert(phandle != NULL);
+    osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
     thrd_CloseHandle(phandle);
 
     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
-    osi_assert(phandle != NULL);
+    osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
     thrd_CloseHandle(phandle);
 
-#ifdef DJGPP
-    smb_ListShares();
-#endif
-
+    lock_ReleaseMutex(&smb_StartedLock);
     return;
 }
 
 void smb_Shutdown(void)
 {
     NCB *ncbp;
-#ifdef DJGPP
-    dos_ptr dos_ncb;
-#endif
     long code = 0;
     int i;
     smb_vc_t *vcp;
@@ -8705,9 +9131,6 @@ void smb_Shutdown(void)
         
     /* setup the NCB system */
     ncbp = GetNCB();
-#ifdef DJGPP
-    dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
-#endif
 
     /* Block new sessions by setting shutdown flag */
     smbShutdownFlag = 1;
@@ -8723,11 +9146,7 @@ void smb_Shutdown(void)
         ncbp->ncb_command = NCBHANGUP;
         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
         ncbp->ncb_lsn = (UCHAR)LSNs[i];
-#ifndef DJGPP
         code = Netbios(ncbp);
-#else
-        code = Netbios(ncbp, dos_ncb);
-#endif
         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
         if (code == 0) code = ncbp->ncb_retcode;
         if (code != 0) {
@@ -8757,15 +9176,11 @@ void smb_Shutdown(void)
     /* Delete Netbios name */
     memset((char *)ncbp, 0, sizeof(NCB));
     for (i = 0; i < lana_list.length; i++) {
-        if (lana_list.lana[i] == 255) continue;
+        if (lana_list.lana[i] == LANA_INVALID) continue;
         ncbp->ncb_command = NCBDELNAME;
         ncbp->ncb_lana_num = lana_list.lana[i];
         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
-#ifndef DJGPP
         code = Netbios(ncbp);
-#else
-        code = Netbios(ncbp, dos_ncb);
-#endif
         if (code == 0) 
             code = ncbp->ncb_retcode;
         if (code != 0) {
@@ -8782,7 +9197,11 @@ void smb_Shutdown(void)
         smb_fid_t *fidp;
         smb_tid_t *tidp;
      
-        for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
+       if (vcp->magic != SMB_VC_MAGIC)
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+                      __FILE__, __LINE__);
+
+       for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
         {
             if (fidp->scp != NULL) {
                 cm_scache_t * scp;
@@ -8791,6 +9210,10 @@ void smb_Shutdown(void)
                 if (fidp->scp != NULL) {
                     scp = fidp->scp;
                     fidp->scp = NULL;
+                   lock_ObtainMutex(&scp->mx);
+                   scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
+                   lock_ReleaseMutex(&scp->mx);
+                   osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
                     cm_ReleaseSCache(scp);
                 }
                 lock_ReleaseMutex(&fidp->mx);
@@ -8810,6 +9233,8 @@ void smb_Shutdown(void)
         }
     }
     lock_ReleaseWrite(&smb_rctLock);
+    FreeNCB(ncbp);
+    TlsFree(smb_TlsRequestSlot);
 }
 
 /* Get the UNC \\<servername>\<sharename> prefix. */
@@ -8885,7 +9310,7 @@ void smb_LogPacket(smb_packet_t *packet)
 
         *cp = 0;
 
-        osi_Log0( smb_logp, osi_LogSaveString(smb_logp, buf));
+        osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
     }
 
     osi_Log0(smb_logp, "*** End SMB packet dump ***");
@@ -8903,97 +9328,76 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
     if (lock)
         lock_ObtainRead(&smb_rctLock);
   
-    sprintf(output, "begin dumping smb_vc_t\n");
+    sprintf(output, "begin dumping smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
     {
         smb_fid_t *fidp;
       
-        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
-                 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
-        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-      
-        sprintf(output, "begin dumping smb_fid_t\n");
-        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-
-        for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
-        {
-            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n", 
-                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
-                     fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
-                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
-            WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-        }
-      
-        sprintf(output, "done dumping smb_fid_t\n");
-        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    }
-
-    sprintf(output, "done dumping smb_vc_t\n");
-    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-  
-    sprintf(output, "begin dumping DEAD smb_vc_t\n");
-    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-
-    for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp) 
-    {
-        smb_fid_t *fidp;
-      
-        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
+        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
       
-        sprintf(output, "begin dumping smb_fid_t\n");
+        sprintf(output, "begin dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
         {
-            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n", 
+            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n", 
                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
       
-        sprintf(output, "done dumping smb_fid_t\n");
+        sprintf(output, "done dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }
 
-    sprintf(output, "done dumping DEAD smb_vc_t\n");
+    sprintf(output, "done dumping smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
   
-    sprintf(output, "begin dumping DEAD smb_vc_t\n");
+    sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
     for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp) 
     {
         smb_fid_t *fidp;
       
-        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
+        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
       
-        sprintf(output, "begin dumping smb_fid_t\n");
+        sprintf(output, "begin dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
         {
-            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n", 
+            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n", 
                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
       
-        sprintf(output, "done dumping smb_fid_t\n");
+        sprintf(output, "done dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }
 
-    sprintf(output, "done dumping DEAD smb_vc_t\n");
+    sprintf(output, "done dumping DEAD smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
   
     if (lock)
         lock_ReleaseRead(&smb_rctLock);
     return 0;
 }
+
+long smb_IsNetworkStarted(void)
+{
+    long rc;
+    lock_ObtainWrite(&smb_globalLock);
+    rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
+    lock_ReleaseWrite(&smb_globalLock);
+    return rc;
+}