windows-smb-dead-vc-gc-20080627
[openafs.git] / src / WINNT / afsd / smb.c
index eba965d..0aa88bb 100644 (file)
 #include <afs/stds.h>
 
 #include <windows.h>
+#pragma warning(push)
+#pragma warning(disable: 4005)
 #include <ntstatus.h>
+#pragma warning(pop)
 #include <stddef.h>
 #include <stdlib.h>
 #include <malloc.h>
 #include "smb.h"
 #include "lanahelper.h"
 
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+
 /* These characters are illegal in Windows filenames */
-static char *illegalChars = "\\/:*?\"<>|";
+static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
 
 static int smbShutdownFlag = 0;
 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
@@ -56,9 +62,15 @@ osi_log_t *  smb_logp;
 osi_rwlock_t smb_globalLock;
 osi_rwlock_t smb_rctLock;
 osi_mutex_t  smb_ListenerLock;
-char smb_LANadapter;
+osi_mutex_t  smb_StartedLock;
+
+unsigned char smb_LANadapter = LANA_INVALID;
 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
+int  smb_LanAdapterChangeDetected = 0;
+afs_uint32    smb_AsyncStore = 1;
+afs_uint32    smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
+
+BOOL isGateway = FALSE;
 
 /* for debugging */
 long smb_maxObsConcurrentCalls=0;
@@ -69,9 +81,9 @@ smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
 smb_packet_t *smb_packetFreeListp;
 smb_ncb_t *smb_ncbFreeListp;
 
-int smb_NumServerThreads;
+afs_uint32 smb_NumServerThreads;
 
-int numNCBs, numSessions, numVCs;
+afs_uint32 numNCBs, numSessions, numVCs;
 
 int smb_maxVCPerServer;
 int smb_maxMpxRequests;
@@ -86,6 +98,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];
@@ -96,7 +109,6 @@ 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;
 char *smb_RawBufs;
@@ -108,12 +120,12 @@ char *smb_RawBufs;
 
 /* for raw write */
 typedef struct raw_write_cont {
-       long code;
-       osi_hyper_t offset;
-       long count;
-       char *buf;
-       int writeMode;
-       long alreadyWritten;
+    long code;
+    osi_hyper_t offset;
+    long count;
+    char *buf;
+    int writeMode;
+    long alreadyWritten;
 } raw_write_cont_t;
 
 /* dir search stuff */
@@ -124,12 +136,16 @@ smb_dirSearch_t *smb_lastDirSearchp;
 /* hide dot files? */
 int smb_hideDotFiles;
 
+/* Negotiate Unicode support? */
+LONG smb_UseUnicode;
+
 /* global state about V3 protocols */
 int smb_useV3;         /* try to negotiate V3 */
 
-static showErrors = 0;
+static int showErrors = 0;
 /* MessageBox or something like it */
-int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
+int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
+= NULL;
 
 /* GMT time info:
  * Time in Unix format of midnight, 1/1/1970 local time.
@@ -158,18 +174,18 @@ 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);
-int smb_NetbiosInit(void);
+int smb_NetbiosInit(int);
 
 #ifdef LOG_PACKET
 void smb_LogPacket(smb_packet_t *packet);
 #endif /* LOG_PACKET */
-
-char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
+                                                         
+clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
 int smb_ServerDomainNameLength = 0;
-char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
-int smb_ServerOSLength = sizeof(smb_ServerOS);
-char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
-int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
+clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
+int smb_ServerOSLength = lengthof(smb_ServerOS);
+clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
+int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
 
 /* Faux server GUID. This is never checked. */
 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
@@ -205,7 +221,7 @@ void smb_UpdateServerPriority()
        time_t now = osi_Time();
 
        /* Give one priority boost for each 15 seconds */
-       SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
+       SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
     }
 }
 
@@ -478,8 +494,9 @@ unsigned int smb_Attributes(cm_scache_t *scp)
 /* Check if the named file/dir is a dotfile/dotdir */
 /* String pointed to by lastComp can have leading slashes, but otherwise should have
    no other patch components */
-unsigned int smb_IsDotFile(char *lastComp) {
-    char *s;
+unsigned int smb_IsDotFile(clientchar_t *lastComp) {
+    clientchar_t *s;
+
     if(lastComp) {
         /* skip over slashes */
         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
@@ -488,12 +505,12 @@ unsigned int smb_IsDotFile(char *lastComp) {
         return 0;
 
     /* nulls, curdir and parent dir doesn't count */
-    if (!*s) 
+    if (!*s)
         return 0;
-    if (*s == '.') {
+    if (*s == _C('.')) {
         if (!*(s + 1)) 
             return 0;
-        if(*(s+1) == '.' && !*(s + 2)) 
+        if(*(s+1) == _C('.') && !*(s + 2)) 
             return 0;
         return 1;
     }
@@ -786,7 +803,7 @@ 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;
 }
@@ -800,7 +817,7 @@ 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_globalLock); /* for numVCs */
     lock_ObtainWrite(&smb_rctLock);
     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
        if (vcp->magic != SMB_VC_MAGIC)
@@ -835,7 +852,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;
@@ -847,13 +864,25 @@ 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);
@@ -864,20 +893,20 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
         }
     }
     lock_ReleaseWrite(&smb_rctLock);
-       lock_ReleaseWrite(&smb_globalLock);
+    lock_ReleaseWrite(&smb_globalLock);
     return vcp;
 }
 
-int smb_IsStarMask(char *maskp)
+int smb_IsStarMask(clientchar_t *maskp)
 {
     int i;
-    char tc;
+    clientchar_t tc;
         
     for(i=0; i<11; i++) {
         tc = *maskp++;
-        if (tc == '?' || tc == '*' || tc == '>')
+        if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
            return 1;
-    }  
+    }
     return 0;
 }
 
@@ -889,35 +918,47 @@ void smb_ReleaseVCInternal(smb_vc_t *vcp)
     vcp->refCount--;
 
     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;
-         }
-       } 
-       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);
+        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;
+                }
+            } 
+            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);
+            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++;
-      }
+            /* 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++;
+        }
+    } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
+        /* The reference count is non-zero but the VC is dead.
+         * This implies that some FIDs, TIDs, etc on the VC have yet to 
+         * be cleaned up.  Add a reference that will be dropped by
+         * smb_CleanupDeadVC() and try to cleanup the VC again.
+         * Eventually the refCount will drop to zero when all of the
+         * active threads working with the VC end their task.
+         */
+        vcp->refCount++;        /* put the refCount back */
+        lock_ReleaseWrite(&smb_rctLock);
+        smb_CleanupDeadVC(vcp);
+        lock_ObtainWrite(&smb_rctLock);
     }
 }
 
@@ -990,7 +1031,7 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
 
-        if (fidpIter->delete)
+        if (fidpIter->deleteOk)
             continue;
 
         fid = fidpIter->fid;
@@ -1008,27 +1049,23 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
 
     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
        tidpNext = tidpIter->nextp;
-       if (tidpIter->delete)
+       if (tidpIter->deleteOk)
            continue;
-       tidpIter->delete = 1;
+       tidpIter->deleteOk = 1;
 
        tid = tidpIter->tid;
        osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
 
        smb_HoldTIDNoLock(tidpIter);
-       lock_ReleaseWrite(&smb_rctLock);
-
-       smb_ReleaseTID(tidpIter);
-
-       lock_ObtainWrite(&smb_rctLock);
+       smb_ReleaseTID(tidpIter, TRUE);
        tidpNext = vcp->tidsp;
     }
 
     for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
        uidpNext = uidpIter->nextp;
-       if (uidpIter->delete)
+       if (uidpIter->deleteOk)
            continue;
-       uidpIter->delete = 1;
+       uidpIter->deleteOk = 1;
 
        /* do not add an additional reference count for the smb_user_t
         * as the smb_vc_t already is holding a reference */
@@ -1040,10 +1077,14 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
        uidpNext = vcp->usersp;
     }
 
+    lock_ObtainMutex(&vcp->mx);
+    vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
+    lock_ReleaseMutex(&vcp->mx);
+
     /* 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);
 }
@@ -1055,18 +1096,16 @@ smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
     lock_ObtainWrite(&smb_rctLock);
   retry:
     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
-       if (tidp->refCount == 0 && tidp->delete) {
+       if (tidp->refCount == 0 && tidp->deleteOk) {
            tidp->refCount++;
-           lock_ReleaseWrite(&smb_rctLock);
-           smb_ReleaseTID(tidp);
-           lock_ObtainWrite(&smb_rctLock);
+           smb_ReleaseTID(tidp, TRUE);
            goto retry;
        }
 
         if (tid == tidp->tid) {
             tidp->refCount++;
             break;
-        }      
+        }
     }
     if (!tidp && (flags & SMB_FLAG_CREATE)) {
         tidp = malloc(sizeof(*tidp));
@@ -1081,29 +1120,30 @@ smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
     }
     lock_ReleaseWrite(&smb_rctLock);
     return tidp;
-}              
+}
 
 void smb_HoldTIDNoLock(smb_tid_t *tidp)
 {
     tidp->refCount++;
 }
 
-void smb_ReleaseTID(smb_tid_t *tidp)
+void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
 {
     smb_tid_t *tp;
     smb_tid_t **ltpp;
     cm_user_t *userp;
 
     userp = NULL;
-    lock_ObtainWrite(&smb_rctLock);
-    osi_assert(tidp->refCount-- > 0);
-    if (tidp->refCount == 0 && (tidp->delete)) {
+    if (!locked)
+        lock_ObtainWrite(&smb_rctLock);
+    osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
+    if (tidp->refCount == 0 && (tidp->deleteOk)) {
         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 */
@@ -1111,7 +1151,8 @@ void smb_ReleaseTID(smb_tid_t *tidp)
         smb_ReleaseVCNoLock(tidp->vcp);
         tidp->vcp = NULL;
     }
-    lock_ReleaseWrite(&smb_rctLock);
+    if (!locked)
+        lock_ReleaseWrite(&smb_rctLock);
     if (userp)
         cm_ReleaseUser(userp);
 }              
@@ -1124,9 +1165,9 @@ smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
         if (uid == uidp->userID) {
             uidp->refCount++;
-            osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
+            osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
                     vcp, uidp->userID, 
-                    osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
+                    ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
             break;
         }
     }
@@ -1140,22 +1181,23 @@ smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
         vcp->usersp = uidp;
         lock_InitializeMutex(&uidp->mx, "user_t mutex");
         uidp->userID = uid;
-        osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
-                vcp, uidp->userID, 
-                osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
+        osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
+                vcp, uidp->userID,
+                ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
     }
     lock_ReleaseWrite(&smb_rctLock);
     return uidp;
 }              
 
-smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
+smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
+                                   afs_uint32 flags)
 {
     smb_username_t *unp= NULL;
 
     lock_ObtainWrite(&smb_rctLock);
     for(unp = usernamesp; unp; unp = unp->nextp) {
-        if (stricmp(unp->name, usern) == 0 &&
-             stricmp(unp->machine, machine) == 0) {
+        if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
+            cm_ClientStrCmpI(unp->machine, machine) == 0) {
             unp->refCount++;
             break;
         }
@@ -1165,8 +1207,8 @@ smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
         memset(unp, 0, sizeof(*unp));
         unp->refCount = 1;
         unp->nextp = usernamesp;
-        unp->name = strdup(usern);
-        unp->machine = strdup(machine);
+        unp->name = cm_ClientStrDup(usern);
+        unp->machine = cm_ClientStrDup(machine);
         usernamesp = unp;
         lock_InitializeMutex(&unp->mx, "username_t mutex");
        if (flags & SMB_FLAG_AFSLOGON)
@@ -1177,7 +1219,7 @@ smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
     return unp;
 }      
 
-smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
+smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
 {
     smb_user_t *uidp= NULL;
 
@@ -1185,10 +1227,10 @@ smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
         if (!uidp->unp) 
             continue;
-        if (stricmp(uidp->unp->name, usern) == 0) {
+        if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
             uidp->refCount++;
-            osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
-                    vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
+            osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
+                    vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
             break;
         } else
             continue;
@@ -1205,7 +1247,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;
@@ -1213,7 +1255,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);
@@ -1221,12 +1263,10 @@ void smb_ReleaseUsername(smb_username_t *unp)
        free(unp->name);
        free(unp->machine);
        free(unp);
-    }          
+    }
     lock_ReleaseWrite(&smb_rctLock);
-
-    if (userp) {
+    if (userp)
         cm_ReleaseUser(userp);
-    }  
 }      
 
 void smb_HoldUIDNoLock(smb_user_t *uidp)
@@ -1241,14 +1281,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;
@@ -1308,7 +1348,7 @@ cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
  * Return a pointer to a pathname extracted from a TID structure.  The
  * TID structure is not held; assume it won't go away.
  */
-long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
+long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
 {
     smb_tid_t *tidp;
     long code = 0;
@@ -1322,7 +1362,7 @@ long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
             /* tidp->pathname would be NULL, but that's fine */
         }
         *treepath = tidp->pathname;
-       smb_ReleaseTID(tidp);
+       smb_ReleaseTID(tidp, FALSE);
     }
     return code;
 }
@@ -1367,7 +1407,7 @@ 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) {
+       if (fidp->refCount == 0 && fidp->deleteOk) {
            fidp->refCount++;
            lock_ReleaseWrite(&smb_rctLock);
            smb_ReleaseFID(fidp);
@@ -1465,16 +1505,16 @@ void smb_ReleaseFID(smb_fid_t *fidp)
 
     lock_ObtainMutex(&fidp->mx);
     lock_ObtainWrite(&smb_rctLock);
-    osi_assert(fidp->refCount-- > 0);
-    if (fidp->refCount == 0 && (fidp->delete)) {
+    osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
+    if (fidp->refCount == 0 && (fidp->deleteOk)) {
         vcp = fidp->vcp;
         fidp->vcp = NULL;
         scp = fidp->scp;    /* release after lock is released */
        if (scp) {
-           lock_ObtainMutex(&scp->mx);
+           lock_ObtainWrite(&scp->rw);
            scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
-           lock_ReleaseMutex(&scp->mx);
-           osi_Log2(afsd_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
+           lock_ReleaseWrite(&scp->rw);
+           osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
            fidp->scp = NULL;
        }
         userp = fidp->userp;
@@ -1489,10 +1529,10 @@ void smb_ReleaseFID(smb_fid_t *fidp)
         if (ioctlp) {
             if (ioctlp->prefix)
                 cm_FreeSpace(ioctlp->prefix);
-            if (ioctlp->inAllocp)
-                free(ioctlp->inAllocp);
-            if (ioctlp->outAllocp)
-                free(ioctlp->outAllocp);
+            if (ioctlp->ioctl.inAllocp)
+                free(ioctlp->ioctl.inAllocp);
+            if (ioctlp->ioctl.outAllocp)
+                free(ioctlp->ioctl.outAllocp);
             free(ioctlp);
         }       
        lock_ReleaseMutex(&fidp->mx);
@@ -1518,12 +1558,12 @@ void smb_ReleaseFID(smb_fid_t *fidp)
  * Case-insensitive search for one string in another;
  * used to find variable names in submount pathnames.
  */
-static char *smb_stristr(char *str1, char *str2)
+static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
 {
-    char *cursor;
+    clientchar_t *cursor;
 
     for (cursor = str1; *cursor; cursor++)
-        if (stricmp(cursor, str2) == 0)
+        if (cm_ClientStrCmpI(cursor, str2) == 0)
             return cursor;
 
     return NULL;
@@ -1534,25 +1574,24 @@ static char *smb_stristr(char *str1, char *str2)
  * name has been identified by smb_stristr() and is in substr.  Variable name
  * length (plus one) is in substr_size.  Variable value is in newstr.
  */
-static void smb_subst(char *str1, char *substr, unsigned int substr_size,
-                      char *newstr)
+static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
+                      unsigned int substr_size, clientchar_t *newstr)
 {
-    char temp[1024];
+    clientchar_t temp[1024];
 
-    strcpy(temp, substr + substr_size - 1);
-    strcpy(substr, newstr);
-    strcat(str1, temp);
-}       
-
-char VNUserName[] = "%USERNAME%";
-char VNLCUserName[] = "%LCUSERNAME%";
-char VNComputerName[] = "%COMPUTERNAME%";
-char VNLCComputerName[] = "%LCCOMPUTERNAME%";
+    cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
+    cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
+    cm_ClientStrCat(str1, cchstr1, temp);
+}
 
+clientchar_t VNUserName[] = _C("%USERNAME%");
+clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
+clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
+clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
 
 typedef struct smb_findShare_rock {
-    char * shareName;
-    char * match;
+    clientchar_t * shareName;
+    clientchar_t * match;
     int matchType;
 } smb_findShare_rock_t;
 
@@ -1564,13 +1603,17 @@ long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 {
     int matchType = 0;
     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
-    if (!strnicmp(dep->name, vrock->shareName, 12)) {
-        if(!stricmp(dep->name, vrock->shareName))
+    normchar_t normName[MAX_PATH];
+
+    cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
+
+    if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
+        if(!cm_ClientStrCmpI(normName, vrock->shareName))
             matchType = SMB_FINDSHARE_EXACT_MATCH;
         else
             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
         if(vrock->match) free(vrock->match);
-        vrock->match = strdup(dep->name);
+        vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
         vrock->matchType = matchType;
 
         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
@@ -1581,15 +1624,17 @@ long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 
 
 /* find a shareName in the table of submounts */
-int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
-       char **pathNamep)
-{
-    DWORD len;
-    char pathName[1024];
-    char *var;
-    char temp[1024];
+int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
+                  clientchar_t *shareName,
+                  clientchar_t **pathNamep)
+{
+    DWORD cblen;
+    DWORD cchlen;
+    clientchar_t pathName[1024];
+    clientchar_t *var;
     DWORD sizeTemp;
-    char *p, *q;
+    clientchar_t *p, *q;
+    fschar_t *cellname = NULL;
     HKEY parmKey;
     DWORD code;
     DWORD allSubmount = 1;
@@ -1600,18 +1645,18 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
      * world to do so.
      */
     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
-                         0, KEY_QUERY_VALUE, &parmKey);
+                        0, KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
-        len = sizeof(allSubmount);
+        cblen = sizeof(allSubmount);
         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
-                                (BYTE *) &allSubmount, &len);
+                               (BYTE *) &allSubmount, &cblen);
         if (code != ERROR_SUCCESS) {
             allSubmount = 1;
         }
         RegCloseKey (parmKey);
     }
 
-    if (allSubmount && _stricmp(shareName, "all") == 0) {
+    if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
         *pathNamep = NULL;
         return 1;
     }
@@ -1619,78 +1664,120 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
     /* In case, the all share is disabled we need to still be able
      * to handle ioctl requests 
      */
-    if (_stricmp(shareName, "ioctl$") == 0) {
-        *pathNamep = strdup("/.__ioctl__");
+    if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
+        *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
         return 1;
     }
 
-    if (_stricmp(shareName, "IPC$") == 0 ||
-        _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
-        _stricmp(shareName, "DESKTOP.INI") == 0
-         ) {
+    if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
+        ) {
         *pathNamep = NULL;
         return 0;
     }
 
+    /* Check for volume references
+     * 
+     * They look like <cell>{%,#}<volume>
+     */
+    if (cm_ClientStrChr(shareName, '%') != NULL ||
+        cm_ClientStrChr(shareName, '#') != NULL) {
+        clientchar_t 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_LogSaveClientString(smb_logp, shareName));
+
+        cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
+                            _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
+        cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
+
+        *pathNamep = malloc(cchlen * sizeof(clientchar_t));
+        if (*pathNamep) {
+            cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
+            cm_ClientStrLwr(*pathNamep);
+            osi_Log1(smb_logp, "   returning pathname [%S]",
+                     osi_LogSaveClientString(smb_logp, *pathNamep));
+
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
-                         0, KEY_QUERY_VALUE, &parmKey);
+                        0, KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
-        len = sizeof(pathName);
-        code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
-                                (BYTE *) pathName, &len);
+        cblen = sizeof(pathName);
+        code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
+                                (BYTE *) pathName, &cblen);
         if (code != ERROR_SUCCESS)
-            len = 0;
+            cblen = 0;
         RegCloseKey (parmKey);
     } else {
-        len = 0;
-    }   
-    if (len != 0 && len != sizeof(pathName) - 1) {
+        cblen = 0;
+    }
+    cchlen = cblen / sizeof(clientchar_t);
+    if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
         /* We can accept either unix or PC style AFS pathnames.  Convert
          * Unix-style to PC style here for internal use. 
          */
         p = pathName;
-        if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
-            p += strlen(cm_mountRoot);  /* skip mount path */
+        cchlen = lengthof(pathName);
+
+        /* within this code block, we maintain, cchlen = writeable
+           buffer length of p */
+
+        if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
+            p += cm_mountRootCLen;  /* skip mount path */
+            cchlen -= (p - pathName);
+        }
+
         q = p;
         while (*q) {
-            if (*q == '/') *q = '\\';    /* change to \ */
+            if (*q == _C('/')) *q = _C('\\');    /* change to \ */
             q++;
         }
 
         while (1)
         {
+            clientchar_t temp[1024];
+
             if (var = smb_stristr(p, VNUserName)) {
                 if (uidp && uidp->unp)
-                    smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
+                    smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
                 else
-                    smb_subst(p, var, sizeof(VNUserName)," ");
+                    smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
             }
             else if (var = smb_stristr(p, VNLCUserName)) 
             {
                 if (uidp && uidp->unp)
-                    strcpy(temp, uidp->unp->name);
+                    cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
                 else 
-                    strcpy(temp, " ");
-                _strlwr(temp);
-                smb_subst(p, var, sizeof(VNLCUserName), temp);
+                    cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
+                cm_ClientStrLwr(temp);
+                smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
             }
             else if (var = smb_stristr(p, VNComputerName)) 
             {
-                sizeTemp = sizeof(temp);
-                GetComputerName((LPTSTR)temp, &sizeTemp);
-                smb_subst(p, var, sizeof(VNComputerName), temp);
+                sizeTemp = lengthof(temp);
+                GetComputerNameW(temp, &sizeTemp);
+                smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
             }
             else if (var = smb_stristr(p, VNLCComputerName)) 
             {
-                sizeTemp = sizeof(temp);
+                sizeTemp = lengthof(temp);
                 GetComputerName((LPTSTR)temp, &sizeTemp);
-                _strlwr(temp);
-                smb_subst(p, var, sizeof(VNLCComputerName), temp);
+                cm_ClientStrLwr(temp);
+                smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
             }
             else     
                 break;
         }
-        *pathNamep = strdup(p);
+        *pathNamep = cm_ClientStrDup(p);
         return 1;
     } 
     else
@@ -1699,7 +1786,8 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
         cm_req_t req;
         smb_findShare_rock_t vrock;
         osi_hyper_t thyper;
-        char * p = shareName; 
+        fschar_t ftemp[1024];
+        clientchar_t * p = shareName; 
         int rw = 0;
 
         /*  attempt to locate a partial match in root.afs.  This is because
@@ -1709,18 +1797,21 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
         thyper.HighPart = 0;
         thyper.LowPart = 0;
 
-        vrock.shareName = shareName;
+        vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
         vrock.match = NULL;
         vrock.matchType = 0;
 
         cm_HoldSCache(cm_data.rootSCachep);
         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
-            (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
+                           (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
         cm_ReleaseSCache(cm_data.rootSCachep);
 
+        free(vrock.shareName);
+        vrock.shareName = NULL;
+
         if (vrock.matchType) {
-            sprintf(pathName,"/%s/",vrock.match);
-            *pathNamep = strdup(strlwr(pathName));
+            cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
+            *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
             free(vrock.match);
             return 1;
         }
@@ -1732,17 +1823,25 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
             rw = 1;
         }
         /* Get the full name for this cell */
-        code = cm_SearchCellFile(p, temp, 0, 0);
+        cellname = cm_ClientStringToFsStringAlloc(p, cm_ClientStrLen(p), NULL);
+        code = cm_SearchCellFile(cellname, ftemp, 0, 0);
 #ifdef AFS_AFSDB_ENV
         if (code && cm_dnsEnabled) {
             int ttl;
-            code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
+            code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
         }
 #endif
+        if (cellname)
+            free(cellname);
+
         /* construct the path */
-        if (code == 0) {     
-            sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
-            *pathNamep = strdup(strlwr(pathName));
+        if (code == 0) {
+            clientchar_t temp[1024];
+
+            cm_FsStringToClientString(ftemp, cm_FsStrLen(ftemp), temp, 1024);
+            cm_ClientStrPrintfN(pathName, lengthof(pathName),
+                                rw ? _C("/.%S/") : _C("/%S/"), temp);
+            *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
             return 1;
         }
     }
@@ -1757,10 +1856,10 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
 #define CSC_POLICY_PROGRAMS 2
 #define CSC_POLICY_DISABLE 3
 
-int smb_FindShareCSCPolicy(char *shareName)
+int smb_FindShareCSCPolicy(clientchar_t *shareName)
 {
     DWORD len;
-    char policy[1024];
+    clientchar_t policy[1024];
     DWORD dwType;
     HKEY hkCSCPolicy;
     int  retval = CSC_POLICY_MANUAL;
@@ -1776,19 +1875,19 @@ int smb_FindShareCSCPolicy(char *shareName)
                     NULL );
 
     len = sizeof(policy);
-    if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
+    if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
          len == 0) {
-        retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
+        retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
     }
-    else if (stricmp(policy, "documents") == 0)
+    else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
     {
         retval = CSC_POLICY_DOCUMENTS;
     }
-    else if (stricmp(policy, "programs") == 0)
+    else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
     {
         retval = CSC_POLICY_PROGRAMS;
     }
-    else if (stricmp(policy, "disable") == 0)
+    else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
     {
         retval = CSC_POLICY_DISABLE;
     }
@@ -1835,17 +1934,17 @@ void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
 {
     lock_ObtainWrite(&smb_globalLock);
     lock_ObtainMutex(&dsp->mx);
-    osi_Log3(afsd_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
+    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);
+        lock_ObtainWrite(&dsp->scp->rw);
         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
             dsp->scp->bulkStatProgress = hzero;
         }      
-        lock_ReleaseMutex(&dsp->scp->mx);
+        lock_ReleaseWrite(&dsp->scp->rw);
     }  
     lock_ReleaseMutex(&dsp->mx);
     lock_ReleaseWrite(&smb_globalLock);
@@ -1857,7 +1956,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);
@@ -1865,7 +1964,7 @@ void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
         lock_ReleaseMutex(&dsp->mx);
         lock_FinalizeMutex(&dsp->mx);
         scp = dsp->scp;
-       osi_Log3(afsd_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
+       osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
                 dsp->cookie, dsp, scp);
         free(dsp);
     } else {
@@ -1954,6 +2053,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;
@@ -1998,7 +2099,7 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
         if (!smb_lastDirSearchp) 
             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
     
-       osi_Log2(afsd_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
+       osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
                 dsp->cookie, dsp);
        break;
     }  
@@ -2016,7 +2117,7 @@ static smb_packet_t *GetPacket(void)
         smb_packetFreeListp = tbp->nextp;
     lock_ReleaseWrite(&smb_globalLock);
     if (!tbp) {
-        tbp = calloc(65540,1);
+        tbp = calloc(sizeof(*tbp),1);
         tbp->magic = SMB_PACKETMAGIC;
         tbp->ncbp = NULL;
         tbp->vcp = NULL;
@@ -2029,9 +2130,9 @@ static smb_packet_t *GetPacket(void)
         tbp->ncb_length = 0;
         tbp->flags = 0;
         tbp->spacep = NULL;
-        
+        tbp->stringsp = NULL;
     }
-    osi_assert(tbp->magic == SMB_PACKETMAGIC);
+    osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
 
     return tbp;
 }
@@ -2042,6 +2143,7 @@ smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
     tbp = GetPacket();
     memcpy(tbp, pkt, sizeof(smb_packet_t));
     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
+    tbp->stringsp = NULL;
     if (tbp->vcp)
        smb_HoldVC(tbp->vcp);
     return tbp;
@@ -2062,17 +2164,29 @@ static NCB *GetNCB(void)
         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;
     return ncbp;
 }
 
+static void FreeSMBStrings(smb_packet_t * pkt)
+{
+    cm_space_t * s;
+    cm_space_t * ns;
+
+    for (s = pkt->stringsp; s; s = ns) {
+        ns = s->nextp;
+        cm_FreeSpace(s);
+    }
+    pkt->stringsp = NULL;
+}
+
 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;
@@ -2089,6 +2203,7 @@ void smb_FreePacket(smb_packet_t *tbp)
     tbp->oddByte = 0;
     tbp->ncb_length = 0;
     tbp->flags = 0;
+    FreeSMBStrings(tbp);
     lock_ReleaseWrite(&smb_globalLock);
 
     if (vcp)
@@ -2100,7 +2215,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;
@@ -2239,7 +2354,7 @@ unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
 
 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
 {
-    char *parmDatap;
+    unsigned char *parmDatap;
 
     /* make sure we have enough slots */
     if (*smbp->wctp <= slot) 
@@ -2252,7 +2367,7 @@ void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
 
 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
 {
-    char *parmDatap;
+    unsigned char *parmDatap;
 
     /* make sure we have enough slots */
     if (*smbp->wctp <= slot) 
@@ -2267,7 +2382,7 @@ void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
 
 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
 {
-    char *parmDatap;
+    unsigned char *parmDatap;
     int i;
 
     /* make sure we have enough slots */
@@ -2281,7 +2396,7 @@ void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
 
 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
 {
-    char *parmDatap;
+    unsigned char *parmDatap;
 
     /* make sure we have enough slots */
     if (*smbp->wctp <= slot) {
@@ -2296,11 +2411,14 @@ void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
     *parmDatap++ = parmValue & 0xff;
 }
 
-void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
+
+
+void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
+                            clientchar_t *inPathp)
 {
-    char *lastSlashp;
+    clientchar_t *lastSlashp;
         
-    lastSlashp = strrchr(inPathp, '\\');
+    lastSlashp = cm_ClientStrRChr(inPathp, '\\');
     if (lastComponentp)
         *lastComponentp = lastSlashp;
     if (lastSlashp) {
@@ -2316,14 +2434,255 @@ void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp
     }
 }
 
-unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
+clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
+                                  char **chainpp, int flags)
 {
+    size_t cb;
+
     if (*inp++ != 0x4) 
         return NULL;
-    if (chainpp) {
-        *chainpp = inp + strlen(inp) + 1;      /* skip over null-terminated string */
+
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    cb = sizeof(pktp->data) - (inp - pktp->data);
+    if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
+#ifdef DEBUG_UNICODE
+        DebugBreak();
+#endif
+        cb = sizeof(pktp->data);
+    }
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
+                              char ** chainpp, int flags)
+{
+    size_t cb;
+
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    cb = sizeof(pktp->data) - (inp - pktp->data);
+    if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
+#ifdef DEBUG_UNICODE
+        DebugBreak();
+#endif
+        cb = sizeof(pktp->data);
+    }
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
+                                size_t cb, char ** chainpp, int flags)
+{
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
+                                 size_t cch, char ** chainpp, int flags)
+{
+    size_t cb = cch;
+
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+    else
+        cb = cch * sizeof(wchar_t);
+#endif
+
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+clientchar_t *
+smb_ParseStringBuf(const char * bufbase,
+                   cm_space_t ** stringspp,
+                   unsigned char *inp, size_t *pcb_max,
+                   char **chainpp, int flags)
+{
+#ifdef SMB_UNICODE
+    if (!(flags & SMB_STRF_FORCEASCII)) {
+        size_t cch_src;
+        cm_space_t * spacep;
+        int    null_terms = 0;
+
+        if (bufbase && ((inp - bufbase) % 2) != 0) {
+            inp++;              /* unicode strings are always word aligned */
+        }
+
+        if (*pcb_max > 0) {
+            if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
+                                        &cch_src))) {
+                cch_src = *pcb_max / sizeof(wchar_t);
+                *pcb_max = 0;
+                null_terms = 0;
+            } else {
+                *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
+                null_terms = 1;
+            }
+        } else {
+            cch_src = 0;
+        }
+
+        spacep = cm_GetSpace();
+        spacep->nextp = *stringspp;
+        *stringspp = spacep;
+
+        if (cch_src == 0) {
+            if (chainpp) {
+                *chainpp = inp + sizeof(wchar_t);
+            }
+
+            *(spacep->wdata) = 0;
+            return spacep->wdata;
+        }
+
+        StringCchCopyNW(spacep->wdata,
+                        lengthof(spacep->wdata),
+                        (const clientchar_t *) inp, cch_src);
+
+        if (chainpp)
+            *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
+
+        return spacep->wdata;
+
+    } else {
+#endif
+        cm_space_t * spacep;
+        int cchdest;
+
+        /* Not using Unicode */
+        if (chainpp) {
+            *chainpp = inp + strlen(inp) + 1;
+        }
+
+        spacep = cm_GetSpace();
+        spacep->nextp = *stringspp;
+        *stringspp = spacep;
+
+        cchdest = lengthof(spacep->wdata);
+        cm_Utf8ToUtf16(inp, *pcb_max, spacep->wdata, cchdest);
+
+        return spacep->wdata;
+#ifdef SMB_UNICODE
+    }
+#endif
+}
+
+unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
+                            clientchar_t * str,
+                            size_t * plen, int flags)
+{
+    size_t buffersize;
+    int align = 0;
+
+    if (outp == NULL) {
+        /* we are only calculating the required size */
+
+        if (plen == NULL)
+            return NULL;
+
+#ifdef SMB_UNICODE
+
+        if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
+
+            StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
+            if (!(flags & SMB_STRF_IGNORENULL))
+                *plen += sizeof(wchar_t);
+
+            return (unsigned char *) 1; /* return TRUE if we are using unicode */
+        }
+        else
+#endif
+        {
+            /* Storing ANSI */
+
+            int cch_str;
+            int cch_dest;
+
+            cch_str = cm_ClientStrLen(str);
+            cch_dest = cm_ClientStringToUtf8(str, cch_str, NULL, 0);
+
+            if (plen)
+                *plen = ((flags & SMB_STRF_IGNORENULL)? cch_dest: cch_dest+1);
+
+            return NULL;
+        }
+
+        /* Not reached. */
+    }
+
+    /* if outp != NULL ... */
+
+    /* Number of bytes left in the buffer.
+
+       If outp lies inside the packet data buffer, we assume that the
+       buffer is the packet data buffer.  Otherwise we assume that the
+       buffer is sizeof(packet->data).
+
+    */
+    if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
+        align = ((outp - pktp->data) % 2);
+        buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
+    } else {
+        align = (((size_t) outp) % 2);
+        buffersize = sizeof(pktp->data);
+    }
+
+#ifdef SMB_UNICODE
+
+    if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
+        int nchars;
+
+        if (align)
+            *outp++ = '\0';
+
+        if (*str == _C('\0')) {
+
+            if (buffersize < sizeof(wchar_t))
+                return NULL;
+
+            *((wchar_t *) outp) = L'\0';
+            if (plen && !(flags & SMB_STRF_IGNORENULL))
+                *plen += sizeof(wchar_t);
+            return outp + sizeof(wchar_t);
+        }
+
+        nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, buffersize / sizeof(wchar_t));
+        if (nchars == 0) {
+            osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
+                     osi_LogSaveClientString(smb_logp, str),
+                     GetLastError());
+            return NULL;
+        }
+
+        if (plen)
+            *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
+
+        return outp + sizeof(wchar_t) * nchars;
+    }
+    else
+#endif
+    {
+        /* Storing ANSI */
+        size_t cch_dest;
+
+        cch_dest = cm_ClientStringToUtf8(str, -1, outp, buffersize);
+
+        if (plen)
+            *plen += ((flags & SMB_STRF_IGNORENULL)? cch_dest - 1: cch_dest);
+
+        return outp + cch_dest;
     }
-    return inp;
 }
 
 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
@@ -2345,6 +2704,23 @@ unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *length
     return inp;
 }      
 
+unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
+{
+    int tlen;
+
+    if (*inp++ != 0x1) return NULL;
+    tlen = inp[0] + (inp[1]<<8);
+    inp += 2;          /* skip length field */
+        
+    if (chainpp) {
+        *chainpp = inp + tlen;
+    }  
+
+    if (lengthp) *lengthp = tlen;
+        
+    return inp;
+}
+
 /* format a packet as a response */
 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
 {
@@ -2373,8 +2749,15 @@ 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;
+#ifdef SMB_UNICODE
+    if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
+        outp->flg2 |= SMB_FLAGS2_UNICODE;
+#endif
 
     /* copy fields in generic packet area */
     op->wctp = &outp->wct;
@@ -2464,7 +2847,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) {
@@ -2525,11 +2909,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 */
@@ -2577,25 +2957,26 @@ 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 */
+    } 
+    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 if (code == CM_ERROR_NOSUCHDEVICE) {
+        NTStatus = 0xC000000EL; /* No Such Device */
     }
-#endif
-    else if (code == RXKADUNKNOWNKEY) {
-       NTStatus = 0xC0000322L; /* Bad Kerberos key */
+    else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
+        NTStatus = 0xC0000055L; /* Lock Not Granted */
     } else {
         NTStatus = 0xC0982001L;        /* SMB non-specific error */
     }
@@ -2635,7 +3016,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! */
     }
@@ -2780,6 +3162,7 @@ long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return CM_ERROR_BADOP;
 }
 
+/* SMB_COM_ECHO */
 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short EchoCount, i;
@@ -2800,6 +3183,7 @@ long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
+/* SMB_COM_READ_RAW */
 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -2807,6 +3191,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     unsigned short fd;
     unsigned pid;
     smb_fid_t *fidp;
+    smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp = NULL;
     NCB *ncbp;
@@ -2850,7 +3235,14 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     if (!fidp)
         goto send1;
 
-    pid = ((smb_t *) inp)->pid;
+    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        code = CM_ERROR_NOSUCHFILE;
+        goto send1a;
+    }
+
+
+    pid = smbp->pid;
     {
         LARGE_INTEGER LOffset, LLength;
         cm_key_t key;
@@ -2862,9 +3254,9 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&fidp->scp->rw);
         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ReleaseWrite(&fidp->scp->rw);
     }    
     if (code) {
         goto send1a;
@@ -2894,6 +3286,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
             lock_ReleaseMutex(&smb_RawBufLock);
         }
 
+        lock_ReleaseMutex(&fidp->mx);
         smb_ReleaseFID(fidp);
         return rc;
     }
@@ -2952,6 +3345,7 @@ long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     return 0;
 }
 
+/* SMB_COM_NEGOTIATE */
 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *namep;
@@ -3071,7 +3465,8 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
          * and NT Find *
          * and NT SMB's *
          * and raw mode 
-         * and DFS */
+         * and DFS
+         * and Unicode */
         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
 #ifdef DFS_SUPPORT
                NTNEGOTIATE_CAPABILITY_DFS |
@@ -3086,6 +3481,12 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         if ( smb_authType == SMB_AUTH_EXTENDED )
             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
 
+#ifdef SMB_UNICODE
+        if ( smb_UseUnicode ) {
+            caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
+        }
+#endif
+
         smb_SetSMBParmLong(outp, 9, caps);
         time(&unixTime);
         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
@@ -3102,7 +3503,9 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             datap = smb_GetSMBData(outp, NULL);
             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
             /* and the faux domain name */
-            strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
+            cm_ClientStringToUtf8(smb_ServerDomainName, -1,
+                                  datap + MSV1_0_CHALLENGE_LENGTH,
+                                  sizeof(outp->data)/sizeof(char) - (datap - outp->data));
         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
             void * secBlob;
             int secBlobLength;
@@ -3164,7 +3567,9 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
             /* paste in a new encryption key */
             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
             /* and the faux domain name */
-            strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
+            cm_ClientStringToUtf8(smb_ServerDomainName, -1,
+                                  datap + MSV1_0_CHALLENGE_LENGTH,
+                                  sizeof(outp->data)/sizeof(char) - (datap - outp->data));
         } else {
             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
             smb_SetSMBParm(outp, 12, 0); /* resvd */
@@ -3266,7 +3671,7 @@ void smb_Daemon(void *parmp)
        now = osi_Time();
        lock_ObtainWrite(&smb_rctLock);
        for ( unpp=&usernamesp; *unpp; ) {
-           int delete = 0;
+           int deleteOk = 0;
            smb_username_t *unp;
 
            lock_ObtainMutex(&(*unpp)->mx);
@@ -3276,10 +3681,10 @@ void smb_Daemon(void *parmp)
                ;
            else if (!smb_LogoffTokenTransfer ||
                     ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
-               delete = 1;
+               deleteOk = 1;
            lock_ReleaseMutex(&(*unpp)->mx);
 
-           if (delete) {
+           if (deleteOk) {
                cm_user_t * userp;
 
                unp = *unpp;    
@@ -3290,11 +3695,8 @@ void smb_Daemon(void *parmp)
                free(unp->name);
                free(unp->machine);
                free(unp);
-               if (userp) {
-                   lock_ReleaseWrite(&smb_rctLock);
+               if (userp)
                    cm_ReleaseUser(userp);
-                   lock_ObtainWrite(&smb_rctLock);
-               }
            } else {
                unpp = &(*unpp)->nextp;
            }
@@ -3345,7 +3747,12 @@ void smb_WaitingLocksDaemon()
                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
                     continue;
 
-                osi_assert(wl->state != SMB_WAITINGLOCKSTATE_ERROR);
+                if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
+                    code = CM_ERROR_LOCK_NOT_GRANTED;
+                    break;
+                }
+
+                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. */
@@ -3363,8 +3770,8 @@ void smb_WaitingLocksDaemon()
             if (code == CM_ERROR_WOULDBLOCK) {
 
                 /* no progress */
-                if (wlRequest->timeRemaining != 0xffffffff
-                     && (wlRequest->timeRemaining -= 1000) < 0)
+                if (wlRequest->msTimeout != 0xffffffff
+                     && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
                     goto endWait;
 
                 continue;
@@ -3380,24 +3787,25 @@ void smb_WaitingLocksDaemon()
                          wlRequest);
 
                 scp = wlRequest->scp;
-               osi_Log2(afsd_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
+               osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
 
                 cm_InitReq(&req);
 
-                lock_ObtainMutex(&scp->mx);
+                lock_ObtainWrite(&scp->rw);
 
                 for (wl = wlRequest->locks; wl; wl = wlNext) {
                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
-                    
-                    cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
-                              wl->LLength, wl->key, NULL, &req);
+                
+                    if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
+                        cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
+                                  wl->LLength, wl->key, NULL, &req);
 
                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
 
                     free(wl);
                 }
                 
-                lock_ReleaseMutex(&scp->mx);
+                lock_ReleaseWrite(&scp->rw);
 
             } else {
 
@@ -3458,31 +3866,31 @@ long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     return 0;
 }
 
+/* SMB_COM_TREE_CONNECT */
 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
 {
     smb_tid_t *tidp;
     smb_user_t *uidp;
     unsigned short newTid;
-    char shareName[256];
-    char *sharePath;
+    clientchar_t shareName[AFSPATHMAX];
+    clientchar_t *sharePath;
     int shareFound;
-    char *tp;
-    char *pathp;
-    char *passwordp;
+    clientchar_t *tp;
+    clientchar_t *pathp;
     cm_user_t *userp;
 
     osi_Log0(smb_logp, "SMB receive tree connect");
 
     /* parse input parameters */
-    tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
-    passwordp = smb_ParseASCIIBlock(tp, &tp);
-    tp = strrchr(pathp, '\\');
+    {
+        char *tbp;
+        tbp = smb_GetSMBData(inp, NULL);
+        pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
+    }
+    tp = cm_ClientStrRChr(pathp, '\\');
     if (!tp)
         return CM_ERROR_BADSMB;
-    strcpy(shareName, tp+1);
+    cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
 
     lock_ObtainMutex(&vcp->mx);
     newTid = vcp->tidCounter++;
@@ -3495,14 +3903,14 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     if (uidp)
         smb_ReleaseUID(uidp);
     if (!shareFound) {
-        smb_ReleaseTID(tidp);
+        smb_ReleaseTID(tidp, FALSE);
         return CM_ERROR_BADSHARENAME;
     }
     lock_ObtainMutex(&tidp->mx);
     tidp->userp = userp;
     tidp->pathname = sharePath;
     lock_ReleaseMutex(&tidp->mx);
-    smb_ReleaseTID(tidp);
+    smb_ReleaseTID(tidp, FALSE);
 
     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
     smb_SetSMBParm(rsp, 1, newTid);
@@ -3512,32 +3920,15 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     return 0;
 }
 
-unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
-{
-    int tlen;
-
-    if (*inp++ != 0x1) return NULL;
-    tlen = inp[0] + (inp[1]<<8);
-    inp += 2;          /* skip length field */
-        
-    if (chainpp) {
-        *chainpp = inp + tlen;
-    }  
-
-    if (lengthp) *lengthp = tlen;
-        
-    return inp;
-}
-
 /* set maskp to the mask part of the incoming path.
  * Mask is 11 bytes long (8.3 with the dot elided).
  * Returns true if succeeds with a valid name, otherwise it does
  * its best, but returns false.
  */
-int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
+int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
 {
-    char *tp;
-    char *up;
+    clientchar_t *tp;
+    clientchar_t *up;
     int i;
     int tc;
     int valid8Dot3;
@@ -3547,23 +3938,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 */
+    tp = cm_ClientStrRChr(pathp, '\\');
+    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 */
@@ -3587,17 +3986,17 @@ int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
     /* unreachable */
 }
 
-int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
+int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
 {
-    char umask[11];
+    clientchar_t umask[11];
     int valid;
     int i;
-    char tc1;
-    char tc2;
-    char *tp1;
-    char *tp2;
+    clientchar_t tc1;
+    clientchar_t tc2;
+    clientchar_t *tp1;
+    clientchar_t *tp2;
 
-    /* XXX redo this, calling smb_V3MatchMask with a converted mask */
+    /* XXX redo this, calling cm_MatchMask with a converted mask */
 
     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
     if (!valid) 
@@ -3609,10 +4008,10 @@ int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
     tp1 = umask;       /* real name, in mask format */
     tp2 = maskp;       /* mask, in mask format */
     for(i=0; i<11; i++) {
-        tc1 = *tp1++;  /* char from real name */
-        tc2 = *tp2++;  /* char from mask */
-        tc1 = (char) cm_foldUpper[(unsigned char)tc1];
-        tc2 = (char) cm_foldUpper[(unsigned char)tc2];
+        tc1 = *tp1++;  /* clientchar_t from real name */
+        tc2 = *tp2++;  /* clientchar_t from mask */
+        tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
+        tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
         if (tc1 == tc2) 
             continue;
         if (tc2 == '?' && tc1 != ' ') 
@@ -3626,11 +4025,11 @@ int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
     return 1;
 }
 
-char *smb_FindMask(char *pathp)
+clientchar_t *smb_FindMask(clientchar_t *pathp)
 {
-    char *tp;
+    clientchar_t *tp;
         
-    tp = strrchr(pathp, '\\'); /* find last slash */
+    tp = cm_ClientStrRChr(pathp, '\\');        /* find last slash */
 
     if (tp) 
         return tp+1;   /* skip the slash */
@@ -3638,11 +4037,15 @@ char *smb_FindMask(char *pathp)
         return pathp;  /* no slash, return the entire path */
 }       
 
+/* SMB_COM_SEARCH for a volume label
+
+   (This is called from smb_ReceiveCoreSearchDir() and not an actual
+   dispatch function.) */
 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    unsigned char *pathp;
+    clientchar_t *pathp;
     unsigned char *tp;
-    unsigned char mask[11];
+    clientchar_t mask[12];
     unsigned char *statBlockp;
     unsigned char initStatBlock[21];
     int statLen;
@@ -3651,12 +4054,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);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
-    statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
-    osi_assert(statBlockp != NULL);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp,
+                                SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
+    osi_assertx(pathp != NULL, "null path");
+    statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
+    osi_assertx(statBlockp != NULL, "null statBlock");
     if (statLen == 0) {
         statBlockp = initStatBlock;
         statBlockp[0] = 8;
@@ -3697,6 +4099,9 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     *tp++ = 0;
     *tp++ = 0;
 
+    /* The filename is a UCHAR buffer that is ASCII even if Unicode
+       was negotiated. */
+
     /* finally, null-terminated 8.3 pathname, which we set to AFS */
     memset(tp, ' ', 13);
     strcpy(tp, "AFS");
@@ -3708,8 +4113,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,
+                        clientchar_t * tidPathp, clientchar_t * relPathp,
+                        cm_user_t *userp, cm_req_t *reqp)
 {
     long code = 0;
     cm_scache_t *scp;
@@ -3719,23 +4126,31 @@ long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
     char attr;
     smb_dirListPatch_t *patchp;
     smb_dirListPatch_t *npatchp;
+    clientchar_t path[AFSPATHMAX];
 
     for (patchp = *dirPatchespp; patchp; patchp =
          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
 
         dptr = patchp->dptr;
 
+        cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
+                            relPathp ? relPathp : _C(""), patchp->dep->name);
+        reqp->relPathp = path;
+        reqp->tidPathp = tidPathp;
+
         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
+        reqp->relPathp = reqp->tidPathp = NULL;
+
         if (code) {
             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
                 *dptr++ = SMB_ATTR_HIDDEN;
             continue;
         }
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         if (code) {    
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
             cm_ReleaseSCache(scp);
             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
                 *dptr++ = SMB_ATTR_HIDDEN;
@@ -3744,6 +4159,7 @@ long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
 
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
+        lock_ConvertWToR(&scp->rw);
         attr = smb_Attributes(scp);
         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
@@ -3766,7 +4182,7 @@ long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
         /* copy out file length */
         *((u_long *)dptr) = scp->length.LowPart;
         dptr += 4;
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseRead(&scp->rw);
         cm_ReleaseSCache(scp);
     }
         
@@ -3782,14 +4198,15 @@ long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
     return code;
 }
 
+/* SMB_COM_SEARCH */
 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int attribute;
     long nextCookie;
-    char *tp;
+    unsigned char *tp;
     long code = 0;
-    char *pathp;
-    cm_dirEntry_t *dep;
+    clientchar_t *pathp;
+    cm_dirEntry_t *dep = 0;
     int maxCount;
     smb_dirListPatch_t *dirListPatchesp;
     smb_dirListPatch_t *curPatchp;
@@ -3809,10 +4226,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     cm_pageHeader_t *pageHeaderp;
     cm_user_t *userp = NULL;
     int slotInPage;
-    char shortName[13];
-    char *actualName;
-    char *shortNameEnd;
-    char mask[11];
+    clientchar_t mask[12];
     int returnedNames;
     long nextEntryCookie;
     int numDirChunks;          /* # of 32 byte dir chunks in this entry */
@@ -3823,7 +4237,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;
+    clientchar_t *tidPathp = 0;
     cm_req_t req;
     cm_fid_t fid;
     int fileType;
@@ -3837,9 +4251,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     caseFold = CM_FLAG_CASEFOLD;
 
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp,
+                                SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
 
     /* bail out if request looks bad */
@@ -3862,8 +4275,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         if (attribute & 0x8)
             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
 
-        osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
-                  maxCount, osi_LogSaveString(smb_logp, pathp));
+        osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
+                 maxCount, osi_LogSaveClientString(smb_logp, pathp));
 
         if (*pathp == 0) {     /* null pathp, treat as root dir */
             if (!(attribute & SMB_ATTR_DIRECTORY))     /* exclude dirs */
@@ -3874,7 +4287,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)) 
@@ -3888,8 +4301,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         dsp = smb_FindDirSearch(inCookiep[12]);
         if (!dsp) {
             /* can't find dir search status; fatal error */
-            osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
-                     inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
+            osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
+                     inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
             return CM_ERROR_BADFD;
         }
         attribute = dsp->attribute;
@@ -3900,7 +4313,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.
@@ -3917,12 +4330,12 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     lock_ObtainMutex(&dsp->mx);
     if (dsp->scp) {
         scp = dsp->scp;
-       osi_Log2(afsd_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
+       osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
         cm_HoldSCache(scp);
         code = 0;
     } else {
         spacep = inp->spacep;
-        smb_StripLastComponent(spacep->data, NULL, pathp);
+        smb_StripLastComponent(spacep->wdata, NULL, pathp);
         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
         if (code) {
             lock_ReleaseMutex(&dsp->mx);
@@ -3931,17 +4344,23 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             smb_ReleaseDirSearch(dsp);
             return CM_ERROR_NOFILES;
         }
-        code = cm_NameI(cm_data.rootSCachep, spacep->data,
+        cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
+        cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
+
+        code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
         if (code == 0) {
 #ifdef DFS_SUPPORT
             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
+                int pnc;
+
+                pnc  = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
                 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;
@@ -3949,7 +4368,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 #endif /* DFS_SUPPORT */
 
             dsp->scp = scp;
-           osi_Log2(afsd_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, 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.
@@ -3957,14 +4376,14 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
              * now.
              */
             cm_HoldSCache(scp);
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
                  && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
                 dsp->flags |= SMB_DIRSEARCH_BULKST;
                dsp->scp->bulkStatProgress = hzero;
             }
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
         }
     }
     lock_ReleaseMutex(&dsp->mx);
@@ -3982,11 +4401,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     smb_SetSMBParm(outp, 0, 0);
 
     /* get the directory size */
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) {
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         smb_DeleteDirSearch(dsp);
@@ -4008,6 +4427,10 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     code = 0;
     returnedNames = 0;
     while (1) {
+        clientchar_t *actualName;
+        clientchar_t shortName[13];
+        clientchar_t *shortNameEnd;
+
         /* make sure that curOffset.LowPart doesn't point to the first
          * 32 bytes in the 2nd through last dir page, and that it doesn't
          * point at the first 13 32-byte chunks in the first dir page,
@@ -4055,24 +4478,22 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                 buf_Release(bufferp);
                 bufferp = NULL;
             }  
-            lock_ReleaseMutex(&scp->mx);
-            lock_ObtainRead(&scp->bufCreateLock);
+            lock_ReleaseWrite(&scp->rw);
             code = buf_Get(scp, &thyper, &bufferp);
-            lock_ReleaseRead(&scp->bufCreateLock);
             lock_ObtainMutex(&dsp->mx);
 
             /* now, if we're doing a star match, do bulk fetching of all of 
              * the status info for files in the dir.
              */
             if (starPattern) {
-                smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
-                lock_ObtainMutex(&scp->mx);
+                smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
+                lock_ObtainWrite(&scp->rw);
                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
                      LargeIntegerGreaterThanOrEqualTo(thyper, 
                                                       scp->bulkStatProgress)) {
                     /* Don't bulk stat if risking timeout */
                     int now = GetTickCount();
-                    if (now - req.startTime > RDRtimeout) {
+                    if (now - req.startTime > RDRtimeout * 1000) {
                         scp->bulkStatProgress = thyper;
                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
@@ -4081,7 +4502,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                         code = cm_TryBulkStat(scp, &thyper, userp, &req);
                 }
             } else {
-                lock_ObtainMutex(&scp->mx);
+                lock_ObtainWrite(&scp->rw);
             }
             lock_ReleaseMutex(&dsp->mx);
             if (code) {
@@ -4164,15 +4585,16 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
 
         /* Compute 8.3 name if necessary */
-        actualName = dep->name;
+        actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
         if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
-            cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
+            free(actualName);
+            cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
             actualName = shortName;
         }
 
-        osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
-                  dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
-                  osi_LogSaveString(smb_logp, actualName));
+        osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
+                 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
+                 osi_LogSaveClientString(smb_logp, actualName));
 
         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
             /* this is one of the entries to use: it is not deleted
@@ -4191,15 +4613,13 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
             {
                 /* We have already done the cm_TryBulkStat above */
-                fid.cell = scp->fid.cell;
-                fid.volume = scp->fid.volume;
-                fid.vnode = ntohl(dep->fid.vnode);
-                fid.unique = ntohl(dep->fid.unique);
+                cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
                 fileType = cm_FindFileType(&fid);
                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
                          "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");
@@ -4208,11 +4628,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 
             *op++ = resByte;
             memcpy(op, mask, 11); op += 11;
-            *op++ = (char) dsp->cookie;        /* they say it must be non-zero */
-            *op++ = (char)(nextEntryCookie & 0xff);
-            *op++ = (char)((nextEntryCookie>>8) & 0xff);
-            *op++ = (char)((nextEntryCookie>>16) & 0xff);
-            *op++ = (char)((nextEntryCookie>>24) & 0xff);
+            *op++ = (unsigned char) dsp->cookie;       /* they say it must be non-zero */
+            *op++ = (unsigned char)(nextEntryCookie & 0xff);
+            *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
+            *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
+            *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
             memcpy(op, &clientCookie, 4); op += 4;
 
             /* now we emit the attribute.  This is sort of tricky,
@@ -4231,10 +4651,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             curPatchp = malloc(sizeof(*curPatchp));
             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
             curPatchp->dptr = op;
-            curPatchp->fid.cell = scp->fid.cell;
-            curPatchp->fid.volume = scp->fid.volume;
-            curPatchp->fid.vnode = ntohl(dep->fid.vnode);
-            curPatchp->fid.unique = ntohl(dep->fid.unique);
+            cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
 
             /* do hidden attribute here since name won't be around when applying
              * dir list patches
@@ -4256,9 +4673,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
              * it fits in 8.3 or the pattern wouldn't match, but it
              * never hurts to be sure.
              */
-            strncpy(op, actualName, 13);
+            cm_ClientStringToUtf8(actualName, -1, op, 13);
             if (smb_StoreAnsiFilenames)
                 CharToOem(op, op);
+            /* This is a UCHAR field, which is ASCII even if Unicode
+               is negotiated. */
 
             /* Uppercase if requested by client */
             if (!KNOWS_LONG_NAMES(inp))
@@ -4278,7 +4697,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     }          /* while copying data for dir listing */
 
     /* release the mutex */
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     if (bufferp) {
        buf_Release(bufferp);
        bufferp = NULL;
@@ -4287,7 +4706,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     /* 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)
@@ -4315,9 +4734,9 @@ 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));
-    origOp[1] = (char)(temp & 0xff);
-    origOp[2] = (char)((temp>>8) & 0xff);
+    osi_assertx(temp == (43 * returnedNames), "unexpected data length");
+    origOp[1] = (unsigned char)(temp & 0xff);
+    origOp[2] = (unsigned char)((temp>>8) & 0xff);
     if (returnedNames == 0) 
         smb_DeleteDirSearch(dsp);
     smb_ReleaseDirSearch(dsp);
@@ -4326,31 +4745,33 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     return code;
 }      
 
+
 /* verify that this is a valid path to a directory.  I don't know why they
  * don't use the get file attributes call.
+ *
+ * SMB_COM_CHECK_DIRECTORY
  */
 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *pathp;
+    clientchar_t *pathp;
     long code = 0;
     cm_scache_t *rootScp;
     cm_scache_t *newScp;
     cm_user_t *userp;
     unsigned int attrs;
     int caseFold;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     cm_req_t req;
+    char * pdata;
 
     cm_InitReq(&req);
 
-    pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
+    pdata = smb_GetSMBData(inp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADFD;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
-    osi_Log1(smb_logp, "SMB receive check path %s",
-             osi_LogSaveString(smb_logp, pathp));
+    osi_Log1(smb_logp, "SMB receive check path %S",
+             osi_LogSaveClientString(smb_logp, pathp));
         
     rootScp = cm_data.rootSCachep;
         
@@ -4374,9 +4795,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;
@@ -4384,12 +4806,12 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 #endif /* DFS_SUPPORT */
 
     /* now lock the vnode with a callback; returns with newScp locked */
-    lock_ObtainMutex(&newScp->mx);
+    lock_ObtainWrite(&newScp->rw);
     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
     if (code) {
        if (code != CM_ERROR_NOACCESS) {
-           lock_ReleaseMutex(&newScp->mx);
+           lock_ReleaseWrite(&newScp->rw);
            cm_ReleaseSCache(newScp);
            cm_ReleaseUser(userp);
            return code;
@@ -4403,16 +4825,17 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     if (!(attrs & SMB_ATTR_DIRECTORY))
         code = CM_ERROR_NOTDIR;
 
-    lock_ReleaseMutex(&newScp->mx);
+    lock_ReleaseWrite(&newScp->rw);
 
     cm_ReleaseSCache(newScp);
     cm_ReleaseUser(userp);
     return code;
 }      
 
+/* SMB_COM_SET_INFORMATION */
 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *pathp;
+    clientchar_t *pathp;
     long code = 0;
     cm_scache_t *rootScp;
     unsigned short attribute;
@@ -4421,7 +4844,8 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     afs_uint32 dosTime;
     cm_user_t *userp;
     int caseFold;
-    char *tidPathp;
+    clientchar_t *tidPathp;
+    char * datap;
     cm_req_t req;
 
     cm_InitReq(&req);
@@ -4430,12 +4854,10 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     attribute = smb_GetSMBParm(inp, 0);
     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
 
-    pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
+    datap = smb_GetSMBData(inp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADSMB;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
                
     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
              dosTime, attribute);
@@ -4461,9 +4883,10 @@ long smb_ReceiveCoreSetFileAttributes(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;
@@ -4474,11 +4897,11 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
      * need the current status to determine what the new status is, in some
      * cases.
      */
-    lock_ObtainMutex(&newScp->mx);
+    lock_ObtainWrite(&newScp->rw);
     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
     if (code) {
-        lock_ReleaseMutex(&newScp->mx);
+        lock_ReleaseWrite(&newScp->rw);
         cm_ReleaseSCache(newScp);
         cm_ReleaseUser(userp);
         return code;
@@ -4488,7 +4911,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 
     /* Check for RO volume */
     if (newScp->flags & CM_SCACHEFLAG_RO) {
-        lock_ReleaseMutex(&newScp->mx);
+        lock_ReleaseWrite(&newScp->rw);
         cm_ReleaseSCache(newScp);
         cm_ReleaseUser(userp);
         return CM_ERROR_READONLY;
@@ -4510,7 +4933,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         attr.unixModeBits = newScp->unixModeBits | 0222;
         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
     }
-    lock_ReleaseMutex(&newScp->mx);
+    lock_ReleaseWrite(&newScp->rw);
 
     /* now call setattr */
     if (attr.mask)
@@ -4524,9 +4947,10 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     return code;
 }
 
+
 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *pathp;
+    clientchar_t *pathp;
     long code = 0;
     cm_scache_t *rootScp;
     cm_scache_t *newScp, *dscp;
@@ -4534,26 +4958,24 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     int attrs;
     cm_user_t *userp;
     int caseFold;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     cm_space_t *spacep;
-    char *lastComp;
+    clientchar_t *lastComp;
+    char * datap;
     cm_req_t req;
 
     cm_InitReq(&req);
 
-    pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
+    datap = smb_GetSMBData(inp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADSMB;
         
     if (*pathp == 0)           /* null path */
-        pathp = "\\";
-    else
-        if (smb_StoreAnsiFilenames)
-            OemToChar(pathp,pathp);
+        pathp = _C("\\");
 
-    osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
-             osi_LogSaveString(smb_logp, pathp));
+    osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
+             osi_LogSaveClientString(smb_logp, pathp));
 
     rootScp = cm_data.rootSCachep;
         
@@ -4586,16 +5008,18 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
      */
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastComp, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
 #ifndef SPECIAL_FOLDERS
-    if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
-        code = cm_NameI(rootScp, spacep->data,
+    if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
+        code = cm_NameI(rootScp, spacep->wdata,
                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
                         userp, tidPathp, &req, &dscp);
         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->wdata);
+                if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
                     return CM_ERROR_BADSHARENAME;
@@ -4629,9 +5053,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;
@@ -4639,11 +5064,11 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 #endif /* DFS_SUPPORT */
 
     /* now lock the vnode with a callback; returns with newScp locked */
-    lock_ObtainMutex(&newScp->mx);
+    lock_ObtainWrite(&newScp->rw);
     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
     if (code) {
-        lock_ReleaseMutex(&newScp->mx);
+        lock_ReleaseWrite(&newScp->rw);
         cm_ReleaseSCache(newScp);
         cm_ReleaseUser(userp);
         return code;
@@ -4680,7 +5105,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     smb_SetSMBParm(outp, 8, 0);
     smb_SetSMBParm(outp, 9, 0);
     smb_SetSMBDataLength(outp, 0);
-    lock_ReleaseMutex(&newScp->mx);
+    lock_ReleaseWrite(&newScp->rw);
 
     cm_ReleaseSCache(newScp);
     cm_ReleaseUser(userp);
@@ -4688,6 +5113,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     return 0;
 }      
 
+/* SMB_COM_TREE_DISCONNECT */
 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tid_t *tidp;
@@ -4698,19 +5124,20 @@ long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_
     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
     if (tidp) {
        lock_ObtainWrite(&smb_rctLock);
-        tidp->delete = 1;
+        tidp->deleteOk = 1;
+        smb_ReleaseTID(tidp, TRUE);
         lock_ReleaseWrite(&smb_rctLock);
-        smb_ReleaseTID(tidp);
     }
 
     return 0;
 }
 
+/* SMB_COM_0PEN */
 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_fid_t *fidp;
-    char *pathp;
-    char *lastNamep;
+    clientchar_t *pathp;
+    clientchar_t *lastNamep;
     int share;
     int attribute;
     long code = 0;
@@ -4719,17 +5146,16 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     afs_uint32 dosTime;
     int caseFold;
     cm_space_t *spacep;
-    char *tidPathp;
+    clientchar_t *tidPathp;
+    char * datap;
     cm_req_t req;
 
     cm_InitReq(&req);
 
-    pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
-       
-    osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
+    datap = smb_GetSMBData(inp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
+
+    osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
 
 #ifdef DEBUG_VERBOSE
     {
@@ -4745,8 +5171,8 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     attribute = smb_GetSMBParm(inp, 1);
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
-    if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
+    if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
@@ -4784,9 +5210,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;
@@ -4811,14 +5238,14 @@ 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(afsd_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
-    lock_ObtainMutex(&scp->mx);
+    osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
 
     /* and the user */
     cm_HoldUser(userp);
@@ -4826,14 +5253,14 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     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);
+    lock_ObtainRead(&scp->rw);
     smb_SetSMBParm(outp, 0, fidp->fid);
     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
@@ -4844,7 +5271,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* pass the open mode back; XXXX add access checks */
     smb_SetSMBParm(outp, 6, (share & 0xf));
     smb_SetSMBDataLength(outp, 0);
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseRead(&scp->rw);
         
     /* notify open */
     cm_Open(scp, 0, userp);
@@ -4861,9 +5288,10 @@ typedef struct smb_unlinkRock {
     cm_user_t *userp;
     cm_req_t *reqp;
     smb_vc_t *vcp;
-    char *maskp;               /* pointer to the star pattern */
+    clientchar_t *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)
@@ -4872,8 +5300,7 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     smb_unlinkRock_t *rockp;
     int caseFold;
     int match;
-    char shortName[13];
-    char *matchName;
+    normchar_t matchName[MAX_PATH];
         
     rockp = vrockp;
 
@@ -4881,51 +5308,49 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
         caseFold |= CM_FLAG_8DOT3;
 
-    matchName = dep->name;
-    match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
+    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
+    match = cm_MatchMask(matchName, rockp->maskp, caseFold);
     if (!match &&
-         (rockp->flags & SMB_MASKFLAG_TILDE) &&
-         !cm_Is8Dot3(dep->name)) {
-        cm_Gen8Dot3Name(dep, shortName, NULL);
-        matchName = shortName;
+        (rockp->flags & SMB_MASKFLAG_TILDE) &&
+        !cm_Is8Dot3(matchName)) {
+        cm_Gen8Dot3Name(dep, matchName, NULL);
         /* 8.3 matches are always case insensitive */
-        match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
+        match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
     }
     if (match) {
-        osi_Log1(smb_logp, "Unlinking %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 | FILE_NOTIFY_CHANGE_CREATION,
-                             dscp, dep->name, NULL, TRUE);
-        if (code == 0) {
-            rockp->any = 1;
+        osi_Log1(smb_logp, "Found match %S",
+                 osi_LogSaveClientString(smb_logp, matchName));
 
-            /* 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) && !cm_ClientStrCmp(matchName, rockp->maskp))
+            code = CM_ERROR_STOPNOW;
+        else
+            code = 0;
     }
     else code = 0;
 
     return code;
 }
 
+/* SMB_COM_DELETE */
 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int attribute;
     long code = 0;
-    char *pathp;
-    char *tp;
+    clientchar_t *pathp;
+    unsigned char *tp;
     cm_space_t *spacep;
     cm_scache_t *dscp;
-    char *lastNamep;
+    clientchar_t *lastNamep;
     smb_unlinkRock_t rock;
     cm_user_t *userp;
     osi_hyper_t thyper;
     int caseFold;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     cm_req_t req;
 
     cm_InitReq(&req);
@@ -4933,15 +5358,13 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     attribute = smb_GetSMBParm(inp, 0);
         
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
-    osi_Log1(smb_logp, "SMB receive unlink %s",
-             osi_LogSaveString(smb_logp, pathp));
+    osi_Log1(smb_logp, "SMB receive unlink %S",
+             osi_LogSaveClientString(smb_logp, pathp));
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
     userp = smb_GetUserFromVCP(vcp, inp);
 
@@ -4952,7 +5375,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
-    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
                     &req, &dscp);
     if (code) {
         cm_ReleaseUser(userp);
@@ -4961,9 +5384,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->wdata);
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
-        if ( WANTS_DFS_PATHNAMES(inp) )
+        if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
             return CM_ERROR_BADSHARENAME;
@@ -4977,8 +5401,8 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         lastNamep++;
 
     rock.any = 0;
-    rock.maskp = smb_FindMask(pathp);
-    rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
+    rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
+    rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
 
     thyper.LowPart = 0;
     thyper.HighPart = 0;
@@ -4986,6 +5410,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. 
@@ -5006,24 +5431,53 @@ 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) {
+            normchar_t normalizedName[MAX_PATH];
+
+            /* Note: entry->name is a non-normalized name */
+
+            osi_Log1(smb_logp, "Unlinking %s",
+                     osi_LogSaveString(smb_logp, entry->name));
+
+            cm_FsStringToNormString(entry->name, -1,
+                                    normalizedName, lengthof(normalizedName));
+
+            code = cm_Unlink(dscp, entry->name, normalizedName, 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, normalizedName, NULL, TRUE);
+        }
+    }
+
+    cm_DirEntryListFree(&rock.matches);
+
     cm_ReleaseUser(userp);
         
     cm_ReleaseSCache(dscp);
 
+    free(rock.maskp);
+
     if (code == 0 && !rock.any)
         code = CM_ERROR_NOSUCHFILE;
     return code;
 }       
 
 typedef struct smb_renameRock {
-    cm_scache_t *odscp;        /* old dir */
-    cm_scache_t *ndscp;        /* new dir */
-    cm_user_t *userp;  /* user */
-    cm_req_t *reqp;            /* request struct */
-    smb_vc_t *vcp;             /* virtual circuit */
-    char *maskp;               /* pointer to star pattern of old file name */
-    int flags;             /* tilde, casefold, etc */
-    char *newNamep;            /* ptr to the new file's name */
+    cm_scache_t *odscp;  /* old dir */
+    cm_scache_t *ndscp;  /* new dir */
+    cm_user_t *userp;    /* user */
+    cm_req_t *reqp;      /* request struct */
+    smb_vc_t *vcp;       /* virtual circuit */
+    normchar_t *maskp;   /* pointer to star pattern of old file name */
+    int flags;           /* tilde, casefold, etc */
+    clientchar_t *newNamep;     /* ptr to the new file's name */
+    fschar_t fsOldName[MAX_PATH]; /* raw FS name */
+    clientchar_t clOldName[MAX_PATH]; /* client name */
     int any;
 } smb_renameRock_t;
 
@@ -5033,43 +5487,39 @@ 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]="";
+    normchar_t matchName[MAX_PATH];
 
     rockp = (smb_renameRock_t *) vrockp;
 
+    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
         caseFold |= CM_FLAG_8DOT3;
 
-    match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
+    match = cm_MatchMask(matchName, rockp->maskp, caseFold);
     if (!match &&
         (rockp->flags & SMB_MASKFLAG_TILDE) &&
-         !cm_Is8Dot3(dep->name)) {
-        cm_Gen8Dot3Name(dep, shortName, NULL);
-        match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
+        !cm_Is8Dot3(matchName)) {
+        cm_Gen8Dot3Name(dep, matchName, NULL);
+        match = cm_MatchMask(matchName, rockp->maskp, caseFold);
     }
+
     if (match) {
        rockp->any = 1;
-
-       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.
-         */
-       osi_Log1(smb_logp, "cm_Rename returns %ld", code);
-        if (code == 0) 
-            code = CM_ERROR_STOPNOW;
-    }       
-    else 
+        StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
+        cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
+                        matchName);
+        code = CM_ERROR_STOPNOW;
+    } else {
        code = 0;
+    }
 
     return code;
 }
 
 
 long 
-smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
+smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
 {
     long code = 0;
     cm_space_t *spacep = NULL;
@@ -5078,12 +5528,12 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     cm_scache_t *newDscp = NULL;
     cm_scache_t *tmpscp= NULL;
     cm_scache_t *tmpscp2 = NULL;
-    char *oldLastNamep;
-    char *newLastNamep;
+    clientchar_t *oldLastNamep;
+    clientchar_t *newLastNamep;
     osi_hyper_t thyper;
     cm_user_t *userp;
     int caseFold;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     DWORD filter;
     cm_req_t req;
 
@@ -5096,10 +5546,10 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
 
     cm_InitReq(&req);
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
+    smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
 
     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
-    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
                     userp, tidPathp, &req, &oldDscp);
     if (code) {
         cm_ReleaseUser(userp);
@@ -5108,17 +5558,18 @@ 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->wdata);
         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;
     }
 #endif /* DFS_SUPPORT */
 
-    smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
-    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
+    smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
                     userp, tidPathp, &req, &newDscp);
 
     if (code) {
@@ -5129,10 +5580,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->wdata);
         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;
@@ -5164,21 +5616,25 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     rock.userp = userp;
     rock.reqp = &req;
     rock.vcp = vcp;
-    rock.maskp = oldLastNamep;
-    rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
+    rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
+    rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
     rock.newNamep = newLastNamep;
+    rock.fsOldName[0] = '\0';
+    rock.clOldName[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) ) {
-        osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
-                 osi_LogSaveString(afsd_logp, newLastNamep));
+    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_LogSaveClientString(smb_logp, newLastNamep));
 
         /* Check if the old and the new names differ only in case. If so return
          * success, else return CM_ERROR_EXISTS 
          */
-        if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
+        if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
 
             /* This would be a success only if the old file is *as same as* the new file */
             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
@@ -5203,6 +5659,9 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
         cm_ReleaseSCache(newDscp);
         cm_ReleaseSCache(oldDscp);
         cm_ReleaseUser(userp);
+
+        free(rock.maskp);
+        rock.maskp = NULL;
         return code; 
     }
 
@@ -5219,31 +5678,40 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     }
     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.fsOldName[0] != '\0') {
+       code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
+                         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, rock.clOldName,
+                                 newLastNamep, TRUE);
+        } else {
+            if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
+                smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
+                                  filter, oldDscp, rock.clOldName,
+                                  NULL, TRUE);
+            if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
+                smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
+                                 filter, newDscp, newLastNamep,
+                                 NULL, TRUE);
+        }
     }
 
     if (tmpscp != NULL) 
@@ -5251,11 +5719,15 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     cm_ReleaseUser(userp);
     cm_ReleaseSCache(oldDscp);
     cm_ReleaseSCache(newDscp);
+
+    free(rock.maskp);
+    rock.maskp = NULL;
+
     return code;
 }       
 
 long 
-smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp) 
+smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp) 
 {
     long code = 0;
     cm_space_t *spacep = NULL;
@@ -5264,11 +5736,11 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     cm_scache_t *tmpscp= NULL;
     cm_scache_t *tmpscp2 = NULL;
     cm_scache_t *sscp = NULL;
-    char *oldLastNamep;
-    char *newLastNamep;
+    clientchar_t *oldLastNamep;
+    clientchar_t *newLastNamep;
     cm_user_t *userp;
     int caseFold;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     DWORD filter;
     cm_req_t req;
 
@@ -5285,9 +5757,9 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
+    smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
     
-    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
                     userp, tidPathp, &req, &oldDscp);
     if (code) {
         cm_ReleaseUser(userp);
@@ -5296,17 +5768,18 @@ 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->wdata);
         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;
     }
 #endif /* DFS_SUPPORT */
 
-    smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
-    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
+    smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
                     userp, tidPathp, &req, &newDscp);
     if (code) {
         cm_ReleaseSCache(oldDscp);
@@ -5316,10 +5789,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->wdata);
         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;
@@ -5349,7 +5823,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
         newLastNamep++;
 
     /* now lookup the old name */
-    osi_Log1(smb_logp,"  looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
+    osi_Log1(smb_logp,"  looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
     code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
     if (code) {
         cm_ReleaseSCache(oldDscp);
@@ -5360,9 +5834,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) ) {
-        osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
-                 osi_LogSaveString(afsd_logp, newLastNamep));
+    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_LogSaveClientString(smb_logp, newLastNamep));
 
         /* if the existing link is to the same file, then we return success */
         if (!code) {
@@ -5384,7 +5860,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));
+    osi_Log1(smb_logp,"  Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
     osi_Log1(smb_logp,"  Link returns 0x%x", code);
 
@@ -5406,25 +5882,22 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     return code;
 }
 
+/* SMB_COM_RENAME */
 long 
 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *oldPathp;
-    char *newPathp;
-    char *tp;
+    clientchar_t *oldPathp;
+    clientchar_t *newPathp;
+    unsigned char *tp;
     long code;
 
     tp = smb_GetSMBData(inp, NULL);
-    oldPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(oldPathp,oldPathp);
-    newPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(newPathp,newPathp);
+    oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
-    osi_Log2(smb_logp, "smb rename [%s] to [%s]",
-             osi_LogSaveString(smb_logp, oldPathp),
-             osi_LogSaveString(smb_logp, newPathp));
+    osi_Log2(smb_logp, "smb rename [%S] to [%S]",
+             osi_LogSaveClientString(smb_logp, oldPathp),
+             osi_LogSaveClientString(smb_logp, newPathp));
 
     code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
 
@@ -5438,9 +5911,10 @@ typedef struct smb_rmdirRock {
     cm_scache_t *dscp;
     cm_user_t *userp;
     cm_req_t *reqp;
-    char *maskp;               /* pointer to the star pattern */
+    normchar_t *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)
@@ -5448,63 +5922,53 @@ int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper
     long code = 0;
     smb_rmdirRock_t *rockp;
     int match;
-    char shortName[13];
-    char *matchName;
+    normchar_t matchName[MAX_PATH];
         
     rockp = (smb_rmdirRock_t *) vrockp;
 
-    matchName = dep->name;
+    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
-        match = (cm_stricmp(matchName, rockp->maskp) == 0);
+        match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
     else
-        match = (strcmp(matchName, rockp->maskp) == 0);
+        match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
     if (!match &&
          (rockp->flags & SMB_MASKFLAG_TILDE) &&
-         !cm_Is8Dot3(dep->name)) {
-        cm_Gen8Dot3Name(dep, shortName, NULL);
-        matchName = shortName;
-        match = (cm_stricmp(matchName, rockp->maskp) == 0);
+         !cm_Is8Dot3(matchName)) {
+        cm_Gen8Dot3Name(dep, matchName, NULL);
+        match = (cm_ClientStrCmpI(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 | FILE_NOTIFY_CHANGE_CREATION,
-                             dscp, dep->name, NULL, TRUE);
-        if (code == 0)
-            rockp->any = 1;
+        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)
 {
     long code = 0;
-    char *pathp;
-    char *tp;
+    clientchar_t *pathp;
+    unsigned char *tp;
     cm_space_t *spacep;
     cm_scache_t *dscp;
-    char *lastNamep;
+    clientchar_t *lastNamep;
     smb_rmdirRock_t rock;
     cm_user_t *userp;
     osi_hyper_t thyper;
     int caseFold;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     cm_req_t req;
 
     cm_InitReq(&req);
 
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
     userp = smb_GetUserFromVCP(vcp, inp);
 
@@ -5515,7 +5979,7 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
-    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
                     userp, tidPathp, &req, &dscp);
 
     if (code) {
@@ -5525,9 +5989,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->wdata);
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
-        if ( WANTS_DFS_PATHNAMES(inp) )
+        if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
             return CM_ERROR_BADSHARENAME;
@@ -5541,14 +6006,15 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         lastNamep++;
        
     rock.any = 0;
-    rock.maskp = lastNamep;
-    rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
+    rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
+    rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
 
     thyper.LowPart = 0;
     thyper.HighPart = 0;
     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);
@@ -5559,15 +6025,42 @@ 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) {
+            clientchar_t clientName[MAX_PATH];
+
+            cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
+
+            osi_Log1(smb_logp, "Removing directory %s",
+                     osi_LogSaveString(smb_logp, entry->name));
+
+            code = cm_RemoveDir(dscp, entry->name, clientName, 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, clientName, NULL, TRUE);
+        }
+    }
+
+    cm_DirEntryListFree(&rock.matches);
+
     cm_ReleaseUser(userp);
         
     cm_ReleaseSCache(dscp);
 
     if (code == 0 && !rock.any)
         code = CM_ERROR_NOSUCHFILE;        
+
+    free(rock.maskp);
+    rock.maskp = NULL;
+
     return code;
 }
 
+/* SMB_COM_FLUSH */
 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -5587,6 +6080,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,7 +6097,7 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
-    if (fidp->flags & SMB_FID_OPENWRITE) {
+    if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
        cm_scache_t * scp = fidp->scp;
        cm_HoldSCache(scp);
        lock_ReleaseMutex(&fidp->mx);
@@ -5617,50 +6116,62 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 }
 
 struct smb_FullNameRock {
-    char *name;
-    cm_scache_t *vnode;
-    char *fullName;
+    clientchar_t *name;
+    cm_scache_t  *vnode;
+    clientchar_t *fullName;
+    fschar_t     *originalName;
 };
 
 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
                      osi_hyper_t *offp)
 {
-    char shortName[13];
+    normchar_t matchName[MAX_PATH];
     struct smb_FullNameRock *vrockp;
 
     vrockp = (struct smb_FullNameRock *)rockp;
 
-    if (!cm_Is8Dot3(dep->name)) {
+    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
+
+    if (!cm_Is8Dot3(matchName)) {
+        clientchar_t shortName[13];
+
         cm_Gen8Dot3Name(dep, shortName, NULL);
 
-        if (cm_stricmp(shortName, vrockp->name) == 0) {
-            vrockp->fullName = strdup(dep->name);
+        if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
+            vrockp->fullName = cm_ClientStrDup(matchName);
+            vrockp->originalName = cm_FsStrDup(dep->name);
             return CM_ERROR_STOPNOW;
         }
     }
-    if (cm_stricmp(dep->name, vrockp->name) == 0 &&
+    if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
         ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
         ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
-        vrockp->fullName = strdup(dep->name);
+        vrockp->fullName = cm_ClientStrDup(matchName);
+        vrockp->originalName = cm_FsStrDup(dep->name);
         return CM_ERROR_STOPNOW;
     }
     return 0;
 }
 
-void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
-                  char **newPathp, cm_user_t *userp, cm_req_t *reqp)
+void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
+                  clientchar_t **newPathp, fschar_t ** originalPathp,
+                  cm_user_t *userp, cm_req_t *reqp)
 {
     struct smb_FullNameRock rock;
     long code = 0;
 
+    memset(&rock, 0, sizeof(rock));
     rock.name = pathp;
     rock.vnode = scp;
 
     code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL); 
-    if (code == CM_ERROR_STOPNOW)
+    if (code == CM_ERROR_STOPNOW) {
         *newPathp = rock.fullName;
-    else
-        *newPathp = strdup(pathp);
+        *originalPathp = rock.originalName;
+    } else {
+        *newPathp = cm_ClientStrDup(pathp);
+        *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
+    }
 }
 
 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
@@ -5668,9 +6179,9 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     long code = 0;
     cm_req_t req;
     cm_scache_t *dscp = NULL;
-    char *pathp = NULL;
+    clientchar_t *pathp = NULL;
     cm_scache_t * scp = NULL;
-    int deleted = 0;
+    cm_scache_t *delscp = NULL;
     int nullcreator = 0;
 
     osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
@@ -5692,12 +6203,12 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     cm_InitReq(&req);
 
     lock_ObtainWrite(&smb_rctLock);
-    if (fidp->delete) {
+    if (fidp->deleteOk) {
        osi_Log0(smb_logp, "  Fid already closed.");
        lock_ReleaseWrite(&smb_rctLock);
        return CM_ERROR_BADFD;
     }
-    fidp->delete = 1;
+    fidp->deleteOk = 1;
     lock_ReleaseWrite(&smb_rctLock);
 
     lock_ObtainMutex(&fidp->mx);
@@ -5707,7 +6218,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     }
 
     if (fidp->NTopen_pathp) {
-       pathp = strdup(fidp->NTopen_pathp);
+       pathp = cm_ClientStrDup(fidp->NTopen_pathp);
     }
 
     if (fidp->scp) {
@@ -5732,9 +6243,11 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
             smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
         }
-       lock_ReleaseMutex(&fidp->mx);
-        code = cm_FSync(scp, userp, &req);
-       lock_ObtainMutex(&fidp->mx);
+        if (smb_AsyncStore != 2) {
+            lock_ReleaseMutex(&fidp->mx);
+            code = cm_FSync(scp, userp, &req);
+            lock_ObtainMutex(&fidp->mx);
+        }
     }
     else 
         code = 0;
@@ -5750,7 +6263,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
        /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
            in zero. */
         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
 
         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
                           CM_SCACHESYNC_NEEDCALLBACK
@@ -5769,35 +6282,45 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
     post_syncopdone:
 
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
     }
 
     if (fidp->flags & SMB_FID_DELONCLOSE) {
-        char *fullPathp;
+        clientchar_t *fullPathp = NULL;
+        fschar_t *originalNamep = NULL;
 
        lock_ReleaseMutex(&fidp->mx);
-        smb_FullName(dscp, scp, pathp, &fullPathp, userp, &req);
-        if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
-            code = cm_RemoveDir(dscp, fullPathp, userp, &req);
+
+        code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
+        if (code) {
+            cm_HoldSCache(scp);
+            delscp = scp;
+        }
+        smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
+        if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
+            code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
            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);
+            code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
            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);
+
+        if (fullPathp)
+            free(fullPathp);
+        if (originalNamep)
+            free(originalNamep);
+
        lock_ObtainMutex(&fidp->mx);
        fidp->flags &= ~SMB_FID_DELONCLOSE;
     }
@@ -5816,8 +6339,8 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
         fidp->NTopen_pathp = NULL;
        fidp->flags &= ~SMB_FID_NTOPEN;
     } else {
-       osi_assert(fidp->NTopen_dscp == NULL);
-       osi_assert(fidp->NTopen_pathp == NULL);
+       osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
+       osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
     }
 
     if (fidp->NTopen_wholepathp) {
@@ -5834,18 +6357,16 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     if (dscp)
        cm_ReleaseSCache(dscp);
 
+    if (delscp) {
+        cm_ReleaseSCache(delscp);
+    }
+
     if (scp) {
-       if (deleted || nullcreator) {
-           lock_ObtainMutex(&scp->mx);
-           if (nullcreator && scp->creator == userp)
-               scp->creator = NULL;
-           if (deleted)
-               scp->flags |= CM_SCACHEFLAG_DELETED;
-           lock_ReleaseMutex(&scp->mx);
-       }
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainWrite(&scp->rw);
+        if (nullcreator && scp->creator == userp)
+            scp->creator = NULL;
        scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
-       lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseWrite(&scp->rw);
        cm_ReleaseSCache(scp);
     }
 
@@ -5855,6 +6376,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     return code;
 }
 
+/* SMB_COM_CLOSE */
 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -5886,7 +6408,7 @@ 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
  */
-long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
+long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
        cm_user_t *userp, long *readp)
 {
     osi_hyper_t offset;
@@ -5897,20 +6419,35 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     osi_hyper_t thyper;
     osi_hyper_t lastByte;
     osi_hyper_t bufferOffset;
-    long bufIndex, nbytes;
+    long bufIndex;
+    afs_uint32 nbytes;
     int chunk;
     int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
     cm_req_t req;
 
+    osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
+              fidp->fid, offsetp->LowPart, count);
+
+    *readp = 0;
+
+    lock_ObtainMutex(&fidp->mx);
+    /* make sure we have a readable FD */
+    if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
+       osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
+                 fidp->fid, fidp->flags);
+       lock_ReleaseMutex(&fidp->mx);
+        code = CM_ERROR_BADFDOP;
+        goto done2;
+    }
+    
     cm_InitReq(&req);
 
     bufferp = NULL;
     offset = *offsetp;
 
-    lock_ObtainMutex(&fidp->mx);
     scp = fidp->scp;
     cm_HoldSCache(scp);
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
 
     if (offset.HighPart == 0) {
         chunk = offset.LowPart >> cm_logChunkSize;
@@ -5970,13 +6507,11 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 buf_Release(bufferp);
                 bufferp = NULL;
             }
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
 
-            lock_ObtainRead(&scp->bufCreateLock);
             code = buf_Get(scp, &thyper, &bufferp);
-            lock_ReleaseRead(&scp->bufCreateLock);
 
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
             if (code) goto done;
             bufferOffset = thyper;
 
@@ -6024,38 +6559,40 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     } /* while 1 */
 
   done:
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     if (bufferp)
         buf_Release(bufferp);
 
     if (code == 0 && sequential)
-        cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
+        cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
 
     cm_ReleaseSCache(scp);
 
+  done2:
+    osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
+              fidp->fid, code, *readp);
     return code;
 }
 
 /*
  * smb_WriteData -- common code for Write and Raw Write
  */
-long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
+long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
        cm_user_t *userp, long *writtenp)
 {
-    osi_hyper_t offset;
+    osi_hyper_t offset = *offsetp;
     long code = 0;
     long written = 0;
-    cm_scache_t *scp;
+    cm_scache_t *scp = NULL;
     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 */
-    cm_buf_t *bufferp;
+    afs_uint32 nbytes;         /* # of bytes to transfer this iteration */
+    cm_buf_t *bufferp = NULL;
     osi_hyper_t thyper;                /* hyper tmp variable */
     osi_hyper_t bufferOffset;
-    long 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 */
+    afs_uint32 bufIndex;               /* index in buffer where our data is */
+    int doWriteBack = 0;
+    osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
     DWORD filter = 0;
     cm_req_t req;
 
@@ -6064,12 +6601,6 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
     *writtenp = 0;
 
-    cm_InitReq(&req);
-
-    bufferp = NULL;
-    doWriteBack = 0;
-    offset = *offsetp;
-
     lock_ObtainMutex(&fidp->mx);
     /* make sure we have a writable FD */
     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
@@ -6077,14 +6608,16 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                  fidp->fid, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         code = CM_ERROR_BADFDOP;
-        goto done;
+        goto done2;
     }
     
+    cm_InitReq(&req);
+
     scp = fidp->scp;
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
 
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK
@@ -6116,15 +6649,23 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     /* now, if the new position (thyper) and the old (offset) are in
      * different storeback windows, remember to store back the previous
      * storeback window when we're done with the write.
+     *
+     * the purpose of this logic is to slow down the CIFS client 
+     * in order to avoid the client disconnecting during the CLOSE
+     * operation if there are too many dirty buffers left to write
+     * than can be accomplished during 45 seconds.  This used to be
+     * based upon cm_chunkSize but we desire cm_chunkSize to be large
+     * so that we can read larger amounts of data at a time.
      */
-    if ((thyper.LowPart & (-cm_chunkSize)) !=
-         (offset.LowPart & (-cm_chunkSize))) {
+    if (smb_AsyncStore == 1 && 
+         (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
+         (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
         /* they're different */
         doWriteBack = 1;
         writeBackOffset.HighPart = offset.HighPart;
-        writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
+        writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
     }
-        
+
     *writtenp = count;
 
     /* now, copy the data one buffer at a time, until we've filled the
@@ -6151,14 +6692,12 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 buf_Release(bufferp);
                 bufferp = NULL;
             }  
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
 
-            lock_ObtainRead(&scp->bufCreateLock);
             code = buf_Get(scp, &thyper, &bufferp);
-            lock_ReleaseRead(&scp->bufCreateLock);
 
             lock_ObtainMutex(&bufferp->mx);
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
             if (code) goto done;
 
             bufferOffset = thyper;
@@ -6197,7 +6736,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                                                                                ConvertLongToLargeInteger(count)),
                                                                minLength))) {
                     if (count < cm_data.buf_blockSize
-                         && bufferp->dataVersion == -1)
+                         && bufferp->dataVersion == CM_BUF_VERSION_BAD)
                         memset(bufferp->datap, 0,
                                 cm_data.buf_blockSize);
                     bufferp->dataVersion = scp->dataVersion;
@@ -6209,9 +6748,9 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 lock_ReleaseMutex(&bufferp->mx);
                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
                                      &req);
-                lock_ReleaseMutex(&scp->mx);
+                lock_ReleaseWrite(&scp->rw);
                 lock_ObtainMutex(&bufferp->mx);
-                lock_ObtainMutex(&scp->mx);
+                lock_ObtainWrite(&scp->rw);
                 if (code) break;
             }
             if (code) {
@@ -6234,7 +6773,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
         /* now copy the data */
        memcpy(bufferp->datap + bufIndex, op, nbytes);
-        buf_SetDirty(bufferp);
+        buf_SetDirty(bufferp, bufIndex, nbytes);
 
         /* and record the last writer */
         if (bufferp->userp != userp) {
@@ -6254,7 +6793,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     } /* while 1 */
 
   done:
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
 
     if (bufferp) {
         lock_ReleaseMutex(&bufferp->mx);
@@ -6270,27 +6809,37 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     }       
     lock_ReleaseMutex(&fidp->mx);
 
-    if (code == 0 && doWriteBack) {
-        long code2;
-        lock_ObtainMutex(&scp->mx);
-        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 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 */
+    if (code == 0) {
+        if (smb_AsyncStore > 0) {
+            if (doWriteBack) {
+                long code2;
+
+                lock_ObtainWrite(&scp->rw);
+                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 0x%x",
+                          fidp->fid, code2);
+                lock_ReleaseWrite(&scp->rw);
+                cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
+                                    writeBackOffset.HighPart, 
+                                    smb_AsyncStoreSize, 0, userp);
+                /* cm_SyncOpDone is called at the completion of cm_BkgStore */
+            }
+        } else {
+            cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
+        }
     }
 
     cm_ReleaseSCache(scp);
 
+  done2:
     osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
               fidp->fid, code, *writtenp);
     return code;
 }
 
+/* SMB_COM_WRITE */
 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fd;
@@ -6300,6 +6849,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     long written = 0, total_written = 0;
     unsigned pid;
     smb_fid_t *fidp;
+    smb_t* smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
     cm_attr_t truncAttr;       /* attribute struct used for truncating file */
@@ -6325,6 +6875,12 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         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);
@@ -6341,7 +6897,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LARGE_INTEGER LOffset;
         LARGE_INTEGER LLength;
 
-        pid = ((smb_t *) inp)->pid;
+        pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
         LOffset.HighPart = offset.HighPart;
@@ -6349,9 +6905,9 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&fidp->scp->rw);
         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ReleaseWrite(&fidp->scp->rw);
 
         if (code) {
            osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
@@ -6404,7 +6960,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         offset = LargeIntegerAdd(offset,
                                  ConvertLongToLargeInteger(written));
-        count -= written;
+        count -= (unsigned short)written;
         total_written += written;
         written = 0;
     }
@@ -6440,6 +6996,12 @@ void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
     fd = smb_GetSMBParm(inp, 0);
     fidp = smb_FindFID(vcp, fd, 0);
 
+    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);
 
@@ -6482,6 +7044,7 @@ long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     return 0;
 }
 
+/* SMB_COM_WRITE_RAW */
 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
 {
     osi_hyper_t offset;
@@ -6489,6 +7052,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     long totalCount;
     unsigned short fd;
     smb_fid_t *fidp;
+    smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
     char *op;
@@ -6542,13 +7106,19 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         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;
         LARGE_INTEGER LOffset;
         LARGE_INTEGER LLength;
 
-        pid = ((smb_t *) inp)->pid;
+        pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
         LOffset.HighPart = offset.HighPart;
@@ -6556,9 +7126,9 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&fidp->scp->rw);
         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ReleaseWrite(&fidp->scp->rw);
 
         if (code) {
             smb_ReleaseFID(fidp);
@@ -6653,6 +7223,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     return 0;
 }
 
+/* SMB_COM_READ */
 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -6660,6 +7231,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     unsigned short fd;
     unsigned pid;
     smb_fid_t *fidp;
+    smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
     char *op;
@@ -6677,6 +7249,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);
@@ -6690,7 +7268,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LARGE_INTEGER LOffset, LLength;
         cm_key_t key;
 
-        pid = ((smb_t *) inp)->pid;
+        pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
         LOffset.HighPart = 0;
@@ -6698,9 +7276,9 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
         
-        lock_ObtainMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&fidp->scp->rw);
         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ReleaseWrite(&fidp->scp->rw);
     }
     if (code) {
         smb_ReleaseFID(fidp);
@@ -6743,20 +7321,21 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return code;
 }
 
+/* SMB_COM_CREATE_DIRECTORY */
 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *pathp;
+    clientchar_t *pathp;
     long code = 0;
     cm_space_t *spacep;
-    char *tp;
+    unsigned char *tp;
     cm_user_t *userp;
     cm_scache_t *dscp;                 /* dir we're dealing with */
     cm_scache_t *scp;                  /* file we're creating */
     cm_attr_t setAttr;
     int initialModeBits;
-    char *lastNamep;
+    clientchar_t *lastNamep;
     int caseFold;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     cm_req_t req;
 
     cm_InitReq(&req);
@@ -6767,15 +7346,13 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     initialModeBits = 0777;
         
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
-    if (strcmp(pathp, "\\") == 0)
+    if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
         return CM_ERROR_EXISTS;
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
     userp = smb_GetUserFromVCP(vcp, inp);
 
@@ -6787,7 +7364,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         return CM_ERROR_NOSUCHPATH;
     }
 
-    code = cm_NameI(cm_data.rootSCachep, spacep->data,
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
                     userp, tidPathp, &req, &dscp);
 
@@ -6798,9 +7375,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->wdata);
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
-        if ( WANTS_DFS_PATHNAMES(inp) )
+        if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
             return CM_ERROR_BADSHARENAME;
@@ -6816,7 +7394,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);
@@ -6847,7 +7425,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     return 0;
 }
 
-BOOL smb_IsLegalFilename(char *filename)
+BOOL smb_IsLegalFilename(clientchar_t *filename)
 {
     /* 
      *  Find the longest substring of filename that does not contain
@@ -6855,18 +7433,19 @@ BOOL smb_IsLegalFilename(char *filename)
      *  than the length of the whole string, then one or more of the
      *  illegal chars is in filename. 
      */
-    if (strcspn(filename, illegalChars) < strlen(filename))
+    if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
         return FALSE;
 
     return TRUE;
-}        
+}
 
+/* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
-    char *pathp;
+    clientchar_t *pathp;
     long code = 0;
     cm_space_t *spacep;
-    char *tp;
+    unsigned char *tp;
     int excl;
     cm_user_t *userp;
     cm_scache_t *dscp;                 /* dir we're dealing with */
@@ -6875,10 +7454,10 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     int initialModeBits;
     smb_fid_t *fidp;
     int attributes;
-    char *lastNamep;
+    clientchar_t *lastNamep;
     int caseFold;
     afs_uint32 dosTime;
-    char *tidPathp;
+    clientchar_t *tidPathp;
     cm_req_t req;
     int created = 0;                   /* the file was new */
 
@@ -6896,12 +7475,10 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        initialModeBits &= ~0222;
         
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
     userp = smb_GetUserFromVCP(vcp, inp);
 
@@ -6912,7 +7489,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_ReleaseUser(userp);
         return CM_ERROR_NOSUCHPATH;
     }
-    code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
+    code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
                     userp, tidPathp, &req, &dscp);
 
     if (code) {
@@ -6922,9 +7499,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->wdata);
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
-        if ( WANTS_DFS_PATHNAMES(inp) )
+        if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
             return CM_ERROR_BADSHARENAME;
@@ -6942,7 +7520,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     if (!smb_IsLegalFilename(lastNamep))
         return CM_ERROR_BADNTFILENAME;
 
-    osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
+    osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
 #ifdef DEBUG_VERBOSE
     {
         char *hexp;
@@ -6953,7 +7531,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;
@@ -7024,25 +7602,25 @@ 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(afsd_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
+    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);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     
     /* and the user */
     fidp->userp = userp;
@@ -7059,6 +7637,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
+/* SMB_COM_SEEK */
 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     long code = 0;
@@ -7080,10 +7659,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);
@@ -7098,7 +7682,7 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     scp = fidp->scp;
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code == 0) {
@@ -7121,7 +7705,7 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
         smb_SetSMBDataLength(outp, 0);
     }
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     smb_ReleaseFID(fidp);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
@@ -7222,30 +7806,36 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
 
         if (dp->procp) {
             /* we have a recognized operation */
+            char * opName = myCrt_Dispatch(inp->inCom);
 
             if (inp->inCom == 0x1d)
                 /* Raw Write */
                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
             else {
-                osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
+                osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
+                         opName,vcp,vcp->lana,vcp->lsn);
                 code = (*(dp->procp)) (vcp, inp, outp);
-                osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
+                osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",
+                         code,vcp,vcp->lana,vcp->lsn);
 #ifdef LOG_PACKET
                 if ( code == CM_ERROR_BADSMB ||
                      code == CM_ERROR_BADOP )
-                smb_LogPacket(inp);
+                     smb_LogPacket(inp);
 #endif /* LOG_PACKET */
             }   
 
+            newTime = GetTickCount();
+            osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
+
             if (oldGen != sessionGen) {
-                newTime = GetTickCount();
                LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
                         newTime - oldTime, ncbp->ncb_length);
-               osi_Log2(smb_logp, "Pkt straddled session startup, "
-                          "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
+               osi_Log3(smb_logp, "Request %s straddled session startup, "
+                          "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
             }
-        }
-        else {
+
+            FreeSMBStrings(inp);
+        } else {
             /* bad opcode, fail the request, after displaying it */
             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
 #ifdef LOG_PACKET
@@ -7422,7 +8012,7 @@ 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]);
@@ -7476,7 +8066,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 */
@@ -7520,7 +8110,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 */
@@ -7560,6 +8150,7 @@ void smb_Server(VOID *parmp)
     UCHAR rc;
     smb_vc_t *vcp = NULL;
     smb_t *smbp;
+    extern void rx_StartClientThread(void);
 
     rx_StartClientThread();
 
@@ -7617,7 +8208,7 @@ 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];
@@ -7765,8 +8356,10 @@ void smb_Server(VOID *parmp)
         smbp = (smb_t *)bufp->data;
         outbufp->flags = 0;
 
+#ifndef NOTRACE
         __try
         {
+#endif
             if (smbp->com == 0x1d) {
                 /* Special handling for Write Raw */
                 raw_write_cont_t rwc;
@@ -7804,9 +8397,11 @@ void smb_Server(VOID *parmp)
                 /* TODO: what else needs to be serialized? */
                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
             }
+#ifndef NOTRACE        
         }
         __except( smb_ServerExceptionFilter() ) {
         }
+#endif
 
         smb_concurrentCalls--;
 
@@ -7844,10 +8439,10 @@ void InitNCBslot(int idx)
 {
     struct smb_packet *bufp;
     EVENT_HANDLE retHandle;
-    int i;
+    afs_uint32 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);
@@ -7876,13 +8471,19 @@ void smb_Listener(void *parmp)
     long code = 0;
     long len;
     long i;
-    int  session, thread;
+    afs_uint32  session, thread;
     smb_vc_t *vcp = NULL;
     int flags = 0;
     char rname[NCBNAMSZ+1];
     char cname[MAX_COMPUTERNAME_LENGTH+1];
     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
     INT_PTR lana = (INT_PTR) parmp;
+    char eventName[MAX_PATH];
+
+    sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
+    ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
+    if ( GetLastError() == ERROR_ALREADY_EXISTS )
+        thrd_ResetEvent(ListenerShutdown[lana]);
 
     ncbp = GetNCB();
 
@@ -7910,56 +8511,82 @@ void smb_Listener(void *parmp)
 
         code = Netbios(ncbp);
 
-       if (code == NRC_BRIDGE) {
-           int lanaRemaining = 0;
+        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 (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
-               ExitThread(1);
+            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;
 
-           osi_Log2(smb_logp,
-                     "NCBLISTEN lana=%d failed with NRC_BRIDGE.  Listener thread exiting.",
-                     ncbp->ncb_lana_num, code);
+            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] == ncbp->ncb_lana_num) {
-                   smb_StopListener(ncbp, lana_list.lana[i]);
-                   lana_list.lana[i] = 255;
+               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] != 255)
+               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 = -1;
+               smb_LANadapter = LANA_INVALID;
                lana_list.length = 0;
            }
-           FreeNCB(ncbp);
-           return;
-       } else if (code != 0) {
-            char tbuffer[256];
+            lock_ReleaseMutex(&smb_StartedLock);
+           break;
+       }
+#if 0
+        else if (code != 0) {
+            char tbuffer[AFSPATHMAX];
 
             /* terminate silently if shutdown flag is set */
-            if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
-                ExitThread(1);
+            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");
 
             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_panic(tbuffer, __FILE__, __LINE__);
+
+            lock_ReleaseMutex(&smb_StartedLock);
+            break;
         }
+#endif /* 0 */
 
         /* check for remote conns */
         /* first get remote name and insert null terminator */
@@ -8002,7 +8629,7 @@ void smb_Listener(void *parmp)
            }
            
            lock_ObtainMutex(&vcp->mx);
-           strcpy(vcp->rname, rname);
+            cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
            vcp->flags |= flags;
            lock_ReleaseMutex(&vcp->mx);
 
@@ -8073,6 +8700,7 @@ void smb_Listener(void *parmp)
                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
                 smbp->rcls = errClass;
             }
+
             smb_SendPacket(vcp, outp);
             smb_FreePacket(outp);
 
@@ -8094,8 +8722,8 @@ void smb_Listener(void *parmp)
              * 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;
@@ -8139,11 +8767,98 @@ void smb_Listener(void *parmp)
         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 */
-int smb_NetbiosInit(void)
+int smb_NetbiosInit(int locked)
 {
     NCB *ncbp;
     int i, lana, code, l;
@@ -8151,11 +8866,53 @@ int smb_NetbiosInit(void)
     int delname_tried=0;
     int len;
     int lana_found = 0;
+    lana_number_t lanaNum;
 
+    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();
 
-    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);
+
+    /* Also copy the value to the client character encoded string */
+    cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
+
+    if (smb_LANadapter == LANA_INVALID) {
         ncbp->ncb_command = NCBENUM;
         ncbp->ncb_buffer = (PUCHAR)&lana_list;
         ncbp->ncb_length = sizeof(lana_list);
@@ -8183,7 +8940,7 @@ int smb_NetbiosInit(void)
             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]);
         }
@@ -8223,7 +8980,7 @@ int smb_NetbiosInit(void)
         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) {
@@ -8239,7 +8996,7 @@ int smb_NetbiosInit(void)
                     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) {
@@ -8251,58 +9008,97 @@ int smb_NetbiosInit(void)
             }
             else {
                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
-                lana_list.lana[l] = 255;  /* invalid lana */
+                lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
             }
         }
         if (code == 0) {
+            smb_LANadapter = lana;
             lana_found = 1;   /* at least one worked */
         }
     }
 
-    osi_assert(lana_list.length >= 0);
+    osi_assertx(lana_list.length >= 0, "empty lana list");
     if (!lana_found) {
         afsi_log("No valid LANA numbers found!");
        lana_list.length = 0;
-       smb_LANadapter = -1;
+       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_StartListeners()
+void smb_StartListeners(int locked)
 {
     int i;
     int lpid;
     thread_t phandle;
 
-    if (smb_ListenerState == SMB_LISTENER_STARTED)
+    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] == 255) 
+        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_assert(phandle != NULL);
+        osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
         thrd_CloseHandle(phandle);
     }
+    if (!locked)
+        lock_ReleaseMutex(&smb_StartedLock);
 }
 
-void smb_RestartListeners()
+void smb_RestartListeners(int locked)
 {
-    if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
-       if (smb_NetbiosInit())
-           smb_StartListeners();
+    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)
+void smb_StopListener(NCB *ncbp, int lana, int wait)
 {
     long code;
 
@@ -8328,17 +9124,32 @@ void smb_StopListener(NCB *ncbp, int lana)
     } else {
        afsi_log("Netbios NCBRESET lana %d succeeded", lana);
     }
+
+    if (wait)
+        thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
 }
 
-void smb_StopListeners(void)
+void smb_StopListeners(int locked)
 {
     NCB *ncbp;
     int lana, l;
 
-    if (smb_ListenerState == SMB_LISTENER_STOPPED)
+    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();
 
@@ -8346,22 +9157,23 @@ void smb_StopListeners(void)
     for (l = 0; l < lana_list.length; l++) {
         lana = lana_list.lana[l];
 
-       if (lana != 255) {
-           smb_StopListener(ncbp, lana);
+       if (lana != LANA_INVALID) {
+           smb_StopListener(ncbp, lana, TRUE);
 
            /* mark the adapter invalid */
-           lana_list.lana[l] = 255;  /* invalid lana */
+           lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
        }
     }
 
     /* force a re-evaluation of the network adapters */
     lana_list.length = 0;
-    smb_LANadapter = -1;
+    smb_LANadapter = LANA_INVALID;
     FreeNCB(ncbp);
-    Sleep(1000);       /* give the listener threads a chance to exit */
+    if (!locked)
+        lock_ReleaseMutex(&smb_StartedLock);
 }
 
-void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
+void smb_Init(osi_log_t *logp, int useV3,
               int nThreads
               , void *aMBfunc
   )
@@ -8370,17 +9182,16 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     thread_t phandle;
     int lpid;
     INT_PTR i;
-    int len;
     struct tm myTime;
     EVENT_HANDLE retHandle;
     char eventName[MAX_PATH];
+    int startListeners = 0;
 
     smb_TlsRequestSlot = TlsAlloc();
 
     smb_MBfunc = aMBfunc;
 
     smb_useV3 = useV3;
-    smb_LANadapter = LANadapt;
 
     /* Initialize smb_localZero */
     myTime.tm_isdst = -1;              /* compute whether on DST or not */
@@ -8404,12 +9215,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");
@@ -8418,6 +9223,7 @@ 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 */
     smb_RawBufs = calloc(65536,1);
@@ -8432,7 +9238,8 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     smb_ncbFreeListp = NULL;
     smb_packetFreeListp = NULL;
 
-    smb_NetbiosInit();
+    lock_ObtainMutex(&smb_StartedLock);
+    startListeners = smb_NetbiosInit(1);
 
     /* Initialize listener and server structures */
     numVCs = 0;
@@ -8630,7 +9437,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);
@@ -8692,43 +9499,44 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
          * It is actually the domain for local logins, and we are acting as
          * a local SMB server. 
          */
-        bufsize = sizeof(smb_ServerDomainName) - 1;
-        GetComputerName(smb_ServerDomainName, &bufsize);
+        bufsize = lengthof(smb_ServerDomainName) - 1;
+        GetComputerNameW(smb_ServerDomainName, &bufsize);
         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
-        afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
+        afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
     }
 
     /* Start listeners, waiters, servers, and daemons */
-
-    smb_StartListeners();
+    if (startListeners)
+        smb_StartListeners(1);
 
     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);
 
     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);
 
+    lock_ReleaseMutex(&smb_StartedLock);
     return;
 }
 
@@ -8736,7 +9544,7 @@ void smb_Shutdown(void)
 {
     NCB *ncbp;
     long code = 0;
-    int i;
+    afs_uint32 i;
     smb_vc_t *vcp;
 
     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
@@ -8788,7 +9596,7 @@ 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);
@@ -8822,10 +9630,10 @@ void smb_Shutdown(void)
                 if (fidp->scp != NULL) {
                     scp = fidp->scp;
                     fidp->scp = NULL;
-                   lock_ObtainMutex(&scp->mx);
+                   lock_ObtainWrite(&scp->rw);
                    scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
-                   lock_ReleaseMutex(&scp->mx);
-                   osi_Log2(afsd_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
+                   lock_ReleaseWrite(&scp->rw);
+                   osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
                     cm_ReleaseSCache(scp);
                 }
                 lock_ReleaseMutex(&fidp->mx);
@@ -8838,9 +9646,7 @@ void smb_Shutdown(void)
             if (tidp->userp) {
                 cm_user_t *userp = tidp->userp;
                 tidp->userp = NULL;
-                lock_ReleaseWrite(&smb_rctLock);
                 cm_ReleaseUser(userp);
-                lock_ObtainWrite(&smb_rctLock);
             }
         }
     }
@@ -8853,6 +9659,7 @@ void smb_Shutdown(void)
 char *smb_GetSharename()
 {
     char *name;
+    int len;
 
     /* Make sure we have been properly initialized. */
     if (smb_localNamep == NULL)
@@ -8861,16 +9668,18 @@ char *smb_GetSharename()
     /* Allocate space for \\<servername>\<sharename>, plus the
      * terminator.
      */
-    name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
-    sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
+    len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
+    name = malloc(len);
+    snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
     return name;
-}   
+}
 
 
 #ifdef LOG_PACKET
 void smb_LogPacket(smb_packet_t *packet)
 {
     BYTE *vp, *cp;
+    smb_t * smbp;
     unsigned length, paramlen, datalen, i, j;
     char buf[81];
     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
@@ -8879,11 +9688,12 @@ void smb_LogPacket(smb_packet_t *packet)
 
     osi_Log0(smb_logp, "*** SMB packet dump ***");
 
+    smbp = (smb_t *) packet->data;
     vp = (BYTE *) packet->data;
 
-    datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
-    length = paramlen + 2 + datalen;
-
+    paramlen = smbp->wct * 2;
+    datalen = *((WORD *) (smbp->vdata + paramlen));
+    length = sizeof(*smbp) + paramlen + 1 + datalen;
 
     for (i=0;i < length; i+=16)
     {
@@ -8940,97 +9750,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");
+                    fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
+                    fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("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");
+                    fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"), 
+                    fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("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;
+}