windows-cpluscplus-compat-20080528
[openafs.git] / src / WINNT / afsd / smb.c
index 93996f8..bee69de 100644 (file)
@@ -31,6 +31,9 @@
 #include "smb.h"
 #include "lanahelper.h"
 
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+
 /* These characters are illegal in Windows filenames */
 static char *illegalChars = "\\/:*?\"<>|";
 
@@ -64,6 +67,8 @@ osi_mutex_t  smb_StartedLock;
 unsigned char smb_LANadapter = LANA_INVALID;
 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
 int  smb_LanAdapterChangeDetected = 0;
+afs_uint32    smb_AsyncStore = 1;
+afs_uint32    smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
 
 BOOL isGateway = FALSE;
 
@@ -76,9 +81,9 @@ smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
 smb_packet_t *smb_packetFreeListp;
 smb_ncb_t *smb_ncbFreeListp;
 
-int smb_NumServerThreads;
+afs_uint32 smb_NumServerThreads;
 
-int numNCBs, numSessions, numVCs;
+afs_uint32 numNCBs, numSessions, numVCs;
 
 int smb_maxVCPerServer;
 int smb_maxMpxRequests;
@@ -131,6 +136,9 @@ smb_dirSearch_t *smb_lastDirSearchp;
 /* hide dot files? */
 int smb_hideDotFiles;
 
+/* Negotiate Unicode support? */
+LONG smb_UseUnicode;
+
 /* global state about V3 protocols */
 int smb_useV3;         /* try to negotiate V3 */
 
@@ -212,7 +220,7 @@ void smb_UpdateServerPriority()
        time_t now = osi_Time();
 
        /* Give one priority boost for each 15 seconds */
-       SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
+       SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
     }
 }
 
@@ -1009,7 +1017,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;
@@ -1027,9 +1035,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);
@@ -1041,9 +1049,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 */
@@ -1070,7 +1078,7 @@ smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
     lock_ObtainWrite(&smb_rctLock);
   retry:
     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
-       if (tidp->refCount == 0 && tidp->delete) {
+       if (tidp->refCount == 0 && tidp->deleteOk) {
            tidp->refCount++;
            smb_ReleaseTID(tidp, TRUE);
            goto retry;
@@ -1111,7 +1119,7 @@ void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
     if (!locked)
         lock_ObtainWrite(&smb_rctLock);
     osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
-    if (tidp->refCount == 0 && (tidp->delete)) {
+    if (tidp->refCount == 0 && (tidp->deleteOk)) {
         ltpp = &tidp->vcp->tidsp;
         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
             if (tp == tidp) 
@@ -1169,8 +1177,8 @@ smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
 
     lock_ObtainWrite(&smb_rctLock);
     for(unp = usernamesp; unp; unp = unp->nextp) {
-        if (stricmp(unp->name, usern) == 0 &&
-             stricmp(unp->machine, machine) == 0) {
+        if (cm_stricmp_utf8(unp->name, usern) == 0 &&
+            cm_stricmp_utf8(unp->machine, machine) == 0) {
             unp->refCount++;
             break;
         }
@@ -1200,7 +1208,7 @@ 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_utf8(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));
@@ -1380,7 +1388,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);
@@ -1479,14 +1487,14 @@ 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)) {
+    if (fidp->refCount == 0 && (fidp->deleteOk)) {
         vcp = fidp->vcp;
         fidp->vcp = NULL;
         scp = fidp->scp;    /* release after lock is released */
        if (scp) {
-           lock_ObtainMutex(&scp->mx);
+           lock_ObtainWrite(&scp->rw);
            scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
-           lock_ReleaseMutex(&scp->mx);
+           lock_ReleaseWrite(&scp->rw);
            osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
            fidp->scp = NULL;
        }
@@ -1536,7 +1544,7 @@ static char *smb_stristr(char *str1, char *str2)
     char *cursor;
 
     for (cursor = str1; *cursor; cursor++)
-        if (stricmp(cursor, str2) == 0)
+        if (cm_stricmp_utf8(cursor, str2) == 0)
             return cursor;
 
     return NULL;
@@ -1577,13 +1585,17 @@ long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 {
     int matchType = 0;
     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
-    if (!strnicmp(dep->name, vrock->shareName, 12)) {
-        if(!stricmp(dep->name, vrock->shareName))
+    char normName[MAX_PATH];
+
+    cm_NormalizeUtf8String(dep->name, -1, normName, sizeof(normName)/sizeof(char));
+
+    if (!strnicmp(normName, vrock->shareName, 12)) {
+        if(!cm_stricmp_utf8(normName, vrock->shareName))
             matchType = SMB_FINDSHARE_EXACT_MATCH;
         else
             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
         if(vrock->match) free(vrock->match);
-        vrock->match = strdup(dep->name);
+        vrock->match = strdup(normName);
         vrock->matchType = matchType;
 
         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
@@ -1624,7 +1636,7 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
         RegCloseKey (parmKey);
     }
 
-    if (allSubmount && _stricmp(shareName, "all") == 0) {
+    if (allSubmount && cm_stricmp_utf8N(shareName, "all") == 0) {
         *pathNamep = NULL;
         return 1;
     }
@@ -1632,16 +1644,16 @@ 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) {
+    if (cm_stricmp_utf8N(shareName, "ioctl$") == 0) {
         *pathNamep = strdup("/.__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_stricmp_utf8N(shareName, "IPC$") == 0 ||
+        cm_stricmp_utf8N(shareName, "srvsvc") == 0 ||
+        cm_stricmp_utf8N(shareName, "wkssvc") == 0 ||
+        cm_stricmp_utf8N(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
+        cm_stricmp_utf8N(shareName, "DESKTOP.INI") == 0
          ) {
         *pathNamep = NULL;
         return 0;
@@ -1662,7 +1674,7 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
         snprintf(pathstr, sizeof(pathstr)/sizeof(char),
                  "/" CM_PREFIX_VOL "%s", shareName);
         pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
-        len = strlen(pathstr) + 1;
+        len = (DWORD)(strlen(pathstr) + 1);
 
         *pathNamep = malloc(len);
         if (*pathNamep) {
@@ -1823,17 +1835,17 @@ int smb_FindShareCSCPolicy(char *shareName)
     len = sizeof(policy);
     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
          len == 0) {
-        retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
+        retval = cm_stricmp_utf8N("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
     }
-    else if (stricmp(policy, "documents") == 0)
+    else if (cm_stricmp_utf8N(policy, "documents") == 0)
     {
         retval = CSC_POLICY_DOCUMENTS;
     }
-    else if (stricmp(policy, "programs") == 0)
+    else if (cm_stricmp_utf8N(policy, "programs") == 0)
     {
         retval = CSC_POLICY_PROGRAMS;
     }
-    else if (stricmp(policy, "disable") == 0)
+    else if (cm_stricmp_utf8N(policy, "disable") == 0)
     {
         retval = CSC_POLICY_DISABLE;
     }
@@ -1884,13 +1896,13 @@ void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
              dsp->cookie, dsp, dsp->scp);
     dsp->flags |= SMB_DIRSEARCH_DELETE;
     if (dsp->scp != NULL) {
-        lock_ObtainMutex(&dsp->scp->mx);
+        lock_ObtainWrite(&dsp->scp->rw);
         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
             dsp->scp->bulkStatProgress = hzero;
         }      
-        lock_ReleaseMutex(&dsp->scp->mx);
+        lock_ReleaseWrite(&dsp->scp->rw);
     }  
     lock_ReleaseMutex(&dsp->mx);
     lock_ReleaseWrite(&smb_globalLock);
@@ -2063,7 +2075,7 @@ static smb_packet_t *GetPacket(void)
         smb_packetFreeListp = tbp->nextp;
     lock_ReleaseWrite(&smb_globalLock);
     if (!tbp) {
-        tbp = calloc(65540,1);
+        tbp = calloc(sizeof(*tbp),1);
         tbp->magic = SMB_PACKETMAGIC;
         tbp->ncbp = NULL;
         tbp->vcp = NULL;
@@ -2076,7 +2088,7 @@ static smb_packet_t *GetPacket(void)
         tbp->ncb_length = 0;
         tbp->flags = 0;
         tbp->spacep = NULL;
-        
+        tbp->stringsp = NULL;
     }
     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
 
@@ -2089,6 +2101,7 @@ smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
     tbp = GetPacket();
     memcpy(tbp, pkt, sizeof(smb_packet_t));
     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
+    tbp->stringsp = NULL;
     if (tbp->vcp)
        smb_HoldVC(tbp->vcp);
     return tbp;
@@ -2116,6 +2129,18 @@ static NCB *GetNCB(void)
     return ncbp;
 }
 
+static void FreeSMBStrings(smb_packet_t * pkt)
+{
+    cm_space_t * s;
+    cm_space_t * ns;
+
+    for (s = pkt->stringsp; s; s = ns) {
+        ns = s->nextp;
+        cm_FreeSpace(s);
+    }
+    pkt->stringsp = NULL;
+}
+
 void smb_FreePacket(smb_packet_t *tbp)
 {
     smb_vc_t * vcp = NULL;
@@ -2136,6 +2161,7 @@ void smb_FreePacket(smb_packet_t *tbp)
     tbp->oddByte = 0;
     tbp->ncb_length = 0;
     tbp->flags = 0;
+    FreeSMBStrings(tbp);
     lock_ReleaseWrite(&smb_globalLock);
 
     if (vcp)
@@ -2343,6 +2369,8 @@ void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
     *parmDatap++ = parmValue & 0xff;
 }
 
+
+
 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
 {
     char *lastSlashp;
@@ -2363,14 +2391,286 @@ void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp
     }
 }
 
-unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
+unsigned char *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
+                                   char **chainpp, int flags)
 {
+    size_t cb;
+
     if (*inp++ != 0x4) 
         return NULL;
+
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    cb = sizeof(pktp->data) - (inp - pktp->data);
+    if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
+#ifdef DEBUG_UNICODE
+        DebugBreak();
+#endif
+        cb = sizeof(pktp->data);
+    }
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+unsigned char *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
+                               char ** chainpp, int flags)
+{
+    size_t cb;
+
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    cb = sizeof(pktp->data) - (inp - pktp->data);
+    if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
+#ifdef DEBUG_UNICODE
+        DebugBreak();
+#endif
+        cb = sizeof(pktp->data);
+    }
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+unsigned char *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
+                                 size_t cb, char ** chainpp, int flags)
+{
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+#endif
+
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+unsigned char *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
+                                  size_t cch, char ** chainpp, int flags)
+{
+    size_t cb = cch;
+
+#ifdef SMB_UNICODE
+    if (!WANTS_UNICODE(pktp))
+        flags |= SMB_STRF_FORCEASCII;
+    else
+        cb = cch * sizeof(wchar_t);
+#endif
+
+    return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
+}
+
+unsigned char *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;
+
+        if (bufbase && ((inp - bufbase) % 2) != 0) {
+            inp++;              /* unicode strings are always word aligned */
+        }
+
+        if (*pcb_max > 0) {
+            if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
+                                        &cch_src))) {
+                cch_src = *pcb_max / sizeof(wchar_t);
+                *pcb_max = 0;
+                null_terms = 0;
+            } else {
+                *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
+                null_terms = 1;
+            }
+        } else {
+            cch_src = 0;
+        }
+
+        spacep = cm_GetSpace();
+        spacep->nextp = *stringspp;
+        *stringspp = spacep;
+
+        if (cch_src == 0) {
+            if (chainpp) {
+                *chainpp = inp + sizeof(wchar_t);
+            }
+
+            spacep->data[0] = '\0';
+            return spacep->data;
+        }
+
+        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;
+        }
+
+        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;
+
+    } else {
+#endif
+        /* Not using Unicode */
     if (chainpp) {
-        *chainpp = inp + strlen(inp) + 1;      /* skip over null-terminated string */
+            *chainpp = inp + strlen(inp) + 1;
     }
+        if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
+            OemToChar(inp, inp);
     return inp;
+#ifdef SMB_UNICODE
+    }
+#endif
+}
+
+unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
+                                  unsigned char * 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 ((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);
+            }
+
+            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 (plen)
+                *plen = sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1 : nchars);
+
+            return (unsigned char *) 1; /* return TRUE if we are using unicode */
+        }
+        else
+#endif
+        {
+            /* Storing ANSI */
+            size_t len;
+
+            len = strlen(str);
+            if (plen)
+                *plen = ((flags & SMB_STRF_IGNORENULL)? len: len+1);
+
+            return NULL;
+        }
+    }
+
+    /* Number of bytes left in the buffer. */
+    if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
+        align = ((outp - pktp->data) % 2);
+        buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
+    } else {
+        align = (((size_t) outp) % 2);
+        buffersize = sizeof(pktp->data);
+    }
+
+#ifdef SMB_UNICODE
+
+    if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
+        int nchars;
+
+        if (align)
+            *outp++ = '\0';
+
+        if (*str == '\0') {
+
+            if (buffersize < sizeof(wchar_t))
+                return NULL;
+
+            *((wchar_t *) outp) = L'\0';
+            if (plen && !(flags & SMB_STRF_IGNORENULL))
+                *plen += sizeof(wchar_t);
+            return outp + sizeof(wchar_t);
+        }
+
+        nchars = 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);
+        }
+
+        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),
+                     GetLastError());
+            return NULL;
+        }
+
+        if (plen)
+            *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
+
+        return outp + sizeof(wchar_t) * nchars;
+    }
+    else
+#endif
+    {
+        /* Storing ANSI */
+        size_t len;
+
+        len = strlen(str); len++;
+        if (len > buffersize)
+            return NULL;
+
+        strcpy(outp, str);
+        if (plen)
+            *plen += ((flags & SMB_STRF_IGNORENULL)? len - 1: len);
+
+        return outp + len;
+    }
 }
 
 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
@@ -2392,6 +2692,23 @@ unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *length
     return inp;
 }      
 
+unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
+{
+    int tlen;
+
+    if (*inp++ != 0x1) return NULL;
+    tlen = inp[0] + (inp[1]<<8);
+    inp += 2;          /* skip length field */
+        
+    if (chainpp) {
+        *chainpp = inp + tlen;
+    }  
+
+    if (lengthp) *lengthp = tlen;
+        
+    return inp;
+}
+
 /* format a packet as a response */
 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
 {
@@ -2425,6 +2742,10 @@ void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op
     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
 #endif
     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
+#ifdef SMB_UNICODE
+    if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
+        outp->flg2 |= SMB_FLAGS2_UNICODE;
+#endif
 
     /* copy fields in generic packet area */
     op->wctp = &outp->wct;
@@ -2639,7 +2960,12 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
        NTStatus = 0xC000007EL; /* Range Not Locked */
     } 
-    else {
+    else if (code == CM_ERROR_NOSUCHDEVICE) {
+        NTStatus = 0xC000000EL; /* No Such Device */
+    }
+    else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
+        NTStatus = 0xC0000055L; /* Lock Not Granted */
+    } else {
         NTStatus = 0xC0982001L;        /* SMB non-specific error */
     }
 
@@ -2824,6 +3150,7 @@ long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return CM_ERROR_BADOP;
 }
 
+/* SMB_COM_ECHO */
 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short EchoCount, i;
@@ -2844,6 +3171,7 @@ long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
+/* SMB_COM_READ_RAW */
 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -2851,6 +3179,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     unsigned short fd;
     unsigned pid;
     smb_fid_t *fidp;
+    smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp = NULL;
     NCB *ncbp;
@@ -2901,7 +3230,7 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     }
 
 
-    pid = ((smb_t *) inp)->pid;
+    pid = smbp->pid;
     {
         LARGE_INTEGER LOffset, LLength;
         cm_key_t key;
@@ -2913,9 +3242,9 @@ long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&fidp->scp->rw);
         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ReleaseWrite(&fidp->scp->rw);
     }    
     if (code) {
         goto send1a;
@@ -3004,6 +3333,7 @@ long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     return 0;
 }
 
+/* SMB_COM_NEGOTIATE */
 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *namep;
@@ -3123,7 +3453,8 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
          * and NT Find *
          * and NT SMB's *
          * and raw mode 
-         * and DFS */
+         * and DFS
+         * and Unicode */
         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
 #ifdef DFS_SUPPORT
                NTNEGOTIATE_CAPABILITY_DFS |
@@ -3138,6 +3469,12 @@ long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         if ( smb_authType == SMB_AUTH_EXTENDED )
             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
 
+#ifdef SMB_UNICODE
+        if ( smb_UseUnicode ) {
+            caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
+        }
+#endif
+
         smb_SetSMBParmLong(outp, 9, caps);
         time(&unixTime);
         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
@@ -3318,7 +3655,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);
@@ -3328,10 +3665,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;    
@@ -3394,6 +3731,11 @@ void smb_WaitingLocksDaemon()
                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
                     continue;
 
+                if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
+                    code = CM_ERROR_LOCK_NOT_GRANTED;
+                    break;
+                }
+
                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
                 
                 /* wl->state is either _DONE or _WAITING.  _ERROR
@@ -3412,8 +3754,8 @@ void smb_WaitingLocksDaemon()
             if (code == CM_ERROR_WOULDBLOCK) {
 
                 /* no progress */
-                if (wlRequest->timeRemaining != 0xffffffff
-                     && (wlRequest->timeRemaining -= 1000) < 0)
+                if (wlRequest->msTimeout != 0xffffffff
+                     && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
                     goto endWait;
 
                 continue;
@@ -3433,20 +3775,21 @@ void smb_WaitingLocksDaemon()
 
                 cm_InitReq(&req);
 
-                lock_ObtainMutex(&scp->mx);
+                lock_ObtainWrite(&scp->rw);
 
                 for (wl = wlRequest->locks; wl; wl = wlNext) {
                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
-                    
-                    cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
-                              wl->LLength, wl->key, NULL, &req);
+                
+                    if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
+                        cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
+                                  wl->LLength, wl->key, NULL, &req);
 
                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
 
                     free(wl);
                 }
                 
-                lock_ReleaseMutex(&scp->mx);
+                lock_ReleaseWrite(&scp->rw);
 
             } else {
 
@@ -3507,6 +3850,7 @@ long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     return 0;
 }
 
+/* SMB_COM_TREE_CONNECT */
 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
 {
     smb_tid_t *tidp;
@@ -3517,17 +3861,13 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     int shareFound;
     char *tp;
     char *pathp;
-    char *passwordp;
     cm_user_t *userp;
 
     osi_Log0(smb_logp, "SMB receive tree connect");
 
     /* parse input parameters */
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
-    passwordp = smb_ParseASCIIBlock(tp, &tp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
     tp = strrchr(pathp, '\\');
     if (!tp)
         return CM_ERROR_BADSMB;
@@ -3561,23 +3901,6 @@ long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *
     return 0;
 }
 
-unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
-{
-    int tlen;
-
-    if (*inp++ != 0x1) return NULL;
-    tlen = inp[0] + (inp[1]<<8);
-    inp += 2;          /* skip length field */
-        
-    if (chainpp) {
-        *chainpp = inp + tlen;
-    }  
-
-    if (lengthp) *lengthp = tlen;
-        
-    return inp;
-}
-
 /* set maskp to the mask part of the incoming path.
  * Mask is 11 bytes long (8.3 with the dot elided).
  * Returns true if succeeds with a valid name, otherwise it does
@@ -3695,6 +4018,10 @@ char *smb_FindMask(char *pathp)
         return pathp;  /* no slash, return the entire path */
 }       
 
+/* SMB_COM_SEARCH for a volume label
+
+   (This is called from smb_ReceiveCoreSearchDir() and not an actual
+   dispatch function.) */
 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned char *pathp;
@@ -3708,10 +4035,9 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
 
     /* pull pathname and stat block out of request */
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
+    pathp = smb_ParseASCIIBlock(inp, tp, (char **) &tp,
+                                SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
     osi_assertx(pathp != NULL, "null path");
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
     statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
     osi_assertx(statBlockp != NULL, "null statBlock");
     if (statLen == 0) {
@@ -3754,6 +4080,9 @@ long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     *tp++ = 0;
     *tp++ = 0;
 
+    /* The filename is a UCHAR buffer that is ASCII even if Unicode
+       was negotiated. */
+
     /* finally, null-terminated 8.3 pathname, which we set to AFS */
     memset(tp, ' ', 13);
     strcpy(tp, "AFS");
@@ -3797,11 +4126,11 @@ smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
                 *dptr++ = SMB_ATTR_HIDDEN;
             continue;
         }
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
         if (code) {    
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
             cm_ReleaseSCache(scp);
             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
                 *dptr++ = SMB_ATTR_HIDDEN;
@@ -3810,6 +4139,7 @@ smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
 
        cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
 
+        lock_ConvertWToR(&scp->rw);
         attr = smb_Attributes(scp);
         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
         if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
@@ -3832,7 +4162,7 @@ smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
         /* copy out file length */
         *((u_long *)dptr) = scp->length.LowPart;
         dptr += 4;
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseRead(&scp->rw);
         cm_ReleaseSCache(scp);
     }
         
@@ -3848,6 +4178,7 @@ smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
     return code;
 }
 
+/* SMB_COM_SEARCH */
 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int attribute;
@@ -3903,9 +4234,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     caseFold = CM_FLAG_CASEFOLD;
 
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp,
+                                SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
 
     /* bail out if request looks bad */
@@ -4027,14 +4357,14 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
              * now.
              */
             cm_HoldSCache(scp);
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
                  && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
                 dsp->flags |= SMB_DIRSEARCH_BULKST;
                dsp->scp->bulkStatProgress = hzero;
             }
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
         }
     }
     lock_ReleaseMutex(&dsp->mx);
@@ -4052,11 +4382,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     smb_SetSMBParm(outp, 0, 0);
 
     /* get the directory size */
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code) {
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
         cm_ReleaseSCache(scp);
         cm_ReleaseUser(userp);
         smb_DeleteDirSearch(dsp);
@@ -4125,7 +4455,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                 buf_Release(bufferp);
                 bufferp = NULL;
             }  
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
             code = buf_Get(scp, &thyper, &bufferp);
             lock_ObtainMutex(&dsp->mx);
 
@@ -4134,7 +4464,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
              */
             if (starPattern) {
                 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
-                lock_ObtainMutex(&scp->mx);
+                lock_ObtainWrite(&scp->rw);
                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
                      LargeIntegerGreaterThanOrEqualTo(thyper, 
                                                       scp->bulkStatProgress)) {
@@ -4149,7 +4479,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                         code = cm_TryBulkStat(scp, &thyper, userp, &req);
                 }
             } else {
-                lock_ObtainMutex(&scp->mx);
+                lock_ObtainWrite(&scp->rw);
             }
             lock_ReleaseMutex(&dsp->mx);
             if (code) {
@@ -4322,6 +4652,8 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
             strncpy(op, actualName, 13);
             if (smb_StoreAnsiFilenames)
                 CharToOem(op, op);
+            /* This is a UCHAR field, which is ASCII even if Unicode
+               is negotiated. */
 
             /* Uppercase if requested by client */
             if (!KNOWS_LONG_NAMES(inp))
@@ -4341,7 +4673,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     }          /* while copying data for dir listing */
 
     /* release the mutex */
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     if (bufferp) {
        buf_Release(bufferp);
        bufferp = NULL;
@@ -4389,8 +4721,11 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     return code;
 }      
 
+
 /* verify that this is a valid path to a directory.  I don't know why they
  * don't use the get file attributes call.
+ *
+ * SMB_COM_CHECK_DIRECTORY
  */
 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
@@ -4407,11 +4742,9 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     cm_InitReq(&req);
 
     pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADFD;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
     osi_Log1(smb_logp, "SMB receive check path %s",
              osi_LogSaveString(smb_logp, pathp));
         
@@ -4448,12 +4781,12 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 #endif /* DFS_SUPPORT */
 
     /* now lock the vnode with a callback; returns with newScp locked */
-    lock_ObtainMutex(&newScp->mx);
+    lock_ObtainWrite(&newScp->rw);
     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
     if (code) {
        if (code != CM_ERROR_NOACCESS) {
-           lock_ReleaseMutex(&newScp->mx);
+           lock_ReleaseWrite(&newScp->rw);
            cm_ReleaseSCache(newScp);
            cm_ReleaseUser(userp);
            return code;
@@ -4467,13 +4800,14 @@ long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     if (!(attrs & SMB_ATTR_DIRECTORY))
         code = CM_ERROR_NOTDIR;
 
-    lock_ReleaseMutex(&newScp->mx);
+    lock_ReleaseWrite(&newScp->rw);
 
     cm_ReleaseSCache(newScp);
     cm_ReleaseUser(userp);
     return code;
 }      
 
+/* SMB_COM_SET_INFORMATION */
 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp;
@@ -4495,11 +4829,9 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
 
     pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADSMB;
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
                
     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
              dosTime, attribute);
@@ -4539,11 +4871,11 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
      * need the current status to determine what the new status is, in some
      * cases.
      */
-    lock_ObtainMutex(&newScp->mx);
+    lock_ObtainWrite(&newScp->rw);
     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
     if (code) {
-        lock_ReleaseMutex(&newScp->mx);
+        lock_ReleaseWrite(&newScp->rw);
         cm_ReleaseSCache(newScp);
         cm_ReleaseUser(userp);
         return code;
@@ -4553,7 +4885,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 
     /* Check for RO volume */
     if (newScp->flags & CM_SCACHEFLAG_RO) {
-        lock_ReleaseMutex(&newScp->mx);
+        lock_ReleaseWrite(&newScp->rw);
         cm_ReleaseSCache(newScp);
         cm_ReleaseUser(userp);
         return CM_ERROR_READONLY;
@@ -4575,7 +4907,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
         attr.unixModeBits = newScp->unixModeBits | 0222;
         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
     }
-    lock_ReleaseMutex(&newScp->mx);
+    lock_ReleaseWrite(&newScp->rw);
 
     /* now call setattr */
     if (attr.mask)
@@ -4589,6 +4921,7 @@ long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     return code;
 }
 
+
 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp;
@@ -4607,15 +4940,12 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     cm_InitReq(&req);
 
     pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
+    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
     if (!pathp)
         return CM_ERROR_BADSMB;
         
     if (*pathp == 0)           /* null path */
         pathp = "\\";
-    else
-        if (smb_StoreAnsiFilenames)
-            OemToChar(pathp,pathp);
 
     osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
              osi_LogSaveString(smb_logp, pathp));
@@ -4653,7 +4983,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastComp, pathp);
 #ifndef SPECIAL_FOLDERS
-    if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
+    if (lastComp && cm_stricmp_utf8N(lastComp, "\\desktop.ini") == 0) {
         code = cm_NameI(rootScp, spacep->data,
                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
                         userp, tidPathp, &req, &dscp);
@@ -4706,11 +5036,11 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
 #endif /* DFS_SUPPORT */
 
     /* now lock the vnode with a callback; returns with newScp locked */
-    lock_ObtainMutex(&newScp->mx);
+    lock_ObtainWrite(&newScp->rw);
     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
     if (code) {
-        lock_ReleaseMutex(&newScp->mx);
+        lock_ReleaseWrite(&newScp->rw);
         cm_ReleaseSCache(newScp);
         cm_ReleaseUser(userp);
         return code;
@@ -4747,7 +5077,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     smb_SetSMBParm(outp, 8, 0);
     smb_SetSMBParm(outp, 9, 0);
     smb_SetSMBDataLength(outp, 0);
-    lock_ReleaseMutex(&newScp->mx);
+    lock_ReleaseWrite(&newScp->rw);
 
     cm_ReleaseSCache(newScp);
     cm_ReleaseUser(userp);
@@ -4755,6 +5085,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     return 0;
 }      
 
+/* SMB_COM_TREE_DISCONNECT */
 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_tid_t *tidp;
@@ -4765,7 +5096,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);
     }
@@ -4773,6 +5104,7 @@ long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_
     return 0;
 }
 
+/* SMB_COM_0PEN */
 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     smb_fid_t *fidp;
@@ -4792,9 +5124,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     cm_InitReq(&req);
 
     pathp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(pathp, NULL);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
        
     osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
 
@@ -4884,9 +5214,9 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* save a pointer to the vnode */
     fidp->scp = scp;
     osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
 
     /* and the user */
     cm_HoldUser(userp);
@@ -4901,7 +5231,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
     lock_ReleaseMutex(&fidp->mx);
 
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainRead(&scp->rw);
     smb_SetSMBParm(outp, 0, fidp->fid);
     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
@@ -4912,7 +5242,7 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     /* pass the open mode back; XXXX add access checks */
     smb_SetSMBParm(outp, 6, (share & 0xf));
     smb_SetSMBDataLength(outp, 0);
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseRead(&scp->rw);
         
     /* notify open */
     cm_Open(scp, 0, userp);
@@ -4941,8 +5271,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;
+    char matchName[MAX_PATH];
         
     rockp = vrockp;
 
@@ -4950,13 +5279,12 @@ 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;
+    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
     match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
     if (!match &&
          (rockp->flags & SMB_MASKFLAG_TILDE) &&
          !cm_Is8Dot3(dep->name)) {
-        cm_Gen8Dot3Name(dep, shortName, NULL);
-        matchName = shortName;
+        cm_Gen8Dot3Name(dep, matchName, NULL);
         /* 8.3 matches are always case insensitive */
         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
     }
@@ -4979,6 +5307,7 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     return code;
 }
 
+/* SMB_COM_DELETE */
 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     int attribute;
@@ -5000,9 +5329,7 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     attribute = smb_GetSMBParm(inp, 0);
         
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     osi_Log1(smb_logp, "SMB receive unlink %s",
              osi_LogSaveString(smb_logp, pathp));
@@ -5079,15 +5406,22 @@ 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) {
+            char 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);
+
+            cm_NormalizeUtf8String(entry->name, -1, normalizedName,
+                                   sizeof(normalizedName)/sizeof(char));
+
+            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);
         }
     }
 
@@ -5111,7 +5445,8 @@ typedef struct smb_renameRock {
     char *maskp;               /* pointer to star pattern of old file name */
     int flags;             /* tilde, casefold, etc */
     char *newNamep;            /* ptr to the new file's name */
-    char oldName[MAX_PATH];
+    char oldName[MAX_PATH];     /* non-normalized name */
+    char normalizedOldName[MAX_PATH]; /* normalized name */
     int any;
 } smb_renameRock_t;
 
@@ -5121,26 +5456,28 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     smb_renameRock_t *rockp;
     int caseFold;
     int match;
-    char shortName[13]="";
+    char matchName[MAX_PATH];
 
     rockp = (smb_renameRock_t *) vrockp;
 
+    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
     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 = smb_V3MatchMask(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_Gen8Dot3Name(dep, matchName, NULL);
+        match = smb_V3MatchMask(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';
+        StringCbCopyA(rockp->oldName, sizeof(rockp->oldName), dep->name);
+        StringCbCopyA(rockp->normalizedOldName, sizeof(rockp->normalizedOldName),
+                      matchName);
             code = CM_ERROR_STOPNOW;
     } else {
        code = 0;
@@ -5252,6 +5589,7 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
     rock.newNamep = newLastNamep;
     rock.oldName[0] = '\0';
+    rock.normalizedOldName[0] = '\0';
     rock.any = 0;
 
     /* Check if the file already exists; if so return error */
@@ -5265,7 +5603,7 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
         /* 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_stricmp_utf8(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);
@@ -5307,7 +5645,7 @@ 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,
+       code = cm_Rename(rock.odscp, rock.oldName, rock.normalizedOldName,
                          rock.ndscp, rock.newNamep, rock.userp,
                          rock.reqp);   
         /* if the call worked, stop doing the search now, since we
@@ -5328,12 +5666,12 @@ 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,
+                                  filter, oldDscp, rock.normalizedOldName,
                                   newLastNamep, TRUE);
         } else {
             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
-                                  filter, oldDscp, oldLastNamep,
+                                  filter, oldDscp, rock.normalizedOldName,
                                   NULL, TRUE);
             if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
                 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
@@ -5506,6 +5844,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     return code;
 }
 
+/* SMB_COM_RENAME */
 long 
 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
@@ -5515,12 +5854,8 @@ smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     long code;
 
     tp = smb_GetSMBData(inp, NULL);
-    oldPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(oldPathp,oldPathp);
-    newPathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(newPathp,newPathp);
+    oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
+    newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     osi_Log2(smb_logp, "smb rename [%s] to [%s]",
              osi_LogSaveString(smb_logp, oldPathp),
@@ -5549,22 +5884,20 @@ 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;
+    char matchName[MAX_PATH];
         
     rockp = (smb_rmdirRock_t *) vrockp;
 
-    matchName = dep->name;
+    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
-        match = (cm_stricmp(matchName, rockp->maskp) == 0);
+        match = (cm_stricmp_utf8(matchName, rockp->maskp) == 0);
     else
         match = (strcmp(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_Gen8Dot3Name(dep, matchName, NULL);
+        match = (cm_stricmp_utf8(matchName, rockp->maskp) == 0);
     }       
 
     if (match) {
@@ -5575,6 +5908,7 @@ int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper
     return 0;
 }
 
+
 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     long code = 0;
@@ -5593,9 +5927,7 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     cm_InitReq(&req);
 
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
@@ -5659,15 +5991,20 @@ 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) {
+            char normalizedName[MAX_PATH];
+
+            cm_NormalizeUtf8String(entry->name, -1, normalizedName,
+                                   sizeof(normalizedName)/sizeof(char));
+
             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, normalizedName, 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, normalizedName, NULL, TRUE);
         }
     }
 
@@ -5682,6 +6019,7 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     return code;
 }
 
+/* SMB_COM_FLUSH */
 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -5718,7 +6056,7 @@ long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     userp = smb_GetUserFromVCP(vcp, inp);
 
     lock_ObtainMutex(&fidp->mx);
-    if (fidp->flags & SMB_FID_OPENWRITE) {
+    if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
        cm_scache_t * scp = fidp->scp;
        cm_HoldSCache(scp);
        lock_ReleaseMutex(&fidp->mx);
@@ -5740,47 +6078,59 @@ struct smb_FullNameRock {
     char *name;
     cm_scache_t *vnode;
     char *fullName;
+    char *originalName;
 };
 
 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
                      osi_hyper_t *offp)
 {
-    char shortName[13];
+    char matchName[MAX_PATH];
     struct smb_FullNameRock *vrockp;
 
     vrockp = (struct smb_FullNameRock *)rockp;
 
+    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
+
     if (!cm_Is8Dot3(dep->name)) {
+        char shortName[13];
+
         cm_Gen8Dot3Name(dep, shortName, NULL);
 
-        if (cm_stricmp(shortName, vrockp->name) == 0) {
-            vrockp->fullName = strdup(dep->name);
+        if (cm_stricmp_utf8N(shortName, vrockp->name) == 0) {
+            vrockp->fullName = strdup(matchName);
+            vrockp->originalName = strdup(dep->name);
             return CM_ERROR_STOPNOW;
         }
     }
-    if (cm_stricmp(dep->name, vrockp->name) == 0 &&
+    if (cm_stricmp_utf8(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 = strdup(matchName);
+        vrockp->originalName = strdup(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)
+                  char **newPathp, char ** 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
+        *originalPathp = rock.originalName;
+    } else {
         *newPathp = strdup(pathp);
+        *originalPathp = strdup(pathp);
+    }
 }
 
 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
@@ -5813,12 +6163,12 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     cm_InitReq(&req);
 
     lock_ObtainWrite(&smb_rctLock);
-    if (fidp->delete) {
+    if (fidp->deleteOk) {
        osi_Log0(smb_logp, "  Fid already closed.");
        lock_ReleaseWrite(&smb_rctLock);
        return CM_ERROR_BADFD;
     }
-    fidp->delete = 1;
+    fidp->deleteOk = 1;
     lock_ReleaseWrite(&smb_rctLock);
 
     lock_ObtainMutex(&fidp->mx);
@@ -5853,9 +6203,11 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
             smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
         }
-       lock_ReleaseMutex(&fidp->mx);
-        code = cm_FSync(scp, userp, &req);
-       lock_ObtainMutex(&fidp->mx);
+        if (smb_AsyncStore != 2) {
+            lock_ReleaseMutex(&fidp->mx);
+            code = cm_FSync(scp, userp, &req);
+            lock_ObtainMutex(&fidp->mx);
+        }
     }
     else 
         code = 0;
@@ -5871,7 +6223,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
        /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
            in zero. */
         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
-        lock_ObtainMutex(&scp->mx);
+        lock_ObtainWrite(&scp->rw);
 
         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
                           CM_SCACHESYNC_NEEDCALLBACK
@@ -5890,12 +6242,13 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
     post_syncopdone:
 
-        lock_ReleaseMutex(&scp->mx);
+        lock_ReleaseWrite(&scp->rw);
        lock_ObtainMutex(&fidp->mx);
     }
 
     if (fidp->flags & SMB_FID_DELONCLOSE) {
-        char *fullPathp;
+        char *fullPathp = NULL;
+        char *originalNamep = NULL;
 
        lock_ReleaseMutex(&fidp->mx);
 
@@ -5904,9 +6257,9 @@ 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)
@@ -5915,7 +6268,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                                      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)
@@ -5924,7 +6277,12 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                                      dscp, fullPathp, NULL, TRUE);
            }
         }
+
+        if (fullPathp)
         free(fullPathp);
+        if (originalNamep)
+            free(originalNamep);
+
        lock_ObtainMutex(&fidp->mx);
        fidp->flags &= ~SMB_FID_DELONCLOSE;
     }
@@ -5963,20 +6321,20 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
 
     if (delscp) {
        if (deleted) {
-           lock_ObtainMutex(&delscp->mx);
+           lock_ObtainWrite(&delscp->rw);
            if (deleted)
                delscp->flags |= CM_SCACHEFLAG_DELETED;
-           lock_ReleaseMutex(&delscp->mx);
+           lock_ReleaseWrite(&delscp->rw);
        }
         cm_ReleaseSCache(delscp);
     }
 
     if (scp) {
-       lock_ObtainMutex(&scp->mx);
+       lock_ObtainWrite(&scp->rw);
         if (nullcreator && scp->creator == userp)
             scp->creator = NULL;
        scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
-       lock_ReleaseMutex(&scp->mx);
+       lock_ReleaseWrite(&scp->rw);
        cm_ReleaseSCache(scp);
     }
 
@@ -5986,6 +6344,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     return code;
 }
 
+/* SMB_COM_CLOSE */
 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fid;
@@ -6017,7 +6376,7 @@ long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 /*
  * smb_ReadData -- common code for Read, Read And X, and Raw Read
  */
-long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
+long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
        cm_user_t *userp, long *readp)
 {
     osi_hyper_t offset;
@@ -6028,20 +6387,35 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     osi_hyper_t thyper;
     osi_hyper_t lastByte;
     osi_hyper_t bufferOffset;
-    long bufIndex, nbytes;
+    long bufIndex;
+    afs_uint32 nbytes;
     int chunk;
     int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
     cm_req_t req;
 
+    osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
+              fidp->fid, offsetp->LowPart, count);
+
+    *readp = 0;
+
+    lock_ObtainMutex(&fidp->mx);
+    /* make sure we have a readable FD */
+    if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
+       osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
+                 fidp->fid, fidp->flags);
+       lock_ReleaseMutex(&fidp->mx);
+        code = CM_ERROR_BADFDOP;
+        goto done2;
+    }
+    
     cm_InitReq(&req);
 
     bufferp = NULL;
     offset = *offsetp;
 
-    lock_ObtainMutex(&fidp->mx);
     scp = fidp->scp;
     cm_HoldSCache(scp);
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
 
     if (offset.HighPart == 0) {
         chunk = offset.LowPart >> cm_logChunkSize;
@@ -6101,11 +6475,11 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 buf_Release(bufferp);
                 bufferp = NULL;
             }
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
 
             code = buf_Get(scp, &thyper, &bufferp);
 
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
             if (code) goto done;
             bufferOffset = thyper;
 
@@ -6153,7 +6527,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     } /* while 1 */
 
   done:
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     if (bufferp)
         buf_Release(bufferp);
 
@@ -6162,19 +6536,22 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
     cm_ReleaseSCache(scp);
 
+  done2:
+    osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
+              fidp->fid, code, *readp);
     return code;
 }
 
 /*
  * smb_WriteData -- common code for Write and Raw Write
  */
-long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
+long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
        cm_user_t *userp, long *writtenp)
 {
     osi_hyper_t offset = *offsetp;
     long code = 0;
     long written = 0;
-    cm_scache_t *scp;
+    cm_scache_t *scp = NULL;
     osi_hyper_t fileLength;    /* file's length at start of write */
     osi_hyper_t minLength;     /* don't read past this */
     afs_uint32 nbytes;         /* # of bytes to transfer this iteration */
@@ -6183,8 +6560,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     osi_hyper_t bufferOffset;
     afs_uint32 bufIndex;               /* index in buffer where our data is */
     int doWriteBack = 0;
-    osi_hyper_t writeBackOffset;/* offset of region to write back when
-                                 * I/O is done */
+    osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
     DWORD filter = 0;
     cm_req_t req;
 
@@ -6193,8 +6569,6 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
     *writtenp = 0;
 
-    cm_InitReq(&req);
-
     lock_ObtainMutex(&fidp->mx);
     /* make sure we have a writable FD */
     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
@@ -6202,14 +6576,16 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                  fidp->fid, fidp->flags);
        lock_ReleaseMutex(&fidp->mx);
         code = CM_ERROR_BADFDOP;
-        goto done;
+        goto done2;
     }
     
+    cm_InitReq(&req);
+
     scp = fidp->scp;
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
 
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     /* start by looking up the file's end */
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                       CM_SCACHESYNC_NEEDCALLBACK
@@ -6249,14 +6625,15 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
      * based upon cm_chunkSize but we desire cm_chunkSize to be large
      * so that we can read larger amounts of data at a time.
      */
-    if ((thyper.LowPart & ~(cm_data.buf_blockSize-1)) !=
-         (offset.LowPart & ~(cm_data.buf_blockSize-1))) {
+    if (smb_AsyncStore == 1 && 
+         (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
+         (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
         /* they're different */
         doWriteBack = 1;
         writeBackOffset.HighPart = offset.HighPart;
-        writeBackOffset.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
+        writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
     }
-        
+
     *writtenp = count;
 
     /* now, copy the data one buffer at a time, until we've filled the
@@ -6283,12 +6660,12 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 buf_Release(bufferp);
                 bufferp = NULL;
             }  
-            lock_ReleaseMutex(&scp->mx);
+            lock_ReleaseWrite(&scp->rw);
 
             code = buf_Get(scp, &thyper, &bufferp);
 
             lock_ObtainMutex(&bufferp->mx);
-            lock_ObtainMutex(&scp->mx);
+            lock_ObtainWrite(&scp->rw);
             if (code) goto done;
 
             bufferOffset = thyper;
@@ -6327,7 +6704,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                                                                                ConvertLongToLargeInteger(count)),
                                                                minLength))) {
                     if (count < cm_data.buf_blockSize
-                         && bufferp->dataVersion == -1)
+                         && bufferp->dataVersion == CM_BUF_VERSION_BAD)
                         memset(bufferp->datap, 0,
                                 cm_data.buf_blockSize);
                     bufferp->dataVersion = scp->dataVersion;
@@ -6339,9 +6716,9 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
                 lock_ReleaseMutex(&bufferp->mx);
                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
                                      &req);
-                lock_ReleaseMutex(&scp->mx);
+                lock_ReleaseWrite(&scp->rw);
                 lock_ObtainMutex(&bufferp->mx);
-                lock_ObtainMutex(&scp->mx);
+                lock_ObtainWrite(&scp->rw);
                 if (code) break;
             }
             if (code) {
@@ -6384,7 +6761,7 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     } /* while 1 */
 
   done:
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
 
     if (bufferp) {
         lock_ReleaseMutex(&bufferp->mx);
@@ -6400,29 +6777,37 @@ long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     }       
     lock_ReleaseMutex(&fidp->mx);
 
-    if (code == 0 && doWriteBack) {
-        long code2;
-
-        lock_ObtainMutex(&scp->mx);
-        osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
-                  fidp->fid);
-        code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
-        osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
-                  fidp->fid, code2);
-        lock_ReleaseMutex(&scp->mx);
-        cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
-                            writeBackOffset.HighPart, 
-                            *writtenp & ~(cm_data.blockSize-1), 0, userp);
-       /* cm_SyncOpDone is called at the completion of cm_BkgStore */
+    if (code == 0) {
+        if (smb_AsyncStore > 0) {
+            if (doWriteBack) {
+                long code2;
+
+                lock_ObtainWrite(&scp->rw);
+                osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
+                          fidp->fid);
+                code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
+                osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
+                          fidp->fid, code2);
+                lock_ReleaseWrite(&scp->rw);
+                cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
+                                    writeBackOffset.HighPart, 
+                                    smb_AsyncStoreSize, 0, userp);
+                /* cm_SyncOpDone is called at the completion of cm_BkgStore */
+            }
+        } else {
+            cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
+        }
     }
 
     cm_ReleaseSCache(scp);
 
+  done2:
     osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
               fidp->fid, code, *writtenp);
     return code;
 }
 
+/* SMB_COM_WRITE */
 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     unsigned short fd;
@@ -6432,6 +6817,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     long written = 0, total_written = 0;
     unsigned pid;
     smb_fid_t *fidp;
+    smb_t* smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
     cm_attr_t truncAttr;       /* attribute struct used for truncating file */
@@ -6479,7 +6865,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LARGE_INTEGER LOffset;
         LARGE_INTEGER LLength;
 
-        pid = ((smb_t *) inp)->pid;
+        pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
         LOffset.HighPart = offset.HighPart;
@@ -6487,9 +6873,9 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&fidp->scp->rw);
         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ReleaseWrite(&fidp->scp->rw);
 
         if (code) {
            osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
@@ -6626,6 +7012,7 @@ long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t
     return 0;
 }
 
+/* SMB_COM_WRITE_RAW */
 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
 {
     osi_hyper_t offset;
@@ -6633,6 +7020,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     long totalCount;
     unsigned short fd;
     smb_fid_t *fidp;
+    smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
     char *op;
@@ -6698,7 +7086,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         LARGE_INTEGER LOffset;
         LARGE_INTEGER LLength;
 
-        pid = ((smb_t *) inp)->pid;
+        pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
         LOffset.HighPart = offset.HighPart;
@@ -6706,9 +7094,9 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
         LLength.HighPart = 0;
         LLength.LowPart = count;
 
-        lock_ObtainMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&fidp->scp->rw);
         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ReleaseWrite(&fidp->scp->rw);
 
         if (code) {
             smb_ReleaseFID(fidp);
@@ -6803,6 +7191,7 @@ long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *out
     return 0;
 }
 
+/* SMB_COM_READ */
 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     osi_hyper_t offset;
@@ -6810,6 +7199,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     unsigned short fd;
     unsigned pid;
     smb_fid_t *fidp;
+    smb_t *smbp = (smb_t*) inp;
     long code = 0;
     cm_user_t *userp;
     char *op;
@@ -6846,7 +7236,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LARGE_INTEGER LOffset, LLength;
         cm_key_t key;
 
-        pid = ((smb_t *) inp)->pid;
+        pid = smbp->pid;
         key = cm_GenerateKey(vcp->vcID, pid, fd);
 
         LOffset.HighPart = 0;
@@ -6854,9 +7244,9 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         LLength.HighPart = 0;
         LLength.LowPart = count;
         
-        lock_ObtainMutex(&fidp->scp->mx);
+        lock_ObtainWrite(&fidp->scp->rw);
         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
-        lock_ReleaseMutex(&fidp->scp->mx);
+        lock_ReleaseWrite(&fidp->scp->rw);
     }
     if (code) {
         smb_ReleaseFID(fidp);
@@ -6899,6 +7289,7 @@ long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return code;
 }
 
+/* SMB_COM_CREATE_DIRECTORY */
 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     char *pathp;
@@ -6923,9 +7314,7 @@ long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp
     initialModeBits = 0777;
         
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     if (strcmp(pathp, "\\") == 0)
         return CM_ERROR_EXISTS;
@@ -7018,6 +7407,7 @@ BOOL smb_IsLegalFilename(char *filename)
     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;
@@ -7053,9 +7443,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
        initialModeBits &= ~0222;
         
     tp = smb_GetSMBData(inp, NULL);
-    pathp = smb_ParseASCIIBlock(tp, &tp);
-    if (smb_StoreAnsiFilenames)
-        OemToChar(pathp,pathp);
+    pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
 
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
@@ -7198,9 +7586,9 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* save a pointer to the vnode */
     fidp->scp = scp;
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     scp->flags |= CM_SCACHEFLAG_SMB_FID;
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     
     /* and the user */
     fidp->userp = userp;
@@ -7217,6 +7605,7 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     return 0;
 }
 
+/* SMB_COM_SEEK */
 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 {
     long code = 0;
@@ -7261,7 +7650,7 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     scp = fidp->scp;
     cm_HoldSCache(scp);
     lock_ReleaseMutex(&fidp->mx);
-    lock_ObtainMutex(&scp->mx);
+    lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, &req, 0,
                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code == 0) {
@@ -7284,7 +7673,7 @@ long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
         smb_SetSMBDataLength(outp, 0);
     }
-    lock_ReleaseMutex(&scp->mx);
+    lock_ReleaseWrite(&scp->rw);
     smb_ReleaseFID(fidp);
     cm_ReleaseSCache(scp);
     cm_ReleaseUser(userp);
@@ -7391,9 +7780,11 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                 /* 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);
+                osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
+                         opName,vcp,vcp->lana,vcp->lsn);
                 code = (*(dp->procp)) (vcp, inp, outp);
-                osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
+                osi_Log4(smb_logp,"Dispatch return  code 0x%x vcp 0x%p lana %d lsn %d",
+                         code,vcp,vcp->lana,vcp->lsn);
 #ifdef LOG_PACKET
                 if ( code == CM_ERROR_BADSMB ||
                      code == CM_ERROR_BADOP )
@@ -7410,8 +7801,9 @@ void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                osi_Log3(smb_logp, "Request %s straddled session startup, "
                           "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
             }
-        }
-        else {
+
+            FreeSMBStrings(inp);
+        } else {
             /* bad opcode, fail the request, after displaying it */
             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
 #ifdef LOG_PACKET
@@ -7931,8 +8323,10 @@ void smb_Server(VOID *parmp)
         smbp = (smb_t *)bufp->data;
         outbufp->flags = 0;
 
+#ifndef NOTRACE
         __try
         {
+#endif
             if (smbp->com == 0x1d) {
                 /* Special handling for Write Raw */
                 raw_write_cont_t rwc;
@@ -7970,9 +8364,11 @@ void smb_Server(VOID *parmp)
                 /* TODO: what else needs to be serialized? */
                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
             }
+#ifndef NOTRACE        
         }
         __except( smb_ServerExceptionFilter() ) {
         }
+#endif
 
         smb_concurrentCalls--;
 
@@ -8010,7 +8406,7 @@ void InitNCBslot(int idx)
 {
     struct smb_packet *bufp;
     EVENT_HANDLE retHandle;
-    int i;
+    afs_uint32 i;
     char eventName[MAX_PATH];
 
     osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
@@ -8042,7 +8438,7 @@ void smb_Listener(void *parmp)
     long code = 0;
     long len;
     long i;
-    int  session, thread;
+    afs_uint32  session, thread;
     smb_vc_t *vcp = NULL;
     int flags = 0;
     char rname[NCBNAMSZ+1];
@@ -8271,6 +8667,7 @@ void smb_Listener(void *parmp)
                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
                 smbp->rcls = errClass;
             }
+
             smb_SendPacket(vcp, outp);
             smb_FreePacket(outp);
 
@@ -9112,7 +9509,7 @@ void smb_Shutdown(void)
 {
     NCB *ncbp;
     long code = 0;
-    int i;
+    afs_uint32 i;
     smb_vc_t *vcp;
 
     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
@@ -9198,9 +9595,9 @@ void smb_Shutdown(void)
                 if (fidp->scp != NULL) {
                     scp = fidp->scp;
                     fidp->scp = NULL;
-                   lock_ObtainMutex(&scp->mx);
+                   lock_ObtainWrite(&scp->rw);
                    scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
-                   lock_ReleaseMutex(&scp->mx);
+                   lock_ReleaseWrite(&scp->rw);
                    osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
                     cm_ReleaseSCache(scp);
                 }
@@ -9245,6 +9642,7 @@ char *smb_GetSharename()
 void smb_LogPacket(smb_packet_t *packet)
 {
     BYTE *vp, *cp;
+    smb_t * smbp;
     unsigned length, paramlen, datalen, i, j;
     char buf[81];
     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
@@ -9253,11 +9651,12 @@ void smb_LogPacket(smb_packet_t *packet)
 
     osi_Log0(smb_logp, "*** SMB packet dump ***");
 
+    smbp = (smb_t *) packet->data;
     vp = (BYTE *) packet->data;
 
-    datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
-    length = paramlen + 2 + datalen;
-
+    paramlen = smbp->wct * 2;
+    datalen = *((WORD *) (smbp->vdata + paramlen));
+    length = sizeof(*smbp) + paramlen + 1 + datalen;
 
     for (i=0;i < length; i+=16)
     {