Windows: Dfs Referrals Processing. Not all errors are errors.
[openafs.git] / src / WINNT / afsd / smb.c
index 5b13317..b510a1d 100644 (file)
@@ -35,7 +35,7 @@
 #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;
@@ -63,7 +63,7 @@ osi_rwlock_t smb_globalLock;
 osi_rwlock_t smb_rctLock;
 osi_mutex_t  smb_ListenerLock;
 osi_mutex_t  smb_StartedLock;
+
 unsigned char smb_LANadapter = LANA_INVALID;
 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
 int  smb_LanAdapterChangeDetected = 0;
@@ -120,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 */
@@ -142,9 +142,10 @@ 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.
@@ -178,17 +179,23 @@ 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 }};
 
+void smb_InitReq(cm_req_t *reqp)
+{
+    cm_InitReq(reqp);
+    reqp->flags |= CM_REQ_SOURCE_SMB;
+}
+
 void smb_ResetServerPriority()
 {
     void * p = TlsGetValue(smb_TlsRequestSlot);
@@ -229,43 +236,43 @@ const char * ncb_error_string(int code)
 {
     const char * s;
     switch ( code ) {
-    case 0x01: s = "llegal buffer length";                     break; 
-    case 0x03: s = "illegal command";                          break; 
-    case 0x05: s = "command timed out";                        break; 
-    case 0x06: s = "message incomplete, issue another command"; break; 
-    case 0x07: s = "illegal buffer address";                   break; 
-    case 0x08: s = "session number out of range";              break; 
-    case 0x09: s = "no resource available";                    break; 
-    case 0x0a: s = "session closed";                           break; 
-    case 0x0b: s = "command cancelled";                        break; 
-    case 0x0d: s = "duplicate name";                           break; 
-    case 0x0e: s = "name table full";                          break; 
-    case 0x0f: s = "no deletions, name has active sessions";   break; 
-    case 0x11: s = "local session table full";                         break; 
-    case 0x12: s = "remote session table full";                break; 
-    case 0x13: s = "illegal name number";                      break; 
-    case 0x14: s = "no callname";                              break; 
-    case 0x15: s = "cannot put * in NCB_NAME";                         break; 
-    case 0x16: s = "name in use on remote adapter";            break; 
-    case 0x17: s = "name deleted";                             break; 
-    case 0x18: s = "session ended abnormally";                         break; 
-    case 0x19: s = "name conflict detected";                   break; 
-    case 0x21: s = "interface busy, IRET before retrying";     break; 
-    case 0x22: s = "too many commands outstanding, retry later";break;
-    case 0x23: s = "ncb_lana_num field invalid";               break; 
-    case 0x24: s = "command completed while cancel occurring "; break; 
-    case 0x26: s = "command not valid to cancel";              break; 
-    case 0x30: s = "name defined by anther local process";     break; 
-    case 0x34: s = "environment undefined. RESET required";    break; 
-    case 0x35: s = "required OS resources exhausted";          break; 
-    case 0x36: s = "max number of applications exceeded";      break; 
-    case 0x37: s = "no saps available for netbios";            break; 
-    case 0x38: s = "requested resources are not available";    break; 
-    case 0x39: s = "invalid ncb address or length > segment";  break; 
-    case 0x3B: s = "invalid NCB DDID";                                 break; 
-    case 0x3C: s = "lock of user area failed";                         break; 
-    case 0x3f: s = "NETBIOS not loaded";                       break; 
-    case 0x40: s = "system error";                             break;                 
+    case 0x01: s = "NRC_BUFLEN llegal buffer length";                  break; 
+    case 0x03: s = "NRC_ILLCMD illegal command";                       break; 
+    case 0x05: s = "NRC_CMDTMO command timed out";                     break; 
+    case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break; 
+    case 0x07: s = "NRC_BADDR  illegal buffer address";                break; 
+    case 0x08: s = "NRC_SNUMOUT session number out of range";          break; 
+    case 0x09: s = "NRC_NORES no resource available";                  break; 
+    case 0x0a: s = "NRC_SCLOSED asession closed";                      break; 
+    case 0x0b: s = "NRC_CMDCAN command cancelled";                     break; 
+    case 0x0d: s = "NRC_DUPNAME duplicate name";                       break; 
+    case 0x0e: s = "NRC_NAMTFUL name table full";                      break; 
+    case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break; 
+    case 0x11: s = "NRC_LOCTFUL local session table full";             break; 
+    case 0x12: s = "NRC_REMTFUL remote session table full";            break; 
+    case 0x13: s = "NRC_ILLNN illegal name number";                    break; 
+    case 0x14: s = "NRC_NOCALL no callname";                           break; 
+    case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME";              break; 
+    case 0x16: s = "NRC_INUSE name in use on remote adapter";          break; 
+    case 0x17: s = "NRC_NAMERR name deleted";                          break; 
+    case 0x18: s = "NRC_SABORT session ended abnormally";              break; 
+    case 0x19: s = "NRC_NAMCONF name conflict detected";               break; 
+    case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying";  break; 
+    case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
+    case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid";            break; 
+    case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break; 
+    case 0x26: s = "NRC_CANCEL command not valid to cancel";           break; 
+    case 0x30: s = "NRC_DUPENV name defined by anther local process";  break; 
+    case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required";     break; 
+    case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted";   break; 
+    case 0x36: s = "NRC_MAXAPPS max number of applications exceeded";  break; 
+    case 0x37: s = "NRC_NOSAPS no saps available for netbios";                 break; 
+    case 0x38: s = "NRC_NORESOURCES requested resources are not available";    break; 
+    case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment";   break; 
+    case 0x3B: s = "NRC_INVDDID invalid NCB DDID";                     break; 
+    case 0x3C: s = "NRC_LOCKFAILlock of user area failed";             break; 
+    case 0x3f: s = "NRC_OPENERR NETBIOS not loaded";                   break; 
+    case 0x40: s = "NRC_SYSTEM system error";                          break;                 
     default:   s = "unknown error";
     }
     return s;
@@ -455,7 +462,46 @@ char * myCrt_RapDispatch(int i)
     case 63:
         return "RAP(63)NetWkStaGetInfo";
     }
-}       
+}
+
+char * myCrt_NmpipeDispatch(int i)
+{
+    switch(i) {
+    case SMB_TRANS_SET_NMPIPE_STATE:
+       return "SET NMPIPE STATE";
+
+    case SMB_TRANS_RAW_READ_NMPIPE:
+       return "RAW READ NMPIPE";
+
+    case SMB_TRANS_QUERY_NMPIPE_STATE:
+       return "QUERY NMPIPE STATE";
+
+    case SMB_TRANS_QUERY_NMPIPE_INFO:
+       return "QUERY NMPIPE INFO";
+
+    case SMB_TRANS_PEEK_NMPIPE:
+       return "PEEK NMPIPE";
+
+    case SMB_TRANS_TRANSACT_NMPIPE:
+       return "TRANSACT NMPIPE";
+
+    case SMB_TRANS_RAW_WRITE_NMPIPE:
+       return "WRITE NMPIPE";
+
+    case SMB_TRANS_READ_NMPIPE:
+       return "READ NMPIPE";
+
+    case SMB_TRANS_WRITE_NMPIPE:
+       return "WRITE NMPIPE";
+
+    case SMB_TRANS_WAIT_NMPIPE:
+       return "WAIT NMPIPE";
+
+    case SMB_TRANS_CALL_NMPIPE:
+       return "CALL NMPIPE";
+    }
+    return "(Unknown)";
+}
 
 /* scache must be locked */
 unsigned int smb_Attributes(cm_scache_t *scp)
@@ -493,8 +539,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++);
@@ -503,12 +550,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;
     }
@@ -811,7 +858,66 @@ void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
     *unixTimep = dosTime + smb_localZero;
 }
 
+void smb_MarkAllVCsDead(smb_vc_t * exclude)
+{
+    smb_vc_t *vcp;
+    smb_vc_t **vcp_to_cleanup = NULL;
+    int n_to_cleanup = 0;
+    int i;
+
+    osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
+
+    lock_ObtainWrite(&smb_globalLock); /* for dead_sessions[] */
+    lock_ObtainWrite(&smb_rctLock);
+    for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
+
+       if (vcp->magic != SMB_VC_MAGIC)
+           osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
+                      __FILE__, __LINE__);
+
+        if (vcp == exclude)
+            continue;
+
+        lock_ObtainMutex(&vcp->mx);
+        if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
+            vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
+            lock_ReleaseMutex(&vcp->mx);
+            dead_sessions[vcp->session] = TRUE;
+        } else {
+            lock_ReleaseMutex(&vcp->mx);
+        }
+        n_to_cleanup ++;
+    }
+
+    vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
+    i = 0;
+    for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
+        if (vcp == exclude)
+            continue;
+
+        vcp_to_cleanup[i++] = vcp;
+        smb_HoldVCNoLock(vcp);
+    }
+
+    osi_assert(i == n_to_cleanup);
+
+    lock_ReleaseWrite(&smb_rctLock);
+    lock_ReleaseWrite(&smb_globalLock);
+
+    for (i=0; i < n_to_cleanup; i++) {
+        smb_CleanupDeadVC(vcp_to_cleanup[i]);
+        smb_ReleaseVC(vcp_to_cleanup[i]);
+        vcp_to_cleanup[i] = 0;
+    }
+
+    free(vcp_to_cleanup);
+}
+
+#ifdef DEBUG_SMB_REFCOUNT
+smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
+#else
 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
+#endif
 {
     smb_vc_t *vcp;
 
@@ -822,11 +928,14 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
            osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
                       __FILE__, __LINE__);
 
+        lock_ObtainMutex(&vcp->mx);
         if (lsn == vcp->lsn && lana == vcp->lana &&
            !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
+            lock_ReleaseMutex(&vcp->mx);
             smb_HoldVCNoLock(vcp);
             break;
         }
+        lock_ReleaseMutex(&vcp->mx);
     }
     if (!vcp && (flags & SMB_FLAG_CREATE)) {
         vcp = malloc(sizeof(*vcp));
@@ -839,7 +948,7 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
         vcp->uidCounter = 1;   /* UID 0 is reserved for blank user */
         vcp->nextp = smb_allVCsp;
         smb_allVCsp = vcp;
-        lock_InitializeMutex(&vcp->mx, "vc_t mutex");
+        lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
         vcp->lsn = lsn;
         vcp->lana = lana;
         vcp->secCtx = NULL;
@@ -872,7 +981,6 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
 
             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
@@ -881,6 +989,8 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
                  */
                 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
             }
+            if (lsaResp)
+                LsaFreeReturnBuffer(lsaResp);
         }
         else
             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
@@ -890,33 +1000,61 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
             osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
         }
     }
+#ifdef DEBUG_SMB_REFCOUNT
+    if (vcp) {
+        afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
+        osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
+    }
+#endif
     lock_ReleaseWrite(&smb_rctLock);
     lock_ReleaseWrite(&smb_globalLock);
     return vcp;
 }
 
-int smb_IsStarMask(char *maskp)
+static int smb_Is8Dot3StarMask(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;
 }
 
+static int smb_IsStarMask(clientchar_t *maskp)
+{
+    clientchar_t tc;
+        
+    while (*maskp) {
+        tc = *maskp++;
+        if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
+           return 1;
+    }
+    return 0;
+}
+
+#ifdef DEBUG_SMB_REFCOUNT
+void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
+#define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
+#else
 void smb_ReleaseVCInternal(smb_vc_t *vcp)
+#endif
 {
     smb_vc_t **vcpp;
     smb_vc_t * avcp;
 
+    lock_AssertWrite(&smb_rctLock);
     vcp->refCount--;
 
     if (vcp->refCount == 0) {
         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
+#ifdef DEBUG_SMB_REFCOUNT
+            afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
+            osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
+#endif
             /* remove VCP from smb_deadVCsp */
             for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
                 if (*vcpp == vcp) {
@@ -928,33 +1066,73 @@ void smb_ReleaseVCInternal(smb_vc_t *vcp)
             memset(vcp,0,sizeof(smb_vc_t));
             free(vcp);
         } else {
+#ifdef DEBUG_SMB_REFCOUNT
+            afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
+#endif
             for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
                 if (avcp == vcp)
                     break;
             }
             osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
-                      avcp?"not ":"",vcp, vcp->refCount);
-#ifdef DEBUG
-            GenerateMiniDump(NULL);
-#endif
+                      avcp?"":"not ",vcp, 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++;
+            if (avcp) {
+                vcp->refCount++;
+#ifdef DEBUG_SMB_REFCOUNT
+                afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
+                osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
+#endif
+            }
         }
+    } 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.  If we were not called by smb_CleanupDeadVC(),
+         * 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.
+         */
+        if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
+            vcp->refCount++;        /* put the refCount back */
+            lock_ReleaseWrite(&smb_rctLock);
+            smb_CleanupDeadVC(vcp);
+#ifdef DEBUG_SMB_REFCOUNT
+            afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
+            osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
+#endif
+            lock_ObtainWrite(&smb_rctLock);
+        }
+    } else {
+#ifdef DEBUG_SMB_REFCOUNT
+        afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
+        osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
+#endif
     }
 }
 
+#ifdef DEBUG_SMB_REFCOUNT
+void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
+#else
 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
+#endif
 {
+    lock_AssertWrite(&smb_rctLock);
     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
     smb_ReleaseVCInternal(vcp);
 }       
 
+#ifdef DEBUG_SMB_REFCOUNT
+void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
+#else
 void smb_ReleaseVC(smb_vc_t *vcp)
+#endif
 {
     lock_ObtainWrite(&smb_rctLock);
     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
@@ -962,17 +1140,36 @@ void smb_ReleaseVC(smb_vc_t *vcp)
     lock_ReleaseWrite(&smb_rctLock);
 }       
 
+#ifdef DEBUG_SMB_REFCOUNT
+void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
+#else
 void smb_HoldVCNoLock(smb_vc_t *vcp)
+#endif
 {
+    lock_AssertWrite(&smb_rctLock);
     vcp->refCount++;
+#ifdef DEBUG_SMB_REFCOUNT
+    afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
+    osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
+#else
     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
+#endif
 }       
 
+#ifdef DEBUG_SMB_REFCOUNT
+void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
+#else
 void smb_HoldVC(smb_vc_t *vcp)
+#endif
 {
     lock_ObtainWrite(&smb_rctLock);
     vcp->refCount++;
+#ifdef DEBUG_SMB_REFCOUNT
+    afsi_log("%s:%d smb_HoldVC       vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
+    osi_Log4(smb_logp,"%s:%d smb_HoldVC       vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
+#else
     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
+#endif
     lock_ReleaseWrite(&smb_rctLock);
 }       
 
@@ -987,7 +1184,7 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
     smb_user_t *uidpIter;
     smb_user_t *uidpNext;
     smb_vc_t **vcpp;
-
+    afs_uint32 refCount = 0;
 
     lock_ObtainMutex(&vcp->mx);
     if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
@@ -1017,7 +1214,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;
@@ -1035,9 +1232,9 @@ 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);
@@ -1049,9 +1246,9 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
 
     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 */
@@ -1064,21 +1261,36 @@ void smb_CleanupDeadVC(smb_vc_t *vcp)
     }
 
     /* 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 */
+     * reference so that the refcount can reach 0 and we can delete it 
+     *
+     * If the refCount == 1 going into the ReleaseVCNoLock call 
+     * the object will be freed and it won't be safe to clear 
+     * the flag.
+     */
+    refCount = vcp->refCount;
     smb_ReleaseVCNoLock(vcp);
-    
+    if (refCount > 1) {
+        lock_ObtainMutex(&vcp->mx);
+        vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
+        lock_ReleaseMutex(&vcp->mx);
+    }
+
     lock_ReleaseWrite(&smb_rctLock);
     osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
 }
 
+#ifdef DEBUG_SMB_REFCOUNT
+smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
+#else
 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
+#endif
 {
     smb_tid_t *tidp;
 
     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++;
            smb_ReleaseTID(tidp, TRUE);
            goto retry;
@@ -1087,7 +1299,7 @@ smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
         if (tid == tidp->tid) {
             tidp->refCount++;
             break;
-        }      
+        }
     }
     if (!tidp && (flags & SMB_FLAG_CREATE)) {
         tidp = malloc(sizeof(*tidp));
@@ -1097,42 +1309,73 @@ smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
         tidp->vcp = vcp;
         smb_HoldVCNoLock(vcp);
         vcp->tidsp = tidp;
-        lock_InitializeMutex(&tidp->mx, "tid_t mutex");
+        lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
         tidp->tid = tid;
     }
+#ifdef DEBUG_SMB_REFCOUNT
+    if (tidp) {
+        afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
+        osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
+    }
+#endif
     lock_ReleaseWrite(&smb_rctLock);
     return tidp;
-}              
+}
 
+#ifdef DEBUG_SMB_REFCOUNT
+void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
+#else
 void smb_HoldTIDNoLock(smb_tid_t *tidp)
+#endif
 {
+    lock_AssertWrite(&smb_rctLock);
     tidp->refCount++;
+#ifdef DEBUG_SMB_REFCOUNT
+    afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
+    osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
+#endif
 }
 
+#ifdef DEBUG_SMB_REFCOUNT
+void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
+#else
 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
+#endif
 {
     smb_tid_t *tp;
     smb_tid_t **ltpp;
-    cm_user_t *userp;
+    cm_user_t *userp = NULL;
+    smb_vc_t  *vcp = NULL;
 
-    userp = NULL;
     if (!locked)
         lock_ObtainWrite(&smb_rctLock);
+    else
+        lock_AssertWrite(&smb_rctLock);
+
     osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
-    if (tidp->refCount == 0 && (tidp->delete)) {
-        ltpp = &tidp->vcp->tidsp;
-        for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
-            if (tp == tidp) 
-                break;
+#ifdef DEBUG_SMB_REFCOUNT
+    afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
+    osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
+#endif
+    if (tidp->refCount == 0) {
+        if (tidp->deleteOk) {
+            ltpp = &tidp->vcp->tidsp;
+            for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
+                if (tp == tidp) 
+                    break;
+            }
+            osi_assertx(tp != NULL, "null smb_tid_t");
+            *ltpp = tp->nextp;
+            lock_FinalizeMutex(&tidp->mx);
+            userp = tidp->userp;       /* remember to drop ref later */
+            tidp->userp = NULL;
+            vcp = tidp->vcp;
+            tidp->vcp = NULL;
+            free(tidp);
         }
-        osi_assertx(tp != NULL, "null smb_tid_t");
-        *ltpp = tp->nextp;
-        lock_FinalizeMutex(&tidp->mx);
-        userp = tidp->userp;   /* remember to drop ref later */
-        tidp->userp = NULL;
-        smb_ReleaseVCNoLock(tidp->vcp);
-        tidp->vcp = NULL;
     }
+    if (vcp)
+        smb_ReleaseVCNoLock(vcp);
     if (!locked)
         lock_ReleaseWrite(&smb_rctLock);
     if (userp)
@@ -1147,9 +1390,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;
         }
     }
@@ -1161,24 +1404,25 @@ smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
         uidp->vcp = vcp;
         smb_HoldVCNoLock(vcp);
         vcp->usersp = uidp;
-        lock_InitializeMutex(&uidp->mx, "user_t mutex");
+        lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
         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;
         }
@@ -1188,10 +1432,10 @@ 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");
+        lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
        if (flags & SMB_FLAG_AFSLOGON)
            unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
     }
@@ -1200,7 +1444,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;
 
@@ -1208,10 +1452,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;
@@ -1244,7 +1488,7 @@ void smb_ReleaseUsername(smb_username_t *unp)
        free(unp->name);
        free(unp->machine);
        free(unp);
-    }          
+    }
     lock_ReleaseWrite(&smb_rctLock);
     if (userp)
         cm_ReleaseUser(userp);
@@ -1252,6 +1496,7 @@ void smb_ReleaseUsername(smb_username_t *unp)
 
 void smb_HoldUIDNoLock(smb_user_t *uidp)
 {
+    lock_AssertWrite(&smb_rctLock);
     uidp->refCount++;
 }
 
@@ -1329,7 +1574,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;
@@ -1371,7 +1616,11 @@ int smb_SUser(cm_user_t *userp)
  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
  * smb_fid_t data structure if desired File ID cannot be found.
  */
+#ifdef DEBUG_SMB_REFCOUNT
+smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
+#else
 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
+#endif
 {
     smb_fid_t *fidp;
     int newFid = 0;
@@ -1388,7 +1637,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);
@@ -1432,7 +1681,7 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
         fidp->refCount = 1;
         fidp->vcp = vcp;
         smb_HoldVCNoLock(vcp);
-        lock_InitializeMutex(&fidp->mx, "fid_t mutex");
+        lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
         fidp->fid = fid;
         fidp->curr_chunk = fidp->prev_chunk = -2;
         fidp->raw_write_event = event;
@@ -1446,38 +1695,103 @@ smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
        }
     }
 
+#ifdef DEBUG_SMB_REFCOUNT
+    if (fidp) {
+        afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
+        osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
+    }
+#endif
     lock_ReleaseWrite(&smb_rctLock);
     return fidp;
 }
 
+
+/* Must not be called with scp->rw held because smb_ReleaseFID might be called */
+#ifdef DEBUG_SMB_REFCOUNT
+smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
+#else
 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
+#endif
 {
-    smb_fid_t *fidp = NULL;
-    int newFid = 0;
+    smb_fid_t *fidp = NULL, *nextp = NULL;
         
     if (!scp)
         return NULL;
 
+    /* 
+     * If the fidp->scp changes out from under us then
+     * we must not grab a refCount.  It means the *fidp
+     * was processed by smb_CloseFID() and the *fidp is 
+     * no longer valid for use.
+     */
     lock_ObtainWrite(&smb_rctLock);
-    for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
+       for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
+        nextp = (smb_fid_t *) osi_QNext(&fidp->q);
+        if (nextp)
+            nextp->refCount++;
+
         if (scp == fidp->scp) {
-            fidp->refCount++;
-            break;
+            lock_ReleaseWrite(&smb_rctLock);
+            lock_ObtainMutex(&fidp->mx);
+            lock_ObtainWrite(&smb_rctLock);
+            if (scp == fidp->scp) {
+                lock_ReleaseMutex(&fidp->mx);
+                break;
+            }
+            lock_ReleaseMutex(&fidp->mx);
+        }
+
+        if (fidp->refCount > 1) {
+            fidp->refCount--;
+        } else {
+            lock_ReleaseWrite(&smb_rctLock);
+            smb_ReleaseFID(fidp);
+            lock_ObtainWrite(&smb_rctLock);
+        }
+    }
+
+    if (nextp) {
+        if (nextp->refCount > 1) {
+            nextp->refCount--;
+        } else {
+            lock_ReleaseWrite(&smb_rctLock);
+            smb_ReleaseFID(nextp);
+            lock_ObtainWrite(&smb_rctLock);
         }
     }
+
+#ifdef DEBUG_SMB_REFCOUNT
+    if (fidp) {
+        afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
+        osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
+      }
+#endif
     lock_ReleaseWrite(&smb_rctLock);
-    return fidp;
+    return (fidp);
 }
 
+#ifdef DEBUG_SMB_REFCOUNT
+void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
+#else
 void smb_HoldFIDNoLock(smb_fid_t *fidp)
+#endif
 {
+    lock_AssertWrite(&smb_rctLock);
     fidp->refCount++;
+#ifdef DEBUG_SMB_REFCOUNT
+    afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
+    osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
+#endif
 }
 
 
-/* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
-/* the sm_fid_t->mx and smb_rctLock must not be held */
+/* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
+/* the smb_fid_t->mx and smb_rctLock must not be held */
+#ifdef DEBUG_SMB_REFCOUNT
+void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
+#else
 void smb_ReleaseFID(smb_fid_t *fidp)
+#endif
 {
     cm_scache_t *scp = NULL;
     cm_user_t *userp = NULL;
@@ -1487,44 +1801,55 @@ void smb_ReleaseFID(smb_fid_t *fidp)
     lock_ObtainMutex(&fidp->mx);
     lock_ObtainWrite(&smb_rctLock);
     osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
-    if (fidp->refCount == 0 && (fidp->delete)) {
-        vcp = fidp->vcp;
-        fidp->vcp = NULL;
-        scp = fidp->scp;    /* release after lock is released */
-       if (scp) {
-           lock_ObtainWrite(&scp->rw);
-           scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
-           lock_ReleaseWrite(&scp->rw);
-           osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
-           fidp->scp = NULL;
-       }
-        userp = fidp->userp;
-        fidp->userp = NULL;
+#ifdef DEBUG_SMB_REFCOUNT
+    afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
+    osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
+#endif
+    if (fidp->refCount == 0) {
+        if (fidp->deleteOk) {
+            vcp = fidp->vcp;
+            fidp->vcp = NULL;
+            scp = fidp->scp;    /* release after lock is released */
+            if (scp) {
+                lock_ObtainWrite(&scp->rw);
+                scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
+                lock_ReleaseWrite(&scp->rw);
+                osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
+                fidp->scp = NULL;
+            }
+            userp = fidp->userp;
+            fidp->userp = NULL;
 
-       if (vcp->fidsp) 
-           osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
-        thrd_CloseHandle(fidp->raw_write_event);
+            if (vcp->fidsp) 
+                osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
+            thrd_CloseHandle(fidp->raw_write_event);
 
-        /* and see if there is ioctl stuff to free */
-        ioctlp = fidp->ioctlp;
-        if (ioctlp) {
-            if (ioctlp->prefix)
+            /* and see if there is ioctl stuff to free */
+            ioctlp = fidp->ioctlp;
+            if (ioctlp) {
+                if (ioctlp->prefix)
                 cm_FreeSpace(ioctlp->prefix);
-            if (ioctlp->inAllocp)
-                free(ioctlp->inAllocp);
-            if (ioctlp->outAllocp)
-                free(ioctlp->outAllocp);
-            free(ioctlp);
-        }       
-       lock_ReleaseMutex(&fidp->mx);
-       lock_FinalizeMutex(&fidp->mx);
-        free(fidp);
+                if (ioctlp->ioctl.inAllocp)
+                    free(ioctlp->ioctl.inAllocp);
+                if (ioctlp->ioctl.outAllocp)
+                    free(ioctlp->ioctl.outAllocp);
+                free(ioctlp);
+            }
 
-       if (vcp)
-           smb_ReleaseVCNoLock(vcp);
-    } else {
-       lock_ReleaseMutex(&fidp->mx);
+           smb_CleanupRPCFid(fidp);
+
+            lock_ReleaseMutex(&fidp->mx);
+            lock_FinalizeMutex(&fidp->mx);
+            free(fidp);
+            fidp = NULL;
+
+            if (vcp)
+                smb_ReleaseVCNoLock(vcp);
+        }
     }
+    if (fidp)
+        lock_ReleaseMutex(&fidp->mx);
+
     lock_ReleaseWrite(&smb_rctLock);
 
     /* now release the scache structure */
@@ -1539,12 +1864,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;
@@ -1555,25 +1880,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;
 
@@ -1585,13 +1909,22 @@ 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];
+
+    if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 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);
+        if(vrock->match) 
+            free(vrock->match);
+        vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
         vrock->matchType = matchType;
 
         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
@@ -1602,15 +1935,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;
@@ -1621,18 +1956,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;
     }
@@ -1640,17 +1975,19 @@ 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, "srvsvc") == 0 ||
-        _stricmp(shareName, "wkssvc") == 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("spoolss")) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C("winreg")) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
+        ) {
         *pathNamep = NULL;
         return 0;
     }
@@ -1659,25 +1996,24 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
      * 
      * They look like <cell>{%,#}<volume>
      */
-    if (strchr(shareName, '%') != NULL ||
-        strchr(shareName, '#') != NULL) {
-        char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
-                                /* make room for '/@vol:' + mountchar + NULL terminator*/
+    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_LogSaveString(smb_logp, shareName));
+        osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
+                 osi_LogSaveClientString(smb_logp, shareName));
 
-        snprintf(pathstr, sizeof(pathstr)/sizeof(char),
-                 "/" CM_PREFIX_VOL "%s", shareName);
-        pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
-        len = (DWORD)(strlen(pathstr) + 1);
+        cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
+                            _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
+        cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
 
-        *pathNamep = malloc(len);
+        *pathNamep = malloc(cchlen * sizeof(clientchar_t));
         if (*pathNamep) {
-            strcpy(*pathNamep, pathstr);
-            strlwr(*pathNamep);
-            osi_Log1(smb_logp, "   returning pathname [%s]",
-                     osi_LogSaveString(smb_logp, *pathNamep));
+            cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
+            cm_ClientStrLwr(*pathNamep);
+            osi_Log1(smb_logp, "   returning pathname [%S]",
+                     osi_LogSaveClientString(smb_logp, *pathNamep));
 
             return 1;
         } else {
@@ -1686,64 +2022,75 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
     }
 
     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 -= (DWORD)(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
@@ -1752,28 +2099,34 @@ 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
             when using the ANSI RAP calls, the share name is limited to 13 chars
             and hence is truncated. Of course we prefer exact matches. */
-        cm_InitReq(&req);
+        smb_InitReq(&req);
         thyper.HighPart = 0;
         thyper.LowPart = 0;
 
-        vrock.shareName = shareName;
+        vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
+        if (vrock.shareName == NULL) 
+            return 0;
         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;
         }
@@ -1785,20 +2138,31 @@ 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, -1, NULL);
+        code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
+        if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
+            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];
+
+            if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
+            cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
+                                rw ? _C("/.%S/") : _C("/%S/"), temp);
+            *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
             return 1;
         }
     }
+    }
     /* failure */
     *pathNamep = NULL;
     return 0;
@@ -1810,10 +2174,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;
@@ -1829,19 +2193,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;
     }
@@ -1868,9 +2232,7 @@ smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
                 if (!smb_lastDirSearchp)
                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
             }
-            lock_ObtainMutex(&dsp->mx);
             dsp->refCount++;
-            lock_ReleaseMutex(&dsp->mx);
             break;
         }
     }
@@ -1886,7 +2248,6 @@ smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
 
 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
 {
-    lock_ObtainWrite(&smb_globalLock);
     lock_ObtainMutex(&dsp->mx);
     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
              dsp->cookie, dsp, dsp->scp);
@@ -1901,7 +2262,6 @@ void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
         lock_ReleaseWrite(&dsp->scp->rw);
     }  
     lock_ReleaseMutex(&dsp->mx);
-    lock_ReleaseWrite(&smb_globalLock);
 }               
 
 /* Must be called with the smb_globalLock held */
@@ -1909,20 +2269,22 @@ void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
 {
     cm_scache_t *scp = NULL;
 
-    lock_ObtainMutex(&dsp->mx);
     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);
-        osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
-        lock_ReleaseMutex(&dsp->mx);
-        lock_FinalizeMutex(&dsp->mx);
-        scp = dsp->scp;
-       osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
-                dsp->cookie, dsp, scp);
-        free(dsp);
-    } else {
-        lock_ReleaseMutex(&dsp->mx);
+    if (dsp->refCount == 0) {
+        lock_ObtainMutex(&dsp->mx);
+        if (dsp->flags & SMB_DIRSEARCH_DELETE) {
+            if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
+                smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
+            osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
+            lock_ReleaseMutex(&dsp->mx);
+            lock_FinalizeMutex(&dsp->mx);
+            scp = dsp->scp;
+            osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
+                     dsp->cookie, dsp, scp);
+            free(dsp);
+        } else {
+            lock_ReleaseMutex(&dsp->mx);
+        }
     }
     /* do this now to avoid spurious locking hierarchy creation */
     if (scp) 
@@ -1954,28 +2316,28 @@ smb_dirSearch_t *smb_FindDirSearch(long cookie)
 void smb_GCDirSearches(int isV3)
 {
     smb_dirSearch_t *prevp;
-    smb_dirSearch_t *tp;
+    smb_dirSearch_t *dsp;
     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
     int victimCount;
     int i;
         
     victimCount = 0;   /* how many have we got so far */
-    for (tp = smb_lastDirSearchp; tp; tp=prevp) {
+    for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
         /* we'll move tp from queue, so
          * do this early.
          */
-        prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q); 
+        prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);        
         /* if no one is using this guy, and we're either in the new protocol,
          * or we're in the old one and this is a small enough ID to be useful
          * to the old protocol, GC this guy.
          */
-        if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
+        if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
             /* hold and delete */
-           lock_ObtainMutex(&tp->mx);
-            tp->flags |= SMB_DIRSEARCH_DELETE;
-           lock_ReleaseMutex(&tp->mx);
-            victimsp[victimCount++] = tp;
-            tp->refCount++;
+           lock_ObtainMutex(&dsp->mx);
+            dsp->flags |= SMB_DIRSEARCH_DELETE;
+           lock_ReleaseMutex(&dsp->mx);
+            victimsp[victimCount++] = dsp;
+            dsp->refCount++;
         }
 
         /* don't do more than this */
@@ -2035,9 +2397,7 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
             /* don't need to watch for refcount zero and deleted, since
             * we haven't dropped the global lock.
             */
-            lock_ObtainMutex(&dsp->mx);
             dsp->refCount--;
-            lock_ReleaseMutex(&dsp->mx);
             ++smb_dirSearchCounter;
             continue;
         }      
@@ -2047,7 +2407,7 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
         dsp->cookie = smb_dirSearchCounter;
         ++smb_dirSearchCounter;
         dsp->refCount = 1;
-        lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
+        lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
         dsp->lastTime = osi_Time();
         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
         if (!smb_lastDirSearchp) 
@@ -2061,7 +2421,7 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
     return dsp;
 }
 
-static smb_packet_t *GetPacket(void)
+static smb_packet_t *smb_GetPacket(void)
 {
     smb_packet_t *tbp;
 
@@ -2094,7 +2454,7 @@ static smb_packet_t *GetPacket(void)
 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
 {
     smb_packet_t *tbp;
-    tbp = GetPacket();
+    tbp = smb_GetPacket();
     memcpy(tbp, pkt, sizeof(smb_packet_t));
     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
     tbp->stringsp = NULL;
@@ -2103,7 +2463,7 @@ smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
     return tbp;
 }
 
-static NCB *GetNCB(void)
+static NCB *smb_GetNCB(void)
 {
     smb_ncb_t *tbp;
     NCB *ncbp;
@@ -2164,7 +2524,7 @@ void smb_FreePacket(smb_packet_t *tbp)
         smb_ReleaseVC(vcp);
 }
 
-static void FreeNCB(NCB *bufferp)
+static void smb_FreeNCB(NCB *bufferp)
 {
     smb_ncb_t *tbp;
         
@@ -2308,7 +2668,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) 
@@ -2321,7 +2681,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) 
@@ -2336,7 +2696,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 */
@@ -2350,7 +2710,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) {
@@ -2367,11 +2727,12 @@ void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
 
 
 
-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) {
@@ -2387,31 +2748,51 @@ void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp
     }
 }
 
-unsigned char *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
-                                   char **chainpp, int flags)
+clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
+                                  char **chainpp, int flags)
 {
     size_t cb;
+    afs_uint32 type = *inp++;
 
-    if (*inp++ != 0x4) 
-        return NULL;
+    /* 
+     * The first byte specifies the type of the input string.
+     * CIFS TR 1.0 3.2.10.  This function only parses null terminated
+     * strings.
+     */
+    switch (type) {
+    /* Length Counted */
+    case 0x1: /* Data Block */
+    case 0x5: /* Variable Block */
+        cb = *inp++ << 16 | *inp++;
+        break;
+
+    /* Null-terminated string */
+    case 0x4: /* ASCII */
+    case 0x3: /* Pathname */
+    case 0x2: /* Dialect */
+        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);
+        }
+        break;
+
+    default:
+        return NULL;            /* invalid input */
+    }
 
 #ifdef SMB_UNICODE
-    if (!WANTS_UNICODE(pktp))
+    if (type == 0x2 /* Dialect */ || !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);
 }
 
-unsigned char *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
-                               char ** chainpp, int flags)
+clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
+                              char ** chainpp, int flags)
 {
     size_t cb;
 
@@ -2427,11 +2808,12 @@ unsigned char *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
 #endif
         cb = sizeof(pktp->data);
     }
-    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
+                              flags | SMB_STRF_SRCNULTERM);
 }
 
-unsigned char *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
-                                 size_t cb, char ** chainpp, int 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))
@@ -2441,8 +2823,8 @@ unsigned char *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
 }
 
-unsigned char *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
-                                  size_t cch, char ** chainpp, int flags)
+clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
+                                 size_t cch, char ** chainpp, int flags)
 {
     size_t cb = cch;
 
@@ -2456,15 +2838,15 @@ unsigned char *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
 }
 
-unsigned char *smb_ParseStringBuf(const unsigned char * bufbase,
-                                  cm_space_t ** stringspp,
-                                  unsigned char *inp, size_t *pcb_max,
-                                  char **chainpp, int flags)
+clientchar_t *
+smb_ParseStringBuf(const unsigned 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;
-        int    cb_dest;
         cm_space_t * spacep;
         int    null_terms = 0;
 
@@ -2483,7 +2865,7 @@ unsigned char *smb_ParseStringBuf(const unsigned char * bufbase,
                 null_terms = 1;
             }
         } else {
-            return NULL;
+            cch_src = 0;
         }
 
         spacep = cm_GetSpace();
@@ -2495,85 +2877,63 @@ unsigned char *smb_ParseStringBuf(const unsigned char * bufbase,
                 *chainpp = inp + sizeof(wchar_t);
             }
 
-            spacep->data[0] = '\0';
-            return spacep->data;
+            *(spacep->wdata) = 0;
+            return spacep->wdata;
         }
 
-        cb_dest = cm_NormalizeUtf16StringToUtf8((const wchar_t *) inp, cch_src,
-                                                spacep->data, sizeof(spacep->data));
-        if (cb_dest == 0) {
-            *stringspp = spacep->nextp;
-            cm_FreeSpace(spacep);
-#ifdef DEBUG_UNICODE
-            DebugBreak();
-#endif
-            return NULL;
-        }
+        StringCchCopyNW(spacep->wdata,
+                        lengthof(spacep->wdata),
+                        (const clientchar_t *) inp, cch_src);
 
         if (chainpp)
             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
 
-        if (cb_dest == 0) {
-#ifdef DEBUG_UNICODE
-            DebugBreak();
-#endif
-        } else if (spacep->data[cb_dest - 1] != 0) {
-            spacep->data[cb_dest++] = 0;
-        }
-
-        return spacep->data;
+        return spacep->wdata;
 
     } else {
 #endif
+        cm_space_t * spacep;
+        int cchdest;
+
         /* Not using Unicode */
-    if (chainpp) {
+        if (chainpp) {
             *chainpp = inp + strlen(inp) + 1;
-    }
-        if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
-            OemToChar(inp, inp);
-    return inp;
+        }
+
+        spacep = cm_GetSpace();
+        spacep->nextp = *stringspp;
+        *stringspp = spacep;
+
+        cchdest = lengthof(spacep->wdata);
+        cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
+                       spacep->wdata, cchdest);
+
+        return spacep->wdata;
 #ifdef SMB_UNICODE
     }
 #endif
 }
 
 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
-                                  unsigned char * str,
-                                  size_t * plen, int flags)
+                            clientchar_t * str,
+                            size_t * plen, int flags)
 {
     size_t buffersize;
     int align = 0;
 
     if (outp == NULL) {
         /* we are only calculating the required size */
-#ifdef SMB_UNICODE
 
-        if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
-            int nchars;
-
-            nchars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
-                                         str, -1, NULL, 0);
-            if (nchars == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+        if (plen == NULL)
+            return NULL;
 
-                if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
-                    nchars = MultiByteToWideChar(1252 /* ANSI - Latin1 */,
-                                                 0, str, -1, NULL, 0);
-                else
-                    nchars = MultiByteToWideChar(CP_OEMCP,
-                                                 0, str, -1, NULL, 0);
-            }
+#ifdef SMB_UNICODE
 
-            if (nchars == 0) {
-                osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
-                         osi_LogSaveString(smb_logp, str),
-                         GetLastError());
-                if (plen)
-                    *plen = 0;
-                return NULL;
-            }
+        if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
 
-            if (plen)
-                *plen = sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1 : nchars);
+            StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
+            if (!(flags & SMB_STRF_IGNORENUL))
+                *plen += sizeof(wchar_t);
 
             return (unsigned char *) 1; /* return TRUE if we are using unicode */
         }
@@ -2581,23 +2941,37 @@ unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
 #endif
         {
             /* Storing ANSI */
-            size_t len;
 
-            len = strlen(str);
+            size_t cch_str;
+            size_t cch_dest;
+
+            cch_str = cm_ClientStrLen(str);
+            cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
+
             if (plen)
-                *plen = ((flags & SMB_STRF_IGNORENULL)? len: len+1);
+                *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
 
             return NULL;
         }
+
+        /* Not reached. */
     }
 
-    /* Number of bytes left in the buffer. */
+    /* 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);
+        align = (int)((outp - pktp->data) % 2);
         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
     } else {
-        align = (((size_t) outp) % 2);
-        buffersize = sizeof(pktp->data);
+        align = (int)(((size_t) outp) % 2);
+        buffersize = (int)sizeof(pktp->data);
     }
 
 #ifdef SMB_UNICODE
@@ -2608,46 +2982,27 @@ unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
         if (align)
             *outp++ = '\0';
 
-        if (*str == '\0') {
+        if (*str == _C('\0')) {
 
             if (buffersize < sizeof(wchar_t))
                 return NULL;
 
             *((wchar_t *) outp) = L'\0';
-            if (plen && !(flags & SMB_STRF_IGNORENULL))
+            if (plen && !(flags & SMB_STRF_IGNORENUL))
                 *plen += sizeof(wchar_t);
             return outp + sizeof(wchar_t);
         }
 
-        nchars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
-                                     str, -1, (wchar_t *) outp, buffersize);
-        if (nchars == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
-
-            /* If we failed to translate the string from UTF-8 to
-               UTF-16, then chances are the string wasn't UTF-8 to
-               begin with.  If StoreAnsiFileNames is set and this is
-               possibly an ANSI file name, we try assuming that the
-               source name is in ANSI.  otherwise we try OEM. */
-
-            if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
-                nchars = MultiByteToWideChar(1252 /* ANSI - Latin1 */,
-                                             0, str, -1, (wchar_t *) outp, buffersize);
-            else
-                nchars = MultiByteToWideChar(CP_OEMCP,
-                                             0, str, -1, (wchar_t *) outp, buffersize);
-        }
-
+        nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
         if (nchars == 0) {
-            /* Both 1252 and OEM should translate to Unicode without a
-               complaint.  This is something else. */
             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
-                     osi_LogSaveString(smb_logp, str),
+                     osi_LogSaveClientString(smb_logp, str),
                      GetLastError());
             return NULL;
         }
 
         if (plen)
-            *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
+            *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
 
         return outp + sizeof(wchar_t) * nchars;
     }
@@ -2655,17 +3010,14 @@ unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
 #endif
     {
         /* Storing ANSI */
-        size_t len;
+        size_t cch_dest;
 
-        len = strlen(str); len++;
-        if (len > buffersize)
-            return NULL;
+        cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
 
-        strcpy(outp, str);
         if (plen)
-            *plen += ((flags & SMB_STRF_IGNORENULL)? len - 1: len);
+            *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
 
-        return outp + len;
+        return outp + cch_dest;
     }
 }
 
@@ -2760,7 +3112,7 @@ void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
         
     ncbp = inp->ncbp;
     if (ncbp == NULL) {
-        ncbp = GetNCB();
+        ncbp = smb_GetNCB();
         localNCB = 1;
     }
  
@@ -2800,7 +3152,7 @@ void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
     }
 
     if (localNCB)
-        FreeNCB(ncbp);
+        smb_FreeNCB(ncbp);
 }
 
 void smb_MapNTError(long code, unsigned long *NTStatusp)
@@ -2809,7 +3161,10 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
 
     /* map CM_ERROR_* errors to NT 32-bit status codes */
     /* NT Status codes are listed in ntstatus.h not winerror.h */
-    if (code == CM_ERROR_NOSUCHCELL) {
+    if (code == 0) {
+        NTStatus = 0;
+    } 
+    else if (code == CM_ERROR_NOSUCHCELL) {
         NTStatus = 0xC000000FL;        /* No such file */
     }
     else if (code == CM_ERROR_NOSUCHVOLUME) {
@@ -2874,7 +3229,7 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
 #endif /* COMMENT */
     }
     else if (code == CM_ERROR_BADSHARENAME) {
-        NTStatus = 0xC00000CCL;        /* Bad network name */
+        NTStatus = 0xC00000BEL;        /* Bad network path (server valid, share bad) */
     }
     else if (code == CM_ERROR_NOIPC) {
 #ifdef COMMENT
@@ -2905,7 +3260,7 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
         NTStatus = 0xC0000033L;        /* Object name invalid */
     }
     else if (code == CM_ERROR_WOULDBLOCK) {
-        NTStatus = 0xC0000055L;        /* Lock not granted */
+        NTStatus = 0xC00000D8L;        /* Can't wait */
     }
     else if (code == CM_ERROR_SHARING_VIOLATION) {
         NTStatus = 0xC0000043L; /* Sharing violation */
@@ -2945,7 +3300,7 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
         NTStatus = 0xC000022DL; /* Retry */
     } 
     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
-        NTStatus = 0xC00000BEL; /* Bad Network Path */
+        NTStatus = 0xC000003AL; /* Path not found */
     } 
     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
        NTStatus = 0xC0000322L; /* No Kerberos key */
@@ -2961,7 +3316,14 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     }
     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
         NTStatus = 0xC0000055L; /* Lock Not Granted */
-    } else {
+    }
+    else if (code == ENOMEM) {
+        NTStatus = 0xC0000017L; /* Out of Memory */
+    }
+    else if (code == CM_ERROR_RPC_MOREDATA) {
+       NTStatus = 0x80000005L; /* Buffer overflow */
+    }
+    else  {
         NTStatus = 0xC0982001L;        /* SMB non-specific error */
     }
 
@@ -2969,6 +3331,180 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
 }       
 
+/* 
+ * NTSTATUS <-> Win32 Error Translation 
+ * http://support.microsoft.com/kb/113996 
+ */
+void smb_MapWin32Error(long code, unsigned long *Win32Ep)
+{
+    unsigned long Win32E;
+
+    /* map CM_ERROR_* errors to Win32 32-bit error codes */
+    if (code == 0) {
+        Win32E = 0;
+    } 
+    else if (code == CM_ERROR_NOSUCHCELL) {
+        Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
+    }
+    else if (code == CM_ERROR_NOSUCHVOLUME) {
+        Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
+    }
+    else if (code == CM_ERROR_TIMEDOUT) {
+#ifdef COMMENT
+        Win32E = ERROR_SHARING_PAUSED; /* Sharing Paused */
+#else
+        Win32E = ERROR_UNEXP_NET_ERR;   /* Timeout */
+#endif
+    }
+    else if (code == CM_ERROR_RETRY) {
+        Win32E = ERROR_RETRY;          /* Retry */
+    }
+    else if (code == CM_ERROR_NOACCESS) {
+        Win32E = ERROR_ACCESS_DENIED;  /* Access denied */
+    }
+    else if (code == CM_ERROR_READONLY) {
+        Win32E = ERROR_WRITE_PROTECT;  /* Write protected */
+    }
+    else if (code == CM_ERROR_NOSUCHFILE ||
+             code == CM_ERROR_BPLUS_NOMATCH) {
+        Win32E = ERROR_FILE_NOT_FOUND; /* No such file */
+    }
+    else if (code == CM_ERROR_NOSUCHPATH) {
+        Win32E = ERROR_PATH_NOT_FOUND; /* Object path not found */
+    }          
+    else if (code == CM_ERROR_TOOBIG) {
+        Win32E = ERROR_BAD_EXE_FORMAT; /* Invalid image format */
+    }
+    else if (code == CM_ERROR_INVAL) {
+        Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
+    }
+    else if (code == CM_ERROR_BADFD) {
+        Win32E = ERROR_INVALID_HANDLE; /* Invalid handle */
+    }
+    else if (code == CM_ERROR_BADFDOP) {
+        Win32E = ERROR_ACCESS_DENIED;  /* Access denied */
+    }
+    else if (code == CM_ERROR_EXISTS) {
+        Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
+    }
+    else if (code == CM_ERROR_NOTEMPTY) {
+        Win32E = ERROR_DIR_NOT_EMPTY;  /* Directory not empty */
+    }  
+    else if (code == CM_ERROR_CROSSDEVLINK) {
+        Win32E = ERROR_NOT_SAME_DEVICE;        /* Not same device */
+    }
+    else if (code == CM_ERROR_NOTDIR) {
+        Win32E = ERROR_DIRECTORY;      /* Not a directory */
+    }
+    else if (code == CM_ERROR_ISDIR) {
+        Win32E = ERROR_ACCESS_DENIED;  /* File is a directory */
+    }
+    else if (code == CM_ERROR_BADOP) {
+        Win32E = ERROR_NOT_SUPPORTED;   /* Not supported */
+    }
+    else if (code == CM_ERROR_BADSHARENAME) {
+        Win32E = ERROR_BAD_NETPATH;    /* Bad network path (server valid, share bad) */
+    }
+    else if (code == CM_ERROR_NOIPC) {
+#ifdef COMMENT
+        Win32E = ERROR_ACCESS_DENIED;  /* Access Denied */
+#else   
+        Win32E = ERROR_REM_NOT_LIST;    /* Remote Resources */
+#endif
+    }
+    else if (code == CM_ERROR_CLOCKSKEW) {
+        Win32E = ERROR_TIME_SKEW;      /* Time difference at DC */
+    }
+    else if (code == CM_ERROR_BADTID) {
+        Win32E = ERROR_FILE_NOT_FOUND; /* SMB bad TID */
+    }
+    else if (code == CM_ERROR_USESTD) {
+        Win32E = ERROR_ACCESS_DENIED;  /* SMB use standard */
+    }
+    else if (code == CM_ERROR_QUOTA) {
+        Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
+    }
+    else if (code == CM_ERROR_SPACE) {
+        Win32E = ERROR_DISK_FULL;      /* Disk full */
+    }
+    else if (code == CM_ERROR_ATSYS) {
+        Win32E = ERROR_INVALID_NAME;   /* Object name invalid */
+    }
+    else if (code == CM_ERROR_BADNTFILENAME) {
+        Win32E = ERROR_INVALID_NAME;   /* Object name invalid */
+    }
+    else if (code == CM_ERROR_WOULDBLOCK) {
+        Win32E = WAIT_TIMEOUT;         /* Can't wait */
+    }
+    else if (code == CM_ERROR_SHARING_VIOLATION) {
+        Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
+    }
+    else if (code == CM_ERROR_LOCK_CONFLICT) {
+        Win32E = ERROR_LOCK_VIOLATION;   /* Lock conflict */
+    }
+    else if (code == CM_ERROR_PARTIALWRITE) {
+        Win32E = ERROR_DISK_FULL;      /* Disk full */
+    }
+    else if (code == CM_ERROR_BUFFERTOOSMALL) {
+        Win32E = ERROR_INSUFFICIENT_BUFFER;    /* Buffer too small */
+    }
+    else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
+        Win32E = ERROR_ALREADY_EXISTS; /* Object name collision */
+    }   
+    else if (code == CM_ERROR_BADPASSWORD) {
+        Win32E = ERROR_LOGON_FAILURE;   /* unknown username or bad password */
+    }
+    else if (code == CM_ERROR_BADLOGONTYPE) {
+        Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
+    }
+    else if (code == CM_ERROR_GSSCONTINUE) {
+        Win32E = ERROR_MORE_DATA;       /* more processing required */
+    }
+    else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
+#ifdef COMMENT
+        Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
+#else
+        Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
+#endif
+    }
+    else if (code == CM_ERROR_PATH_NOT_COVERED) {
+        Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
+    } 
+    else if (code == CM_ERROR_ALLBUSY) {
+        Win32E = ERROR_RETRY;           /* Retry */
+    } 
+    else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
+        Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
+    } 
+    else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
+       Win32E = SEC_E_NO_KERB_KEY;     /* No Kerberos key */
+    } 
+    else if (code == CM_ERROR_BAD_LEVEL) {
+       Win32E = ERROR_INVALID_LEVEL;   /* Invalid Level */
+    } 
+    else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
+       Win32E = ERROR_NOT_LOCKED;      /* Range Not Locked */
+    } 
+    else if (code == CM_ERROR_NOSUCHDEVICE) {
+        Win32E = ERROR_FILE_NOT_FOUND;  /* No Such Device */
+    }
+    else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
+        Win32E = ERROR_LOCK_VIOLATION;  /* Lock Not Granted */
+    }
+    else if (code == ENOMEM) {
+        Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
+    }
+    else if (code == CM_ERROR_RPC_MOREDATA) {
+       Win32E = ERROR_MORE_DATA;       /* Buffer overflow */
+    }
+    else  {
+        Win32E = ERROR_GEN_FAILURE;    /* SMB non-specific error */
+    }
+
+    *Win32Ep = Win32E;
+    osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
+}       
+
 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
                       unsigned char *classp)
 {
@@ -3219,13 +3755,20 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     if (!fidp)
         goto send1;
 
-    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+    lock_ObtainMutex(&fidp->mx);
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_BADFD;
+    }
+
+    if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         code = CM_ERROR_NOSUCHFILE;
         goto send1a;
     }
 
-
     pid = smbp->pid;
     {
         LARGE_INTEGER LOffset, LLength;
@@ -3243,6 +3786,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         lock_ReleaseWrite(&fidp->scp->rw);
     }    
     if (code) {
+        lock_ReleaseMutex(&fidp->mx);
         goto send1a;
     }
 
@@ -3253,13 +3797,13 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         smb_RawBufs = *(char **)smb_RawBufs;
     }
     lock_ReleaseMutex(&smb_RawBufLock);
-    if (!rawBuf)
+    if (!rawBuf) {
+        lock_ReleaseMutex(&fidp->mx);
         goto send1a;
+    }
 
-    lock_ObtainMutex(&fidp->mx);
     if (fidp->flags & SMB_FID_IOCTL)
     {
-       lock_ReleaseMutex(&fidp->mx);
         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
         if (rawBuf) {
             /* Give back raw buffer */
@@ -3487,7 +4031,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,
+                                  (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
             void * secBlob;
             int secBlobLength;
@@ -3549,7 +4095,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,
+                                  (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
         } else {
             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
             smb_SetSMBParm(outp, 12, 0); /* resvd */
@@ -3566,7 +4114,7 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 void smb_CheckVCs(void)
 {
     smb_vc_t * vcp, *nextp;
-    smb_packet_t * outp = GetPacket();
+    smb_packet_t * outp = smb_GetPacket();
     smb_t *smbp;
             
     lock_ObtainWrite(&smb_rctLock);
@@ -3576,14 +4124,24 @@ void smb_CheckVCs(void)
            osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
                       __FILE__, __LINE__);
 
+        /* on the first pass hold 'vcp' which was not held as 'nextp' */
+        if (vcp != nextp)
+            smb_HoldVCNoLock(vcp);
+
+        /* 
+         * obtain a reference to 'nextp' now because we drop the
+         * smb_rctLock later and the list contents could change 
+         * or 'vcp' could be destroyed when released.
+         */
        nextp = vcp->nextp;
+       if (nextp)
+           smb_HoldVCNoLock(nextp);
 
-       if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
+       if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
+            smb_ReleaseVCNoLock(vcp);
            continue;
+        }
 
-       smb_HoldVCNoLock(vcp);
-       if (nextp)
-           smb_HoldVCNoLock(nextp);
        smb_FormatResponsePacket(vcp, NULL, outp);
         smbp = (smb_t *)outp;
        outp->inCom = smbp->com = 0x2b /* Echo */;
@@ -3602,8 +4160,6 @@ void smb_CheckVCs(void)
 
        lock_ObtainWrite(&smb_rctLock);
        smb_ReleaseVCNoLock(vcp);
-       if (nextp)
-           smb_ReleaseVCNoLock(nextp);
     }
     lock_ReleaseWrite(&smb_rctLock);
     smb_FreePacket(outp);
@@ -3651,7 +4207,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);
@@ -3661,10 +4217,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;    
@@ -3769,7 +4325,7 @@ void smb_WaitingLocksDaemon()
                 scp = wlRequest->scp;
                osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
 
-                cm_InitReq(&req);
+                smb_InitReq(&req);
 
                 lock_ObtainWrite(&scp->rw);
 
@@ -3778,7 +4334,7 @@ void smb_WaitingLocksDaemon()
                 
                     if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
                         cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
-                                  wl->LLength, wl->key, NULL, &req);
+                                  wl->LLength, wl->key, 0, NULL, &req);
 
                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
 
@@ -3802,7 +4358,7 @@ void smb_WaitingLocksDaemon()
             vcp = wlRequest->vcp;
             inp = wlRequest->inp;
             outp = wlRequest->outp;
-            ncbp = GetNCB();
+            ncbp = smb_GetNCB();
             ncbp->ncb_length = inp->ncb_length;
             inp->spacep = cm_GetSpace();
 
@@ -3826,7 +4382,7 @@ void smb_WaitingLocksDaemon()
             smb_FreePacket(outp);
             smb_ReleaseVC(vcp);
             cm_ReleaseSCache(wlRequest->scp);
-            FreeNCB(ncbp);
+            smb_FreeNCB(ncbp);
             free(wlRequest);
         } while (nwlRequest && smbShutdownFlag == 0);
         thrd_Sleep(1000);
@@ -3852,22 +4408,27 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     smb_tid_t *tidp;
     smb_user_t *uidp;
     unsigned short newTid;
-    char shareName[AFSPATHMAX];
-    char *sharePath;
+    clientchar_t shareName[AFSPATHMAX];
+    clientchar_t *sharePath;
     int shareFound;
-    char *tp;
-    char *pathp;
+    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(inp, tp, &tp, SMB_STRF_ANSIPATH);
-    tp = strrchr(pathp, '\\');
+    {
+        char *tbp;
+        tbp = smb_GetSMBData(inp, NULL);
+        pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
+        if (!pathp)
+            return CM_ERROR_BADSMB;
+    }
+    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++;
@@ -3875,10 +4436,11 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
 
     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
+    if (!uidp)
+        return CM_ERROR_BADSMB;
     userp = smb_GetUserFromUID(uidp);
     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
-    if (uidp)
-        smb_ReleaseUID(uidp);
+    smb_ReleaseUID(uidp);
     if (!shareFound) {
         smb_ReleaseTID(tidp, FALSE);
         return CM_ERROR_BADSHARENAME;
@@ -3902,10 +4464,10 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
  * 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;
@@ -3918,7 +4480,7 @@ int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
     maskp[11] = '\0';
 
     /* find last backslash, or use whole thing if there is none */
-    tp = strrchr(pathp, '\\');
+    tp = cm_ClientStrRChr(pathp, '\\');
     if (!tp) 
         tp = pathp;
     else 
@@ -3963,17 +4525,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) 
@@ -3985,10 +4547,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 != ' ') 
@@ -4002,11 +4564,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 */
@@ -4020,9 +4582,9 @@ char *smb_FindMask(char *pathp)
    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[12];
+    clientchar_t mask[12];
     unsigned char *statBlockp;
     unsigned char initStatBlock[21];
     int statLen;
@@ -4031,10 +4593,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(inp, tp, (char **) &tp,
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp,
                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
-    osi_assertx(pathp != NULL, "null path");
-    statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
+    if (!pathp)
+        return CM_ERROR_BADSMB;
+    statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
     osi_assertx(statBlockp != NULL, "null statBlock");
     if (statLen == 0) {
         statBlockp = initStatBlock;
@@ -4091,8 +4654,8 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
 }       
 
 static long 
-smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
-                        char * tidPathp, char * relPathp,
+smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
+                        clientchar_t * tidPathp, clientchar_t * relPathp,
                         cm_user_t *userp, cm_req_t *reqp)
 {
     long code = 0;
@@ -4103,14 +4666,77 @@ smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
     char attr;
     smb_dirListPatch_t *patchp;
     smb_dirListPatch_t *npatchp;
-    char path[AFSPATHMAX];
+    clientchar_t path[AFSPATHMAX];
+    afs_uint32 rights;
+    afs_int32 mustFake = 0;
+
+    code = cm_FindACLCache(dscp, userp, &rights);
+    if (code == -1) {
+        lock_ObtainWrite(&dscp->rw);
+        code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
+                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+        lock_ReleaseWrite(&dscp->rw);
+        if (code == CM_ERROR_NOACCESS) {
+            mustFake = 1;
+            code = 0;
+        }
+    }
+    if (code)
+        goto cleanup;
+
+    if (!mustFake) {    /* Bulk Stat */
+        afs_uint32 count;
+        cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
+
+        memset(bsp, 0, sizeof(cm_bulkStat_t));
+
+        for (patchp = *dirPatchespp, count=0; 
+             patchp; 
+             patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
+            cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
+            int i;
+
+            if (tscp) {
+                if (lock_TryWrite(&tscp->rw)) {
+                    /* we have an entry that we can look at */
+                    if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
+                        /* we have a callback on it.  Don't bother
+                        * fetching this stat entry, since we're happy
+                        * with the info we have.
+                        */
+                        lock_ReleaseWrite(&tscp->rw);
+                        cm_ReleaseSCache(tscp);
+                        continue;
+                    }
+                    lock_ReleaseWrite(&tscp->rw);
+                } /* got lock */
+                cm_ReleaseSCache(tscp);
+            }  /* found entry */
+
+            i = bsp->counter++;
+            bsp->fids[i].Volume = patchp->fid.volume;
+            bsp->fids[i].Vnode = patchp->fid.vnode;
+            bsp->fids[i].Unique = patchp->fid.unique;
+
+            if (bsp->counter == AFSCBMAX) {
+                code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+                memset(bsp, 0, sizeof(cm_bulkStat_t));
+            }
+        }
+
+        if (bsp->counter > 0)
+            code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
+
+        free(bsp);
+    }
 
     for (patchp = *dirPatchespp; patchp; patchp =
          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
 
         dptr = patchp->dptr;
 
-        snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
+        cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
+                            relPathp ? relPathp : _C(""), patchp->dep->name);
         reqp->relPathp = path;
         reqp->tidPathp = tidPathp;
 
@@ -4123,42 +4749,79 @@ smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
             continue;
         }
         lock_ObtainWrite(&scp->rw);
-        code = cm_SyncOp(scp, NULL, userp, reqp, 0,
-                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
-        if (code) {    
+        if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
             lock_ReleaseWrite(&scp->rw);
-            cm_ReleaseSCache(scp);
-            if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
-                *dptr++ = SMB_ATTR_HIDDEN;
-            continue;
-        }
 
-       cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+            /* set the attribute */
+            switch (scp->fileType) {
+            case CM_SCACHETYPE_DIRECTORY:
+            case CM_SCACHETYPE_MOUNTPOINT:
+            case CM_SCACHETYPE_INVALID:
+                attr = SMB_ATTR_DIRECTORY;
+                break;
+            case CM_SCACHETYPE_SYMLINK:
+                if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
+                    attr = SMB_ATTR_DIRECTORY;
+                else
+                    attr = SMB_ATTR_NORMAL;
+                break;
+            default:
+                /* if we get here we either have a normal file
+                * or we have a file for which we have never 
+                * received status info.  In this case, we can
+                * check the even/odd value of the entry's vnode.
+                * odd means it is to be treated as a directory
+                * and even means it is to be treated as a file.
+                */
+                if (mustFake && (scp->fid.vnode & 0x1))
+                    attr = SMB_ATTR_DIRECTORY;
+                else
+                    attr = SMB_ATTR_NORMAL;
+            }
+            *dptr++ = attr;
+
+            /* 1969-12-31 23:59:58 +00*/
+            dosTime = 0xEBBFBF7D;
 
-        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)
-            attr |= SMB_ATTR_HIDDEN;
-        *dptr++ = attr;
+            /* copy out time */
+            shortTemp = (unsigned short) (dosTime & 0xffff);
+            *((u_short *)dptr) = shortTemp;
+            dptr += 2;
 
-        /* get dos time */
-        smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+            /* and copy out date */
+            shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
+            *((u_short *)dptr) = shortTemp;
+            dptr += 2;
                 
-        /* copy out time */
-        shortTemp = (unsigned short) (dosTime & 0xffff);
-        *((u_short *)dptr) = shortTemp;
-        dptr += 2;
-
-        /* and copy out date */
-        shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
-        *((u_short *)dptr) = shortTemp;
-        dptr += 2;
+            /* copy out file length */
+            *((u_long *)dptr) = 0;
+            dptr += 4;
+        } else {
+            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)
+                attr |= SMB_ATTR_HIDDEN;
+            *dptr++ = attr;
+
+            /* get dos time */
+            smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
+                
+            /* copy out time */
+            shortTemp = (unsigned short) (dosTime & 0xffff);
+            *((u_short *)dptr) = shortTemp;
+            dptr += 2;
+
+            /* and copy out date */
+            shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
+            *((u_short *)dptr) = shortTemp;
+            dptr += 2;
                 
-        /* copy out file length */
-        *((u_long *)dptr) = scp->length.LowPart;
-        dptr += 4;
-        lock_ReleaseRead(&scp->rw);
+            /* copy out file length */
+            *((u_long *)dptr) = scp->length.LowPart;
+            dptr += 4;
+            lock_ReleaseRead(&scp->rw);
+        }
         cm_ReleaseSCache(scp);
     }
         
@@ -4171,6 +4834,7 @@ smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
     /* and mark the list as empty */
     *dirPatchespp = NULL;
 
+  cleanup:
     return code;
 }
 
@@ -4179,9 +4843,9 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 {
     int attribute;
     long nextCookie;
-    char *tp;
+    unsigned char *tp;
     long code = 0;
-    char *pathp;
+    clientchar_t *pathp;
     cm_dirEntry_t *dep = 0;
     int maxCount;
     smb_dirListPatch_t *dirListPatchesp;
@@ -4202,10 +4866,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[12];
+    clientchar_t mask[12];
     int returnedNames;
     long nextEntryCookie;
     int numDirChunks;          /* # of 32 byte dir chunks in this entry */
@@ -4216,12 +4877,12 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     int starPattern;
     int rootPath = 0;
     int caseFold;
-    char *tidPathp = 0;
+    clientchar_t *tidPathp = 0;
     cm_req_t req;
     cm_fid_t fid;
     int fileType;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     maxCount = smb_GetSMBParm(inp, 0);
 
@@ -4232,12 +4893,12 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
-    inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
+    if (!pathp)
+        return CM_ERROR_BADSMB;
 
-    /* bail out if request looks bad */
-    if (!tp || !pathp) {
+    inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
+    if (!tp)
         return CM_ERROR_BADSMB;
-    }
 
     /* We can handle long names */
     if (vcp->flags & SMB_VCFLAG_USENT)
@@ -4254,8 +4915,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 */
@@ -4269,7 +4930,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         memcpy(dsp->mask, mask, 12);
 
         /* track if this is likely to match a lot of entries */
-        if (smb_IsStarMask(mask)) 
+        if (smb_Is8Dot3StarMask(mask)) 
             starPattern = 1;
         else 
             starPattern = 0;
@@ -4280,8 +4941,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;
@@ -4314,7 +4975,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         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);
@@ -4323,15 +4984,17 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             smb_ReleaseDirSearch(dsp);
             return CM_ERROR_NOFILES;
         }
-        strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
-        strcpy(dsp->relPath, spacep->data);
+        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->data,
+        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 = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
+                int pnc;
+
+                pnc  = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
                 cm_ReleaseSCache(scp);
                 lock_ReleaseMutex(&dsp->mx);
                 cm_ReleaseUser(userp);
@@ -4340,7 +5003,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
                     return CM_ERROR_PATH_NOT_COVERED;
                 else
-                    return CM_ERROR_BADSHARENAME;
+                    return CM_ERROR_NOSUCHPATH;
             }
 #endif /* DFS_SUPPORT */
 
@@ -4354,12 +5017,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
              */
             cm_HoldSCache(scp);
             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;
-            }
+            dsp->flags |= SMB_DIRSEARCH_BULKST;
             lock_ReleaseWrite(&scp->rw);
         }
     }
@@ -4404,6 +5062,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     code = 0;
     returnedNames = 0;
     while (1) {
+        clientchar_t *actualName = NULL;
+        int           free_actualName = 0;
+        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,
@@ -4452,31 +5115,16 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                 bufferp = NULL;
             }  
             lock_ReleaseWrite(&scp->rw);
-            code = buf_Get(scp, &thyper, &bufferp);
+            code = buf_Get(scp, &thyper, &req, &bufferp);
             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, 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 * 1000) {
-                        scp->bulkStatProgress = thyper;
-                        scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
-                        dsp->flags &= ~SMB_DIRSEARCH_BULKST;
-                       dsp->scp->bulkStatProgress = hzero;
-                    } else
-                        code = cm_TryBulkStat(scp, &thyper, userp, &req);
-                }
-            } else {
-                lock_ObtainWrite(&scp->rw);
-            }
+            if (starPattern)
+                smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
+
+            lock_ObtainWrite(&scp->rw);
             lock_ReleaseMutex(&dsp->mx);
             if (code) {
                 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
@@ -4558,15 +5206,27 @@ 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);
+            if (actualName)
+                free(actualName);
+            cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
             actualName = shortName;
+            free_actualName = 0;
+        } else {
+            free_actualName = 1;
         }
 
-        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));
+        if (actualName == NULL) {
+            /* Couldn't convert the name for some reason */
+            osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
+                     osi_LogSaveString(smb_logp, dep->name));
+            goto nextEntry;
+        }
+
+        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
@@ -4600,11 +5260,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,
@@ -4645,7 +5305,7 @@ 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
@@ -4662,6 +5322,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         }      /* if we're including this name */
 
       nextEntry:
+        if (free_actualName && actualName) {
+            free(actualName);
+            actualName = NULL;
+        }
+
         /* and adjust curOffset to be where the new cookie is */
         thyper.HighPart = 0;
         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
@@ -4678,7 +5343,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, dsp->tidPath, dsp->relPath, userp, &req);
+    smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
 
     /* special return code for unsuccessful search */
     if (code == 0 && dataLength < 21 && returnedNames == 0)
@@ -4707,8 +5372,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
      */
     temp -= 3;         /* deduct vbl block info */
     osi_assertx(temp == (43 * returnedNames), "unexpected data length");
-    origOp[1] = (char)(temp & 0xff);
-    origOp[2] = (char)((temp>>8) & 0xff);
+    origOp[1] = (unsigned char)(temp & 0xff);
+    origOp[2] = (unsigned char)((temp>>8) & 0xff);
     if (returnedNames == 0) 
         smb_DeleteDirSearch(dsp);
     smb_ReleaseDirSearch(dsp);
@@ -4725,24 +5390,25 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
  */
 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);
+    smb_InitReq(&req);
 
-    pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
+    pdata = smb_GetSMBData(inp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
-        return CM_ERROR_BADFD;
-    osi_Log1(smb_logp, "SMB receive check path %s",
-             osi_LogSaveString(smb_logp, pathp));
+        return CM_ERROR_BADSMB;
+    osi_Log1(smb_logp, "SMB receive check path %S",
+             osi_LogSaveClientString(smb_logp, pathp));
         
     rootScp = cm_data.rootSCachep;
         
@@ -4772,7 +5438,7 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -4806,7 +5472,7 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 /* 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;
@@ -4815,17 +5481,18 @@ 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);
+    smb_InitReq(&req);
 
     /* decode basic attributes we're passed */
     attribute = smb_GetSMBParm(inp, 0);
     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
 
-    pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
+    datap = smb_GetSMBData(inp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADSMB;
                
@@ -4859,7 +5526,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -4920,7 +5587,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 
 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;
@@ -4928,23 +5595,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);
+    smb_InitReq(&req);
 
-    pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
+    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 = "\\";
+        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;
         
@@ -4977,20 +5645,21 @@ 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) {
-                int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+                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;
+                    return CM_ERROR_NOSUCHPATH;
             } else
 #endif /* DFS_SUPPORT */
             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
@@ -5027,7 +5696,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -5044,21 +5713,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 
     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
-#ifdef undef
-    /* use smb_Attributes instead.   Also the fact that a file is 
-     * in a readonly volume doesn't mean it shojuld be marked as RO 
-     */
-    if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
-        newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
-       newScp->fileType == CM_SCACHETYPE_INVALID)
-        attrs = SMB_ATTR_DIRECTORY;
-    else
-        attrs = 0;
-    if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
-        attrs |= SMB_ATTR_READONLY;    /* turn on read-only flag */
-#else
     attrs = smb_Attributes(newScp);
-#endif
 
     smb_SetSMBParm(outp, 0, attrs);
         
@@ -5092,7 +5747,7 @@ 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);
     }
@@ -5104,8 +5759,8 @@ long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_
 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;
@@ -5114,15 +5769,18 @@ 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);
+    smb_InitReq(&req);
 
-    pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
-       
-    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);
+    if (!pathp)
+        return CM_ERROR_BADSMB;
+
+    osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
 
 #ifdef DEBUG_VERBOSE
     {
@@ -5134,12 +5792,27 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     }
 #endif
 
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
+#endif
+        return CM_ERROR_BADNTFILENAME;
+    }
+
     share = smb_GetSMBParm(inp, 0);
     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).
          */
@@ -5183,7 +5856,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -5207,17 +5880,6 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
     osi_assertx(fidp, "null smb_fid_t");
 
-    /* save a pointer to the vnode */
-    fidp->scp = scp;
-    osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
-    lock_ObtainWrite(&scp->rw);
-    scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseWrite(&scp->rw);
-
-    /* and the user */
-    cm_HoldUser(userp);
-    fidp->userp = userp;
-
     lock_ObtainMutex(&fidp->mx);
     if ((share & 0xf) == 0)
         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
@@ -5225,9 +5887,17 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         fidp->flags |= SMB_FID_OPENWRITE;
     else 
         fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
-    lock_ReleaseMutex(&fidp->mx);
 
-    lock_ObtainRead(&scp->rw);
+    /* save the  user */
+    cm_HoldUser(userp);
+    fidp->userp = userp;
+
+    /* and a pointer to the vnode */
+    fidp->scp = scp;
+    osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
+    lock_ObtainWrite(&scp->rw);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
     smb_SetSMBParm(outp, 0, fidp->fid);
     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
@@ -5238,6 +5908,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(&fidp->mx);
     lock_ReleaseRead(&scp->rw);
         
     /* notify open */
@@ -5255,7 +5926,7 @@ 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;
@@ -5267,8 +5938,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;
 
@@ -5276,26 +5946,31 @@ 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);
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        /* Can't convert name */
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
+
+    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, "Found match %s",
-                 osi_LogSaveString(smb_logp, matchName));
+        osi_Log1(smb_logp, "Found match %S",
+                 osi_LogSaveClientString(smb_logp, matchName));
 
         cm_DirEntryListAdd(dep->name, &rockp->matches);
 
         rockp->any = 1;
 
         /* If we made a case sensitive exact match, we might as well quit now. */
-        if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
+        if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
             code = CM_ERROR_STOPNOW;
         else
             code = 0;
@@ -5310,30 +5985,33 @@ 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);
+    smb_InitReq(&req);
+    memset(&rock, 0, sizeof(rock));
 
     attribute = smb_GetSMBParm(inp, 0);
         
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    if (!pathp)
+        return CM_ERROR_BADSMB;
 
-    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);
 
@@ -5344,7 +6022,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);
@@ -5353,13 +6031,13 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         
 #ifdef DFS_SUPPORT
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,spacep->data);
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -5370,8 +6048,12 @@ 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);
+    if (!rock.maskp) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
+    }
+    rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
 
     thyper.LowPart = 0;
     thyper.HighPart = 0;
@@ -5404,39 +6086,55 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         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));
-            code = cm_Unlink(dscp, entry->name, userp, &req);
+
+            /* We assume this works because entry->name was
+               successfully converted in smb_UnlinkProc() once. */
+            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, entry->name, NULL, TRUE);
+                                 dscp, normalizedName, NULL, TRUE);
         }
     }
 
     cm_DirEntryListFree(&rock.matches);
 
+  done:
+    if (userp)
     cm_ReleaseUser(userp);
         
+    if (dscp)
     cm_ReleaseSCache(dscp);
 
+    if (rock.maskp)
+    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 */
-    char oldName[MAX_PATH];
+    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;
 
@@ -5446,27 +6144,35 @@ 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;
 
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        /* Can't convert string */
+        osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
+
     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;
-        strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
-        rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
-            code = CM_ERROR_STOPNOW;
+        StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
+        cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
+                        matchName);
+        code = CM_ERROR_STOPNOW;
     } else {
        code = 0;
     }
@@ -5476,7 +6182,7 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
 
 
 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;
@@ -5485,12 +6191,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;
 
@@ -5501,12 +6207,14 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
         return CM_ERROR_NOSUCHPATH;
     }
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
+    memset(&rock, 0, sizeof(rock));
+
     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);
@@ -5515,18 +6223,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->data);
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
         cm_ReleaseSCache(oldDscp);
         cm_ReleaseUser(userp);
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #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) {
@@ -5537,14 +6245,14 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
 
 #ifdef DFS_SUPPORT
     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
-        int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
+        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) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -5567,30 +6275,18 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
 
     /* TODO: The old name could be a wildcard.  The new name must not be */
 
-    /* do the vnode call */
-    rock.odscp = oldDscp;
-    rock.ndscp = newDscp;
-    rock.userp = userp;
-    rock.reqp = &req;
-    rock.vcp = vcp;
-    rock.maskp = oldLastNamep;
-    rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
-    rock.newNamep = newLastNamep;
-    rock.oldName[0] = '\0';
-    rock.any = 0;
-
     /* Check if the file already exists; if so return error */
     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
     {
-        osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
-                 osi_LogSaveString(smb_logp, newLastNamep));
+        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);
@@ -5609,14 +6305,25 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
             osi_Log0(smb_logp, "Can't rename.  Target already exists");
             code = CM_ERROR_EXISTS;
         }
+        goto done;
+    }
 
-        if (tmpscp != NULL)
-            cm_ReleaseSCache(tmpscp);
-        cm_ReleaseSCache(newDscp);
-        cm_ReleaseSCache(oldDscp);
-        cm_ReleaseUser(userp);
-        return code; 
+    /* do the vnode call */
+    rock.odscp = oldDscp;
+    rock.ndscp = newDscp;
+    rock.userp = userp;
+    rock.reqp = &req;
+    rock.vcp = vcp;
+    rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
+    if (!rock.maskp) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
     }
+    rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
+    rock.newNamep = newLastNamep;
+    rock.fsOldName[0] = '\0';
+    rock.clOldName[0] = '\0';
+    rock.any = 0;
 
     /* Now search the directory for the pattern, and do the appropriate rename when found */
     thyper.LowPart = 0;                /* search dir from here */
@@ -5631,13 +6338,15 @@ 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 && rock.oldName[0] != '\0') {
-       code = cm_Rename(rock.odscp, rock.oldName,
+    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);   
+                         rock.reqp);
         /* if the call worked, stop doing the search now, since we
          * really only want to rename one file.
          */
+    if (code)
+        osi_Log0(smb_logp, "cm_Rename failure");
        osi_Log1(smb_logp, "cm_Rename returns %ld", code);
     } else if (code == 0) {
         code = CM_ERROR_NOSUCHFILE;
@@ -5653,30 +6362,37 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
         if (oldDscp == newDscp) {
             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
-                                  filter, oldDscp, oldLastNamep,
-                                  newLastNamep, TRUE);
+                                 filter, oldDscp, rock.clOldName,
+                                 newLastNamep, TRUE);
         } else {
             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
-                                  filter, oldDscp, oldLastNamep,
+                                  filter, oldDscp, rock.clOldName,
                                   NULL, TRUE);
             if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
                 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
-                                  filter, newDscp, newLastNamep,
-                                  NULL, TRUE);
+                                 filter, newDscp, newLastNamep,
+                                 NULL, TRUE);
         }
     }
 
+  done:
     if (tmpscp != NULL) 
         cm_ReleaseSCache(tmpscp);
-    cm_ReleaseUser(userp);
-    cm_ReleaseSCache(oldDscp);
-    cm_ReleaseSCache(newDscp);
+    if (userp)
+        cm_ReleaseUser(userp);
+    if (oldDscp)
+        cm_ReleaseSCache(oldDscp);
+    if (newDscp)
+        cm_ReleaseSCache(newDscp);
+    if (rock.maskp)
+        free(rock.maskp);
+
     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;
@@ -5685,11 +6401,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;
 
@@ -5701,14 +6417,14 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
         return CM_ERROR_NOSUCHPATH;
     }
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     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);
@@ -5717,18 +6433,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->data);
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
         cm_ReleaseSCache(oldDscp);
         cm_ReleaseUser(userp);
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #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);
@@ -5738,14 +6454,14 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
 
 #ifdef DFS_SUPPORT
     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
-        int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
+        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) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -5772,7 +6488,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);
@@ -5786,8 +6502,8 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) && 
         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) 
     {
-        osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
-                 osi_LogSaveString(smb_logp, newLastNamep));
+        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) {
@@ -5809,7 +6525,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);
 
@@ -5835,18 +6551,37 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
 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(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    if (!oldPathp)
+        return CM_ERROR_BADSMB;
     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    if (!newPathp)
+        return CM_ERROR_BADSMB;
+
+    osi_Log2(smb_logp, "smb rename [%S] to [%S]",
+             osi_LogSaveClientString(smb_logp, oldPathp),
+             osi_LogSaveClientString(smb_logp, newPathp));
 
-    osi_Log2(smb_logp, "smb rename [%s] to [%s]",
-             osi_LogSaveString(smb_logp, oldPathp),
-             osi_LogSaveString(smb_logp, newPathp));
+    if (!cm_IsValidClientString(newPathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(newPathp, -1);
+        osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "CoreRename rejecting invalid name");
+#endif
+        return CM_ERROR_BADNTFILENAME;
+    }
 
     code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
 
@@ -5860,7 +6595,7 @@ 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;
@@ -5871,26 +6606,29 @@ 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;
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
+
     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) {
-            rockp->any = 1;
+        rockp->any = 1;
         cm_DirEntryListAdd(dep->name, &rockp->matches);
     }
 
@@ -5901,25 +6639,28 @@ int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper
 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);
+    smb_InitReq(&req);
+    memset(&rock, 0, sizeof(rock));
 
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    if (!pathp)
+        return CM_ERROR_BADSMB;
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
     userp = smb_GetUserFromVCP(vcp, inp);
 
@@ -5930,7 +6671,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) {
@@ -5940,13 +6681,13 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         
 #ifdef DFS_SUPPORT
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -5957,8 +6698,12 @@ 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);
+    if (!rock.maskp) {
+        code = CM_ERROR_NOSUCHFILE;
+        goto done;
+    }
+    rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
 
     thyper.LowPart = 0;
     thyper.HighPart = 0;
@@ -5980,26 +6725,40 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         cm_dirEntryList_t * entry;
 
         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
+            clientchar_t clientName[MAX_PATH];
+
+            /* We assume this will succeed because smb_RmdirProc()
+               successfully converted entry->name once above. */
+            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, userp, &req);
+            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, entry->name, NULL, TRUE);
+                                 dscp, clientName, NULL, TRUE);
         }
     }
 
+  done:
+    if (rock.matches)
     cm_DirEntryListFree(&rock.matches);
 
+    if (userp)
     cm_ReleaseUser(userp);
         
+    if (dscp)
     cm_ReleaseSCache(dscp);
 
     if (code == 0 && !rock.any)
         code = CM_ERROR_NOSUCHFILE;        
+
+    if (rock.maskp)
+    free(rock.maskp);
+
     return code;
 }
 
@@ -6012,7 +6771,7 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     long code = 0;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     fid = smb_GetSMBParm(inp, 0);
 
@@ -6021,88 +6780,103 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     fid = smb_ChainFID(fid, inp);
     fidp = smb_FindFID(vcp, fid, 0);
     if (!fidp)
-       return CM_ERROR_BADFD;
+        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;
-    }
+    userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
-    if (fidp->flags & SMB_FID_IOCTL) {
-       lock_ReleaseMutex(&fidp->mx);
-       smb_ReleaseFID(fidp);
+    if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
+        cm_ReleaseUser(userp);
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
         return CM_ERROR_BADFD;
     }
-    lock_ReleaseMutex(&fidp->mx);
-        
-    userp = smb_GetUserFromVCP(vcp, inp);
 
-    lock_ObtainMutex(&fidp->mx);
+    if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
+        lock_ReleaseMutex(&fidp->mx);
+        cm_ReleaseUser(userp);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
-       cm_scache_t * scp = fidp->scp;
-       cm_HoldSCache(scp);
-       lock_ReleaseMutex(&fidp->mx);
+        cm_scache_t * scp = fidp->scp;
+        cm_HoldSCache(scp);
+        lock_ReleaseMutex(&fidp->mx);
         code = cm_FSync(scp, userp, &req);
-       cm_ReleaseSCache(scp);
+        cm_ReleaseSCache(scp);
     } else {
+        lock_ReleaseMutex(&fidp->mx);
         code = 0;
-       lock_ReleaseMutex(&fidp->mx);
     }
         
-    smb_ReleaseFID(fidp);
-        
     cm_ReleaseUser(userp);
-        
+    smb_ReleaseFID(fidp);                
     return code;
 }
 
 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)) {
+    if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
+        osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
+                 osi_LogSaveString(smb_logp, dep->name));
+        return 0;
+    }
+
+    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,
@@ -6110,10 +6884,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;
     cm_scache_t *delscp = NULL;
-    int deleted = 0;
     int nullcreator = 0;
 
     osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
@@ -6121,7 +6894,8 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
     if (!userp) {
        lock_ObtainMutex(&fidp->mx);
-        if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
+        if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
+                                            SMB_FID_RPC))) {
            lock_ReleaseMutex(&fidp->mx);
             osi_Log0(smb_logp, "  No user specified.  Not closing fid");
            return CM_ERROR_BADFD;
@@ -6132,30 +6906,29 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
        lock_ReleaseMutex(&fidp->mx);
     }
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     lock_ObtainWrite(&smb_rctLock);
-    if (fidp->delete) {
-       osi_Log0(smb_logp, "  Fid already closed.");
-       lock_ReleaseWrite(&smb_rctLock);
-       return CM_ERROR_BADFD;
+    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);
     if (fidp->NTopen_dscp) {
-       dscp = fidp->NTopen_dscp;
-       cm_HoldSCache(dscp);
+        dscp = fidp->NTopen_dscp;   
+        cm_HoldSCache(dscp);
     }
 
-    if (fidp->NTopen_pathp) {
-       pathp = strdup(fidp->NTopen_pathp);
-    }
+    if (fidp->NTopen_pathp)
+        pathp = cm_ClientStrDup(fidp->NTopen_pathp);
 
     if (fidp->scp) {
-       scp = fidp->scp;
-       cm_HoldSCache(scp);
+        scp = fidp->scp;
+        cm_HoldSCache(scp);
     }
 
     /* Don't jump the gun on an async raw write */
@@ -6173,7 +6946,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
             scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
             /* This fixes defect 10958 */
             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
-            smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
+            smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
         }
         if (smb_AsyncStore != 2) {
             lock_ReleaseMutex(&fidp->mx);
@@ -6190,10 +6963,10 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
         cm_key_t key;
         long tcode;
 
-       lock_ReleaseMutex(&fidp->mx);
+        lock_ReleaseMutex(&fidp->mx);
 
-       /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
-           in zero. */
+        /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
+              * in zero. */
         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
         lock_ObtainWrite(&scp->rw);
 
@@ -6219,7 +6992,8 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     }
 
     if (fidp->flags & SMB_FID_DELONCLOSE) {
-        char *fullPathp;
+        clientchar_t *fullPathp = NULL;
+        fschar_t *originalNamep = NULL;
 
        lock_ReleaseMutex(&fidp->mx);
 
@@ -6228,27 +7002,30 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
             cm_HoldSCache(scp);
             delscp = scp;
         }
-        smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
+        smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
         if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
-            code = cm_RemoveDir(dscp, fullPathp, userp, &req);
+            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;
     }
@@ -6286,26 +7063,20 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
        cm_ReleaseSCache(dscp);
 
     if (delscp) {
-       if (deleted) {
-           lock_ObtainWrite(&delscp->rw);
-           if (deleted)
-               delscp->flags |= CM_SCACHEFLAG_DELETED;
-           lock_ReleaseWrite(&delscp->rw);
-       }
         cm_ReleaseSCache(delscp);
     }
 
     if (scp) {
-       lock_ObtainWrite(&scp->rw);
+        lock_ObtainWrite(&scp->rw);
         if (nullcreator && scp->creator == userp)
             scp->creator = NULL;
-       scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
-       lock_ReleaseWrite(&scp->rw);
-       cm_ReleaseSCache(scp);
+        scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
+        lock_ReleaseWrite(&scp->rw);
+        cm_ReleaseSCache(scp);
     }
 
     if (pathp)
-       free(pathp);
+        free(pathp);
 
     return code;
 }
@@ -6373,8 +7144,14 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
         code = CM_ERROR_BADFDOP;
         goto done2;
     }
-    
-    cm_InitReq(&req);
+
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        code = CM_ERROR_BADFD;
+        goto done2;
+    }
+       
+    smb_InitReq(&req);
 
     bufferp = NULL;
     offset = *offsetp;
@@ -6443,7 +7220,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
             }
             lock_ReleaseWrite(&scp->rw);
 
-            code = buf_Get(scp, &thyper, &bufferp);
+            code = buf_Get(scp, &thyper, &req, &bufferp);
 
             lock_ObtainWrite(&scp->rw);
             if (code) goto done;
@@ -6545,7 +7322,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
         goto done2;
     }
     
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     scp = fidp->scp;
     cm_HoldSCache(scp);
@@ -6628,7 +7405,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
             }  
             lock_ReleaseWrite(&scp->rw);
 
-            code = buf_Get(scp, &thyper, &bufferp);
+            code = buf_Get(scp, &thyper, &req, &bufferp);
 
             lock_ObtainMutex(&bufferp->mx);
             lock_ObtainWrite(&scp->rw);
@@ -6707,15 +7484,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
 
         /* now copy the data */
        memcpy(bufferp->datap + bufIndex, op, nbytes);
-        buf_SetDirty(bufferp, bufIndex, nbytes);
-
-        /* and record the last writer */
-        if (bufferp->userp != userp) {
-            cm_HoldUser(userp);
-            if (bufferp->userp) 
-                cm_ReleaseUser(bufferp->userp);
-            bufferp->userp = userp;
-        }
+        buf_SetDirty(bufferp, bufIndex, nbytes, userp);
 
         /* adjust counters, pointers, etc. */
         op += nbytes;
@@ -6736,12 +7505,15 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char
 
     lock_ObtainMutex(&fidp->mx);
     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
-         && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
+         && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) 
+    {
+        lock_ReleaseMutex(&fidp->mx);
         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
                           fidp->NTopen_dscp, fidp->NTopen_pathp,
                           NULL, TRUE);
-    }       
-    lock_ReleaseMutex(&fidp->mx);
+    } else {
+        lock_ReleaseMutex(&fidp->mx);
+    }
 
     if (code == 0) {
         if (smb_AsyncStore > 0) {
@@ -6786,6 +7558,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_t* smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
+       cm_scache_t *scp;
     cm_attr_t truncAttr;       /* attribute struct used for truncating file */
     char *op;
     int inDataBlockCount;
@@ -6809,12 +7582,6 @@ 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);
@@ -6823,6 +7590,30 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
        return code;
     }
+
+    if (fidp->flags & SMB_FID_RPC) {
+       lock_ReleaseMutex(&fidp->mx);
+        code = smb_RPCWrite(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
+       return code;
+    }
+
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_BADFD;
+    }
+
+    if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
+    scp = fidp->scp;
+    cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
     userp = smb_GetUserFromVCP(vcp, inp);
 
@@ -6839,9 +7630,9 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainWrite(&fidp->scp->rw);
-        code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseWrite(&fidp->scp->rw);
+        lock_ObtainWrite(&scp->rw);
+        code = cm_LockCheckWrite(scp, LOffset, LLength, key);
+        lock_ReleaseWrite(&scp->rw);
 
         if (code) {
            osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
@@ -6855,7 +7646,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
        osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
         
-        cm_InitReq(&req);
+        smb_InitReq(&req);
 
         truncAttr.mask = CM_ATTRMASK_LENGTH;
         truncAttr.length.LowPart = offset.LowPart;
@@ -6913,6 +7704,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
   done:
     smb_ReleaseFID(fidp);
     cm_ReleaseUser(userp);
+       cm_ReleaseSCache(scp);
 
     return code;
 }
@@ -6930,12 +7722,21 @@ 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)) {
+    lock_ObtainMutex(&fidp->mx);
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
+        return;
+    }
+
+    if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return;
     }
-
+    lock_ReleaseMutex(&fidp->mx);
+       
     osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
              rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
 
@@ -6989,6 +7790,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
+       cm_scache_t *scp;
     char *op;
     unsigned short writeMode;
     char *rawBuf;
@@ -7036,16 +7838,27 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         
     fd = smb_ChainFID(fd, inp);
     fidp = smb_FindFID(vcp, fd, 0);
-    if (!fidp) {
+    if (!fidp)
+        return CM_ERROR_BADFD;
+
+    lock_ObtainMutex(&fidp->mx);
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
         return CM_ERROR_BADFD;
     }
 
-    if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
+    if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
+        lock_ReleaseMutex(&fidp->mx);
         smb_CloseFID(vcp, fidp, NULL, 0);
         smb_ReleaseFID(fidp);
         return CM_ERROR_NOSUCHFILE;
     }
 
+    scp = fidp->scp;
+    cm_HoldSCache(scp);
+    lock_ReleaseMutex(&fidp->mx);
+
     {
         unsigned pid;
         cm_key_t key;
@@ -7060,11 +7873,12 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainWrite(&fidp->scp->rw);
-        code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseWrite(&fidp->scp->rw);
+        lock_ObtainWrite(&scp->rw);
+        code = cm_LockCheckWrite(scp, LOffset, LLength, key);
+        lock_ReleaseWrite(&scp->rw);
 
         if (code) {
+            cm_ReleaseSCache(scp);
             smb_ReleaseFID(fidp);
             return code;
         }
@@ -7128,6 +7942,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
 
     smb_ReleaseFID(fidp);
     cm_ReleaseUser(userp);
+    cm_ReleaseSCache(scp);
 
     if (code) {
         smb_SetSMBParm(outp, 0, total_written);
@@ -7168,6 +7983,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
+    cm_scache_t *scp;
     char *op;
         
     fd = smb_GetSMBParm(inp, 0);
@@ -7182,12 +7998,6 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     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) {
@@ -7196,6 +8006,29 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        smb_ReleaseFID(fidp);
        return code;
     }
+
+    if (fidp->flags & SMB_FID_RPC) {
+       lock_ReleaseMutex(&fidp->mx);
+        code = smb_RPCRead(fidp, vcp, inp, outp);
+       smb_ReleaseFID(fidp);
+       return code;
+    }
+
+    if (!fidp->scp) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_BADFD;
+    }
+
+    if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
+    scp = fidp->scp;
+    cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
 
     {
@@ -7210,11 +8043,12 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
         
-        lock_ObtainWrite(&fidp->scp->rw);
-        code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseWrite(&fidp->scp->rw);
+        lock_ObtainWrite(&scp->rw);
+        code = cm_LockCheckRead(scp, LOffset, LLength, key);
+        lock_ReleaseWrite(&scp->rw);
     }
     if (code) {
+        cm_ReleaseSCache(scp);
         smb_ReleaseFID(fidp);
         return code;
     }
@@ -7252,27 +8086,28 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_ReleaseFID(fidp);
        
     cm_ReleaseUser(userp);
+    cm_ReleaseSCache(scp);
     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);
+    smb_InitReq(&req);
 
     scp = NULL;
         
@@ -7281,12 +8116,14 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
-
-    if (strcmp(pathp, "\\") == 0)
-        return CM_ERROR_EXISTS;
+    if (!pathp)
+        return CM_ERROR_BADSMB;
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
+
+    if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
+        return CM_ERROR_EXISTS;
 
     userp = smb_GetUserFromVCP(vcp, inp);
 
@@ -7298,7 +8135,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);
 
@@ -7309,13 +8146,13 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         
 #ifdef DFS_SUPPORT
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -7337,7 +8174,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         
     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
     setAttr.clientModTime = time(NULL);
-    code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
+    code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
         smb_NotifyChange(FILE_ACTION_ADDED,
                          FILE_NOTIFY_CHANGE_DIR_NAME,
@@ -7359,7 +8196,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
@@ -7367,19 +8204,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 */
@@ -7388,14 +8225,14 @@ 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 */
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
 
     scp = NULL;
     excl = (inp->inCom == 0x03)? 0 : 1;
@@ -7410,9 +8247,26 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         
     tp = smb_GetSMBData(inp, NULL);
     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    if (!pathp)
+        return CM_ERROR_BADSMB;
+
+    if (!cm_IsValidClientString(pathp)) {
+#ifdef DEBUG
+        clientchar_t * hexp;
+
+        hexp = cm_GetRawCharsAlloc(pathp, -1);
+        osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
+                 osi_LogSaveClientString(smb_logp, hexp));
+        if (hexp)
+            free(hexp);
+#else
+        osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
+#endif
+        return CM_ERROR_BADNTFILENAME;
+    }
 
     spacep = inp->spacep;
-    smb_StripLastComponent(spacep->data, &lastNamep, pathp);
+    smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
 
     userp = smb_GetUserFromVCP(vcp, inp);
 
@@ -7423,7 +8277,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) {
@@ -7433,13 +8287,13 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         
 #ifdef DFS_SUPPORT
     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
-        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
+        int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
         cm_ReleaseSCache(dscp);
         cm_ReleaseUser(userp);
         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
             return CM_ERROR_PATH_NOT_COVERED;
         else
-            return CM_ERROR_BADSHARENAME;
+            return CM_ERROR_NOSUCHPATH;
     }
 #endif /* DFS_SUPPORT */
 
@@ -7454,7 +8308,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;
@@ -7584,7 +8438,7 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_user_t *userp;
     cm_req_t req;
 
-    cm_InitReq(&req);
+    smb_InitReq(&req);
         
     fd = smb_GetSMBParm(inp, 0);
     whence = smb_GetSMBParm(inp, 1);
@@ -7595,21 +8449,23 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     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) {
+    if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
        lock_ReleaseMutex(&fidp->mx);
        smb_ReleaseFID(fidp);
         return CM_ERROR_BADFD;
     }
+
+    if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
+        lock_ReleaseMutex(&fidp->mx);
+        smb_CloseFID(vcp, fidp, NULL, 0);
+        smb_ReleaseFID(fidp);
+        return CM_ERROR_NOSUCHFILE;
+    }
+
     lock_ReleaseMutex(&fidp->mx);
-       
+
     userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
@@ -7741,25 +8597,70 @@ 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);
+            smb_t *smbp;
 
-            if (inp->inCom == 0x1d)
+            smbp = (smb_t *) inp;
+
+            osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
+                      opName, smbp->mid, vcp,vcp->lana,vcp->lsn);
+            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",
-                         opName,vcp,vcp->lana,vcp->lsn);
+            } else {
                 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);
-#ifdef LOG_PACKET
-                if ( code == CM_ERROR_BADSMB ||
-                     code == CM_ERROR_BADOP )
-                     smb_LogPacket(inp);
-#endif /* LOG_PACKET */
             }   
+            osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
+                      code, smbp->mid, vcp,vcp->lana,vcp->lsn);
 
             newTime = GetTickCount();
-            osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
+            osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms", 
+                     opName, smbp->mid, newTime - oldTime);
+
+#ifdef LOG_PACKET
+            if ( code == CM_ERROR_BADSMB ||
+                 code == CM_ERROR_BADOP )
+                smb_LogPacket(inp);
+#endif /* LOG_PACKET */
+
+            /* ReceiveV3Tran2A handles its own logging */
+            if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
+                smb_user_t *uidp;
+                smb_fid_t *fidp;
+                clientchar_t *treepath = NULL;  /* do not free */
+                clientchar_t *pathname = NULL;
+                cm_fid_t afid = {0,0,0,0,0};
+
+                uidp = smb_FindUID(vcp, smbp->uid, 0);
+                smb_LookupTIDPath(vcp, smbp->tid, &treepath);
+                fidp = smb_FindFID(vcp, inp->fid, 0);
+
+                if (fidp) {
+                    lock_ObtainMutex(&fidp->mx);
+                    if (fidp->NTopen_pathp)
+                        pathname = fidp->NTopen_pathp;
+                    if (fidp->scp)
+                        afid = fidp->scp->fid;
+                } else {
+                    if (inp->stringsp->wdata)
+                        pathname = inp->stringsp->wdata;
+                }
+
+                afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)", 
+                          opName, newTime - oldTime, 
+                          smbp->uid, uidp ? uidp->unp->name : NULL,
+                          smbp->pid, smbp->mid, smbp->tid,
+                          treepath,
+                          pathname, 
+                          afid.cell, afid.volume, afid.vnode, afid.unique);
+
+                if (fidp)
+                    lock_ReleaseMutex(&fidp->mx);
+
+                if (uidp)
+                    smb_ReleaseUID(uidp);
+                if (fidp)
+                    smb_ReleaseFID(fidp);
+            }
 
             if (oldGen != sessionGen) {
                LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION, 
@@ -8084,11 +8985,12 @@ void smb_Server(VOID *parmp)
     UCHAR rc;
     smb_vc_t *vcp = NULL;
     smb_t *smbp;
+    extern void rx_StartClientThread(void);
 
     rx_StartClientThread();
 
-    outncbp = GetNCB();
-    outbufp = GetPacket();
+    outncbp = smb_GetNCB();
+    outbufp = smb_GetPacket();
     outbufp->ncbp = outncbp;
 
     while (1) {
@@ -8178,12 +9080,12 @@ void smb_Server(VOID *parmp)
                    lock_ObtainWrite(&smb_globalLock);
                    dead_sessions[vcp->session] = TRUE;
                    lock_ReleaseWrite(&smb_globalLock);
-                   smb_CleanupDeadVC(vcp);
-                   smb_ReleaseVC(vcp);
-                   vcp = NULL;
                 } else {
                    lock_ReleaseMutex(&vcp->mx);
                }
+                smb_CleanupDeadVC(vcp);
+                smb_ReleaseVC(vcp);
+                vcp = NULL;
             }
             goto doneWithNCB;
 
@@ -8210,31 +9112,33 @@ void smb_Server(VOID *parmp)
         default:
             /* A weird error code.  Log it, sleep, and continue. */
             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
-           if (vcp) 
+           if (vcp) {
                lock_ObtainMutex(&vcp->mx);
-            if (vcp && vcp->errorCount++ > 3) {
-                osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
-               if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
-                   osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
-                            vcp, vcp->usersp);
-                   vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
-                   lock_ReleaseMutex(&vcp->mx);
-                   lock_ObtainWrite(&smb_globalLock);
-                   dead_sessions[vcp->session] = TRUE;
-                   lock_ReleaseWrite(&smb_globalLock);
-                   smb_CleanupDeadVC(vcp);
-                   smb_ReleaseVC(vcp);
-                   vcp = NULL;
-               } else {
-                   lock_ReleaseMutex(&vcp->mx);
-               }
-               goto doneWithNCB;
-            }
-            else {
-               if (vcp)
+                if (vcp->errorCount++ > 3) {
+                    osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
+                    if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
+                        osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
+                                 vcp, vcp->usersp);
+                        vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
+                        lock_ReleaseMutex(&vcp->mx);
+                        lock_ObtainWrite(&smb_globalLock);
+                        dead_sessions[vcp->session] = TRUE;
+                        lock_ReleaseWrite(&smb_globalLock);
+                    } else {
+                        lock_ReleaseMutex(&vcp->mx);
+                    }
+                    smb_CleanupDeadVC(vcp);
+                    smb_ReleaseVC(vcp);
+                    vcp = NULL;
+                    goto doneWithNCB;
+                }
+                else {
                    lock_ReleaseMutex(&vcp->mx);
-                thrd_Sleep(1000);
-               thrd_SetEvent(SessionEvents[idx_session]);
+                    smb_ReleaseVC(vcp);
+                    vcp = NULL;
+                    Sleep(10);
+                    thrd_SetEvent(SessionEvents[idx_session]);
+                }
             }
            continue;
         }
@@ -8296,14 +9200,17 @@ void smb_Server(VOID *parmp)
             if (smbp->com == 0x1d) {
                 /* Special handling for Write Raw */
                 raw_write_cont_t rwc;
-                EVENT_HANDLE rwevent;
-                char eventName[MAX_PATH];
             
                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
                 if (rwc.code == 0) {
-                    rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
+                    EVENT_HANDLE rwevent;
+                    char eventName[MAX_PATH];
+
+                    snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
+                    rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
+
                     ncbp->ncb_command = NCBRECV | ASYNCH;
                     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
                     ncbp->ncb_lana_num = vcp->lana;
@@ -8343,6 +9250,10 @@ void smb_Server(VOID *parmp)
     }
     if (vcp)
         smb_ReleaseVC(vcp);
+    if (outbufp)
+        smb_FreePacket(outbufp);
+    if (outncbp)
+        smb_FreeNCB(outncbp);
 }
 
 /*
@@ -8377,7 +9288,7 @@ void InitNCBslot(int idx)
 
     osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
 
-    NCBs[idx] = GetNCB();
+    NCBs[idx] = smb_GetNCB();
     sprintf(eventName,"NCBavails[%d]", idx);
     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
     if ( GetLastError() == ERROR_ALREADY_EXISTS )
@@ -8392,7 +9303,7 @@ void InitNCBslot(int idx)
         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
     for (i=0; i<smb_NumServerThreads; i++)
         NCBreturns[i][idx] = retHandle;
-    bufp = GetPacket();
+    bufp = smb_GetPacket();
     bufp->spacep = cm_GetSpace();
     bufs[idx] = bufp;
 }
@@ -8412,13 +9323,15 @@ void smb_Listener(void *parmp)
     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
     INT_PTR lana = (INT_PTR) parmp;
     char eventName[MAX_PATH];
+    int bridgeCount = 0;
+    int nowildCount = 0;
 
-    sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
+    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();
+    ncbp = smb_GetNCB();
 
     /* retrieve computer name */
     GetComputerName(cname, &cnamelen);
@@ -8446,9 +9359,10 @@ void smb_Listener(void *parmp)
 
         if (code == NRC_NAMERR) {
          /* An smb shutdown or Vista resume must have taken place */
-         osi_Log2(smb_logp,
+         osi_Log1(smb_logp,
                   "NCBLISTEN lana=%d failed with NRC_NAMERR.",
-                  ncbp->ncb_lana_num, code);
+                  ncbp->ncb_lana_num);
+         afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
 
             if (lock_TryMutex(&smb_StartedLock)) {
                 lana_list.lana[i] = LANA_INVALID;
@@ -8458,6 +9372,29 @@ void smb_Listener(void *parmp)
         } else if (code ==  NRC_BRIDGE || code != 0) {
             int lanaRemaining = 0;
 
+            if (code == NRC_BRIDGE) {
+                if (++bridgeCount <= 5) {
+                    afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
+                    continue;
+                }
+            } else if (code == NRC_NOWILD) {
+                if (++nowildCount <= 5) {
+                    afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
+
+                    if (bridgeCount > 0) {
+                        memset(ncbp, 0, sizeof(*ncbp));
+                        ncbp->ncb_command = NCBADDNAME;
+                        ncbp->ncb_lana_num = (UCHAR)lana;
+                        /* pad out with spaces instead of null termination */
+                        len = (long)strlen(smb_localNamep);
+                        strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
+                        for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
+                        code = Netbios(ncbp);
+                    }
+                    continue;
+                }
+            }
+
             while (!lock_TryMutex(&smb_StartedLock)) {
                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
                     goto exit_thread;
@@ -8467,6 +9404,8 @@ void smb_Listener(void *parmp)
             osi_Log2(smb_logp,
                       "NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
                       ncbp->ncb_lana_num, ncb_error_string(code));
+           afsi_log("NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
+                    ncbp->ncb_lana_num, ncb_error_string(code));
 
            for (i = 0; i < lana_list.length; i++) {
                if (lana_list.lana[i] == lana) {
@@ -8521,6 +9460,10 @@ void smb_Listener(void *parmp)
         }
 #endif /* 0 */
 
+        /* a successful packet received.  clear bridge error count */
+        bridgeCount = 0;
+        nowildCount = 0;
+
         /* check for remote conns */
         /* first get remote name and insert null terminator */
         memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
@@ -8562,7 +9505,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);
 
@@ -8600,7 +9543,7 @@ void smb_Listener(void *parmp)
 
         if (session >= SESSION_MAX - 1  || numNCBs >= NCB_MAX - 1) {
             unsigned long code = CM_ERROR_ALLBUSY;
-            smb_packet_t * outp = GetPacket();
+            smb_packet_t * outp = smb_GetPacket();
             unsigned char *outWctp;
             smb_t *smbp;
             
@@ -8701,12 +9644,301 @@ void smb_Listener(void *parmp)
     }  /* dispatch while loop */
 
 exit_thread:
-    FreeNCB(ncbp);
+    smb_FreeNCB(ncbp);
     thrd_SetEvent(ListenerShutdown[lana]);
     return;
 }
 
 static void
+configureBackConnectionHostNames(void)
+{
+    /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
+     * there is a restriction on the use of SMB authentication on loopback connections.
+     * There are two work arounds available:
+     * 
+     *   (1) We can disable the check for matching host names.  This does not
+     *   require a reboot:
+     *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
+     *     "DisableLoopbackCheck"=dword:00000001
+     *
+     *   (2) We can add the AFS SMB/CIFS service name to an approved list.  This
+     *   does require a reboot:
+     *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
+     *     "BackConnectionHostNames"=multi-sz
+     *
+     * The algorithm will be:
+     *   (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
+     *   (2a) If not, add it to the list.  (This will not take effect until the next reboot.)
+     *   (2b1)    and check to see if DisableLoopbackCheck is set.
+     *   (2b2)    If not set, set the DisableLoopbackCheck value to 0x1 
+     *   (2b3)                and create HKLM\SOFTWARE\OpenAFS\Client  UnsetDisableLoopbackCheck
+     *   (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
+     *             check for the UnsetDisableLoopbackCheck value.  
+     *             If set, set the DisableLoopbackCheck flag to 0x0 
+     *             and delete the UnsetDisableLoopbackCheck value
+     *
+     * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
+     * force Windows to use the loopback authentication mechanism for the specified 
+     * services.
+     * 
+     * Do not permit the "DisableLoopbackCheck" value to be removed within the same
+     * service session that set it.  
+     */
+    HKEY hkLsa;
+    HKEY hkMSV10;
+    HKEY hkClient;
+    DWORD dwType;
+    DWORD dwSize, dwAllocSize;
+    DWORD dwValue;
+    PBYTE pHostNames = NULL, pName = NULL;
+    BOOL  bNameFound = FALSE;   
+    static BOOL bLoopbackCheckDisabled = FALSE;
+
+    /* BackConnectionHostNames and DisableLoopbackCheck */
+    if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
+                       "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
+                       0,
+                       KEY_READ|KEY_WRITE,
+                       &hkMSV10) == ERROR_SUCCESS )
+    {
+        if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, 
+                            &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
+            (dwType == REG_MULTI_SZ)) 
+        {
+           dwAllocSize += 1 /* in case the source string is not nul terminated */
+               + (DWORD)strlen(cm_NetbiosName) + 2;
+           pHostNames = malloc(dwAllocSize);
+           dwSize = dwAllocSize;
+            if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType, 
+                                pHostNames, &dwSize) == ERROR_SUCCESS) 
+            {
+               for (pName = pHostNames; 
+                    (pName - pHostNames < (int) dwSize) && *pName ; 
+                    pName += strlen(pName) + 1)
+               {
+                   if ( !stricmp(pName, cm_NetbiosName) ) {
+                       bNameFound = TRUE;
+                       break;
+                   }   
+               }
+           }
+        }
+             
+        if ( !bNameFound ) {
+            size_t size = strlen(cm_NetbiosName) + 2;
+            if ( !pHostNames ) {
+                pHostNames = malloc(size);
+               pName = pHostNames;
+            }
+            StringCbCopyA(pName, size, cm_NetbiosName);
+            pName += size - 1;
+            *pName = '\0';  /* add a second nul terminator */
+
+            dwType = REG_MULTI_SZ;
+           dwSize = (DWORD)(pName - pHostNames + 1);
+            RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
+
+            if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
+                               "SYSTEM\\CurrentControlSet\\Control\\Lsa",
+                               0,
+                               KEY_READ|KEY_WRITE,
+                               &hkLsa) == ERROR_SUCCESS )
+            {
+                dwSize = sizeof(DWORD);
+                if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
+                     dwValue == 0 ) {
+                    dwType = REG_DWORD;
+                    dwSize = sizeof(DWORD);
+                    dwValue = 1;
+                    RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
+
+                    if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
+                                        AFSREG_CLT_OPENAFS_SUBKEY,
+                                        0,
+                                        NULL,
+                                        REG_OPTION_NON_VOLATILE,
+                                        KEY_READ|KEY_WRITE,
+                                        NULL,
+                                        &hkClient,
+                                        NULL) == ERROR_SUCCESS) {
+
+                        dwType = REG_DWORD;
+                        dwSize = sizeof(DWORD);
+                        dwValue = 1;
+                        RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
+                        bLoopbackCheckDisabled = TRUE;
+                        RegCloseKey(hkClient);
+                    }
+                    RegCloseKey(hkLsa);
+                }
+            }
+        } else if (!bLoopbackCheckDisabled) {
+            if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
+                                AFSREG_CLT_OPENAFS_SUBKEY,
+                                0,
+                                NULL,
+                                REG_OPTION_NON_VOLATILE,
+                                KEY_READ|KEY_WRITE,
+                                NULL,
+                                &hkClient,
+                                NULL) == ERROR_SUCCESS) {
+
+                dwSize = sizeof(DWORD);
+                if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
+                     dwValue == 1 ) {
+                    if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
+                                       "SYSTEM\\CurrentControlSet\\Control\\Lsa",
+                                       0,
+                                       KEY_READ|KEY_WRITE,
+                                       &hkLsa) == ERROR_SUCCESS )
+                    {
+                        RegDeleteValue(hkLsa, "DisableLoopbackCheck");
+                        RegCloseKey(hkLsa);
+                    }
+                }
+                RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
+                RegCloseKey(hkClient);
+            }
+        }
+
+        if (pHostNames) {
+            free(pHostNames);
+            pHostNames = NULL;
+        }
+
+        RegCloseKey(hkMSV10);
+    }
+}
+
+
+static void
+configureExtendedSMBSessionTimeouts(void)
+{
+    /*
+     * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
+     * new functionality:
+     *
+     *  [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
+     *   "ReconnectableServers"            REG_MULTI_SZ
+     *   "ExtendedSessTimeout"             REG_DWORD  (seconds)
+     *   "ServersWithExtendedSessTimeout"  REG_MULTI_SZ 
+     *  
+     * These values can be used to prevent the smb redirector from timing out
+     * smb connection to the afs smb server prematurely.
+     */
+    HKEY hkLanMan;
+    DWORD dwType;
+    DWORD dwSize, dwAllocSize;
+    DWORD dwValue;
+    PBYTE pHostNames = NULL, pName = NULL;
+    BOOL  bNameFound = FALSE;   
+
+    if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
+                       "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
+                       0,
+                       KEY_READ|KEY_WRITE,
+                       &hkLanMan) == ERROR_SUCCESS )
+    {
+        if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, 
+                            &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
+            (dwType == REG_MULTI_SZ)) 
+        {
+           dwAllocSize += 1 /* in case the source string is not nul terminated */
+               + (DWORD)strlen(cm_NetbiosName) + 2;
+           pHostNames = malloc(dwAllocSize);
+           dwSize = dwAllocSize;
+            if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType, 
+                                pHostNames, &dwSize) == ERROR_SUCCESS) 
+            {
+               for (pName = pHostNames; 
+                    (pName - pHostNames < (int) dwSize) && *pName ; 
+                    pName += strlen(pName) + 1)
+               {
+                   if ( !stricmp(pName, cm_NetbiosName) ) {
+                       bNameFound = TRUE;
+                       break;
+                   }   
+               }
+           }
+        }
+             
+        if ( !bNameFound ) {
+            size_t size = strlen(cm_NetbiosName) + 2;
+            if ( !pHostNames ) {
+                pHostNames = malloc(size);
+               pName = pHostNames;
+            }
+            StringCbCopyA(pName, size, cm_NetbiosName);
+            pName += size - 1;
+            *pName = '\0';  /* add a second nul terminator */
+
+            dwType = REG_MULTI_SZ;
+           dwSize = (DWORD)(pName - pHostNames + 1);
+            RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
+        }
+
+        if (pHostNames) {
+            free(pHostNames);
+            pHostNames = NULL;
+        }
+        
+        if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, 
+                            &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
+            (dwType == REG_MULTI_SZ)) 
+        {
+           dwAllocSize += 1 /* in case the source string is not nul terminated */
+               + (DWORD)strlen(cm_NetbiosName) + 2;
+           pHostNames = malloc(dwAllocSize);
+           dwSize = dwAllocSize;
+            if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType, 
+                                pHostNames, &dwSize) == ERROR_SUCCESS) 
+            {
+               for (pName = pHostNames; 
+                    (pName - pHostNames < (int) dwSize) && *pName ; 
+                    pName += strlen(pName) + 1)
+               {
+                   if ( !stricmp(pName, cm_NetbiosName) ) {
+                       bNameFound = TRUE;
+                       break;
+                   }   
+               }
+           }
+        }
+             
+        if ( !bNameFound ) {
+            size_t size = strlen(cm_NetbiosName) + 2;
+            if ( !pHostNames ) {
+                pHostNames = malloc(size);
+               pName = pHostNames;
+            }
+            StringCbCopyA(pName, size, cm_NetbiosName);
+            pName += size - 1;
+            *pName = '\0';  /* add a second nul terminator */
+
+            dwType = REG_MULTI_SZ;
+           dwSize = (DWORD)(pName - pHostNames + 1);
+            RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
+        }
+
+        if (pHostNames) {
+            free(pHostNames);
+            pHostNames = NULL;
+        }
+
+        if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0, 
+                              &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
+             (dwType != REG_DWORD)) 
+        {
+            dwType = REG_DWORD;
+           dwSize = sizeof(dwValue);
+            dwValue = 300;      /* 5 minutes */
+            RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
+        }
+        RegCloseKey(hkLanMan);
+    }
+}
+
+static void
 smb_LanAdapterChangeThread(void *param)
 {
     /* 
@@ -8756,33 +9988,41 @@ void smb_LanAdapterChange(int locked) {
         SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway, 
                                           LANA_NETBIOS_NAME_FULL)) &&
         lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
-        if ( isGateway != bGateway ||
-             strcmp(cm_NetbiosName, NetbiosName) ) {
+        if ( isGateway != bGateway ) {
+            afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
+                      smb_LANadapter, lanaNum, isGateway, bGateway);
+            change = 1;
+        } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
+            afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
+                      smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
             change = 1;
         } else {
-            NCB *ncbp = GetNCB();
+            NCB *ncbp = smb_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)
+                if (temp_list.length != lana_list.length) {
+                    afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
+                              smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
                     change = 1;
-                else {
+                } else {
                     for (i=0; i<lana_list.length; i++) {
                         if ( temp_list.lana[i] != lana_list.lana[i] ) {
+                            afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
+                                      smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
                             change = 1;
                             break;
                         }
                     }
                 }
             }
-           FreeNCB(ncbp);
+           smb_FreeNCB(ncbp);
         }
     } 
 
     if (change) {
-        afsi_log("Lan Adapter Change detected");
         smb_StopListeners(1);
         smb_RestartListeners(1);
     }
@@ -8812,7 +10052,7 @@ int smb_NetbiosInit(int locked)
         return 0;
     }
     /* setup the NCB system */
-    ncbp = GetNCB();
+    ncbp = smb_GetNCB();
 
     /* 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))) {
@@ -8842,6 +10082,8 @@ int smb_NetbiosInit(int locked)
     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;
@@ -8962,7 +10204,7 @@ int smb_NetbiosInit(int locked)
     }
         
     /* we're done with the NCB now */
-    FreeNCB(ncbp);
+    smb_FreeNCB(ncbp);
 
     afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
     if (lana_list.length > 0)
@@ -8990,6 +10232,15 @@ void smb_StartListeners(int locked)
     }
 
     afsi_log("smb_StartListeners");
+    /* Ensure the AFS Netbios Name is registered to allow loopback access */
+    configureBackConnectionHostNames();
+
+    /* Configure Extended SMB Session Timeouts */
+    if (msftSMBRedirectorSupportsExtendedTimeouts()) {
+        afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
+        configureExtendedSMBSessionTimeouts();
+    }
+
     smb_ListenerState = SMB_LISTENER_STARTED;
     cm_VolStatus_Network_Started(cm_NetbiosName
 #ifdef _WIN64
@@ -9039,7 +10290,7 @@ void smb_StopListener(NCB *ncbp, int lana, int wait)
     memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
     code = Netbios(ncbp);
           
-    afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
+    afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
              lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
 
     /* and then reset the LANA; this will cause the listener threads to exit */
@@ -9051,9 +10302,9 @@ void smb_StopListener(NCB *ncbp, int lana, int wait)
     if (code == 0) 
        code = ncbp->ncb_retcode;
     if (code != 0) {
-       afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
+       afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
     } else {
-       afsi_log("Netbios NCBRESET lana %d succeeded", lana);
+       afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
     }
 
     if (wait)
@@ -9082,7 +10333,7 @@ void smb_StopListeners(int locked)
 #endif
                                   );
 
-    ncbp = GetNCB();
+    ncbp = smb_GetNCB();
 
     /* Unregister the SMB name */
     for (l = 0; l < lana_list.length; l++) {
@@ -9099,7 +10350,7 @@ void smb_StopListeners(int locked)
     /* force a re-evaluation of the network adapters */
     lana_list.length = 0;
     smb_LANadapter = LANA_INVALID;
-    FreeNCB(ncbp);
+    smb_FreeNCB(ncbp);
     if (!locked)
         lock_ReleaseMutex(&smb_StartedLock);
 }
@@ -9147,14 +10398,14 @@ void smb_Init(osi_log_t *logp, int useV3,
     smb_logp = logp;
         
     /* and the global lock */
-    lock_InitializeRWLock(&smb_globalLock, "smb global lock");
-    lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
+    lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
+    lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
 
     /* Raw I/O data structures */
-    lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
+    lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
 
-    lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
-    lock_InitializeMutex(&smb_StartedLock, "smb started lock");
+    lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
+    lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
        
     /* 4 Raw I/O buffers */
     smb_RawBufs = calloc(65536,1);
@@ -9368,13 +10619,12 @@ void smb_Init(osi_log_t *logp, int useV3,
                                                     );
 
                 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
-                    char message[AFSPATHMAX];
-                    sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
-                                       nts, ntsEx);
-                    OutputDebugString(message);
-                    afsi_log(message);
+                    osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
+                             nts, ntsEx);
+
+                    afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
                 } else {
-                    OutputDebugString("MsV1_0SetProcessOption success");
+                    osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
                     afsi_log("MsV1_0SetProcessOption success");
                 }
                 /* END - code from Larry */
@@ -9430,10 +10680,10 @@ void smb_Init(osi_log_t *logp, int useV3,
          * 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 */
@@ -9481,7 +10731,7 @@ void smb_Shutdown(void)
     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
         
     /* setup the NCB system */
-    ncbp = GetNCB();
+    ncbp = smb_GetNCB();
 
     /* Block new sessions by setting shutdown flag */
     smbShutdownFlag = 1;
@@ -9535,7 +10785,7 @@ void smb_Shutdown(void)
         if (code == 0) 
             code = ncbp->ncb_retcode;
         if (code != 0) {
-            fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
+            fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
                      ncbp->ncb_lana_num, code);
         }       
         fflush(stderr);
@@ -9557,6 +10807,7 @@ void smb_Shutdown(void)
             if (fidp->scp != NULL) {
                 cm_scache_t * scp;
 
+                lock_ReleaseWrite(&smb_rctLock);
                 lock_ObtainMutex(&fidp->mx);
                 if (fidp->scp != NULL) {
                     scp = fidp->scp;
@@ -9568,6 +10819,7 @@ void smb_Shutdown(void)
                     cm_ReleaseSCache(scp);
                 }
                 lock_ReleaseMutex(&fidp->mx);
+                lock_ObtainWrite(&smb_rctLock);
             }
         }
 
@@ -9582,7 +10834,7 @@ void smb_Shutdown(void)
         }
     }
     lock_ReleaseWrite(&smb_rctLock);
-    FreeNCB(ncbp);
+    smb_FreeNCB(ncbp);
     TlsFree(smb_TlsRequestSlot);
 }
 
@@ -9590,6 +10842,7 @@ void smb_Shutdown(void)
 char *smb_GetSharename()
 {
     char *name;
+    size_t len;
 
     /* Make sure we have been properly initialized. */
     if (smb_localNamep == NULL)
@@ -9598,10 +10851,11 @@ 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
@@ -9672,37 +10926,119 @@ void smb_LogPacket(smb_packet_t *packet)
 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
 {
     int zilch;
-    char output[1024];
+    char output[4196];
   
     smb_vc_t *vcp;
-  
+    smb_username_t *unp;
+    smb_waitingLockRequest_t *wlrp;
+
     if (lock)
         lock_ObtainRead(&smb_rctLock);
   
+    sprintf(output, "begin dumping smb_username_t\r\n");
+    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+    for (unp = usernamesp; unp; unp=unp->nextp) 
+    {
+        cm_ucell_t *ucellp;
+
+        sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n", 
+                cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
+                unp->name ? unp->name : _C("NULL"), 
+                unp->machine ? unp->machine : _C("NULL"));
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
+        sprintf(output, "  begin dumping cm_ucell_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
+        for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
+            sprintf(output, "  %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n", 
+                     cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno, 
+                     ucellp->expirationTime, ucellp->gen, 
+                     ucellp->userName,
+                     ucellp->cellp->name);
+            WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        }
+
+        sprintf(output, "  done dumping cm_ucell_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
+    }
+    sprintf(output, "done dumping smb_username_t\r\n");
+    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
+
+    sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
+    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
+
+    for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
+        smb_waitingLock_t *lockp;
+
+        sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
+                 cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+      
+        sprintf(output, "  begin dumping smb_waitingLock_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
+            sprintf(output, "  %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n", 
+                    cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
+            WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        }
+        sprintf(output, "  done dumping smb_waitingLock_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+    }
+
+    sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
+    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
     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;
+        smb_tid_t *tidp;
+        smb_user_t *userp;
       
-        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
+        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, 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\r\n");
+        sprintf(output, "  begin dumping smb_user_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        for (userp = vcp->usersp; userp; userp = userp->nextp) {
+            sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
+                    cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
+            WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        }
+        sprintf(output, "  done dumping smb_user_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
+        sprintf(output, "  begin dumping smb_tid_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
+            sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n", 
+                    cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
+                    tidp->pathname ? tidp->pathname : _C("NULL"));
+            WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        }
+        sprintf(output, "  done dumping smb_tid_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
+        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\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");
+            sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n", 
+                    cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
+                    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\r\n");
+        sprintf(output, "  done dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }
 
@@ -9715,24 +11051,47 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
     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\r\n",
-                 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
+        smb_tid_t *tidp;
+        smb_user_t *userp;
+
+        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, 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\r\n");
+        sprintf(output, "  begin dumping smb_user_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        for (userp = vcp->usersp; userp; userp = userp->nextp) {
+            sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n", 
+                    cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
+            WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        }
+        sprintf(output, "  done dumping smb_user_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
+        sprintf(output, "  begin dumping smb_tid_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
+            sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n", 
+                    cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
+                    tidp->pathname ? tidp->pathname : _C("NULL"));
+            WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+        }
+        sprintf(output, "  done dumping smb_tid_t\r\n");
+        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
+
+        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\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");
+            sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n", 
+                    cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
+                    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\r\n");
+        sprintf(output, "  done dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }