windows-unicode-20080626
authorAsanka Herath <asanka@secure-endpoints.com>
Thu, 26 Jun 2008 06:43:49 +0000 (06:43 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Thu, 26 Jun 2008 06:43:49 +0000 (06:43 +0000)
LICENSE MIT

This patch is the second stage of the Unicode conversion.  In this stage
the cache manager has been converted from using 8-bit UTF8 C strings to
16-bit UTF16 C strings in the SMB, the DNLC, the B+ tree, and other
directly related modules.  The cm_cell, cm_volume, cm_scache, cm_buf,
cm_dcache, and cm_dir modules are left 8-bit because their data is all
8-bit UTF8 since they work only on file server strings.

The SMB layer accepts 16-bit UTF16, the B+ tree and DNLC use normalized
strings as the key, and everything uses UTF8.  Efforts have been made
to minimize the number of transitions from UTF8 to UTF16 and back.

For the most part strings are tagged with clientchar_t and normchar_t
and fschar_t types in order to distinguish between the various types of
strings that are in use.

other changes include addition prototyping.

32 files changed:
src/WINNT/afsd/afsd.h
src/WINNT/afsd/afsd_flushvol.c
src/WINNT/afsd/afsd_init.c
src/WINNT/afsd/afsd_init.h
src/WINNT/afsd/afsd_service.c
src/WINNT/afsd/cm_btree.c
src/WINNT/afsd/cm_btree.h
src/WINNT/afsd/cm_buf.h
src/WINNT/afsd/cm_callback.c
src/WINNT/afsd/cm_conn.h
src/WINNT/afsd/cm_dnlc.c
src/WINNT/afsd/cm_dnlc.h
src/WINNT/afsd/cm_dns.c
src/WINNT/afsd/cm_dns.h
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_ioctl.h
src/WINNT/afsd/cm_nls.c
src/WINNT/afsd/cm_nls.h
src/WINNT/afsd/cm_scache.h
src/WINNT/afsd/cm_user.h
src/WINNT/afsd/cm_utils.c
src/WINNT/afsd/cm_utils.h
src/WINNT/afsd/cm_vnodeops.c
src/WINNT/afsd/cm_vnodeops.h
src/WINNT/afsd/cm_volstat.c
src/WINNT/afsd/cm_volstat.h
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb.h
src/WINNT/afsd/smb3.c
src/WINNT/afsd/smb3.h
src/WINNT/afsd/smb_ioctl.c
src/WINNT/afsd/smb_ioctl.h

index 0067a7c..aa027af 100644 (file)
@@ -23,6 +23,7 @@ BOOL APIENTRY About(HWND, unsigned int, unsigned int, long);
 #include <nb30.h>
 
 #include "cm.h"
+#include "cm_nls.h"
 
 #include <osi.h>
 #include <afs/vldbint.h>
@@ -44,9 +45,9 @@ BOOL APIENTRY About(HWND, unsigned int, unsigned int, long);
 #include "cm_volume.h"
 #include "cm_dcache.h"
 #include "cm_access.h"
+#include "cm_dir.h"
 #include "cm_utils.h"
 #include "cm_vnodeops.h"
-#include "cm_dir.h"
 #include "cm_btree.h"
 #include "cm_daemon.h"
 #include "cm_ioctl.h"
@@ -55,7 +56,6 @@ BOOL APIENTRY About(HWND, unsigned int, unsigned int, long);
 #include "cm_memmap.h"
 #include "cm_freelance.h"
 #include "cm_performance.h"
-#include "cm_nls.h"
 #include "smb_ioctl.h"
 #include "afsd_init.h"
 #include "afsd_eventlog.h"
@@ -83,9 +83,12 @@ extern cm_scache_t *cm_rootSCachep;
 
 extern osi_log_t *afsd_logp;
 
-extern char cm_mountRoot[];
+extern fschar_t cm_mountRoot[];
 extern DWORD cm_mountRootLen;
 
+extern clientchar_t cm_mountRootC[];
+extern DWORD cm_mountRootCLen;
+
 extern char cm_CachePath[];
 
 extern BOOL isGateway;
index 640e9ec..124c1b6 100644 (file)
@@ -64,18 +64,18 @@ afsd_ServicePerformFlushVolumes()
     CONST CHAR COLON = ':';
     CONST CHAR SLASH = '\\';
     CONST DWORD        NETRESBUFSIZE = 16384;
-    CHAR               bufMessage[1024];
-    UINT               i;
-    DWORD              dwServerSize;
-    DWORD              dwRet;
-    DWORD              dwCount;
-    DWORD              dwNetResBufSize;
-    DWORD              dwTotalVols = 0;
-    DWORD              dwVolBegin, dwVolEnd;
-    DWORD              dwFlushBegin, dwFlushEnd;
-    HANDLE             hEnum;
+    CHAR       bufMessage[1024];
+    UINT       i;
+    DWORD      dwServerSize;
+    DWORD      dwRet;
+    DWORD      dwCount;
+    DWORD      dwNetResBufSize;
+    DWORD      dwTotalVols = 0;
+    DWORD      dwVolBegin, dwVolEnd;
+    DWORD      dwFlushBegin, dwFlushEnd;
+    HANDLE     hEnum;
     LPNETRESOURCE      lpNetResBuf, lpnr;
-    PCHAR              pszShareName, pc;
+    char        *pszShareName, *pc;
     afs_int32  afsRet = 0;
 
     if ( lana_OnlyLoopback() ) {
index bef18a1..b2cc032 100644 (file)
@@ -36,6 +36,9 @@
 #include "lanahelper.h"
 #include <strsafe.h>
 #include "cm_memmap.h"
+#ifdef DEBUG
+#include <crtdbg.h>
+#endif
 
 extern int RXAFSCB_ExecuteRequest(struct rx_call *z_call);
 extern int RXSTATS_ExecuteRequest(struct rx_call *z_call);
@@ -50,16 +53,21 @@ extern afs_int32 cm_BPlusTrees;
 #endif
 extern afs_int32 cm_OfflineROIsValid;
 extern afs_int32 cm_giveUpAllCBs;
-extern const char **smb_ExecutableExtensions;
+extern const clientchar_t **smb_ExecutableExtensions;
 
 osi_log_t *afsd_logp;
 
 cm_config_data_t        cm_data;
 
-char cm_rootVolumeName[VL_MAXNAMELEN];
+fschar_t cm_rootVolumeName[VL_MAXNAMELEN];
 DWORD cm_rootVolumeNameLen;
-char cm_mountRoot[1024];
+
+fschar_t cm_mountRoot[1024];
 DWORD cm_mountRootLen;
+
+clientchar_t cm_mountRootC[1024];
+DWORD cm_mountRootCLen;
+
 int cm_logChunkSize;
 int cm_chunkSize;
 
@@ -79,6 +87,7 @@ long cm_HostAddr;
 unsigned short cm_callbackport = CM_DEFAULT_CALLBACKPORT;
 
 char cm_NetbiosName[MAX_NB_NAME_LENGTH] = "";
+clientchar_t cm_NetbiosNameC[MAX_NB_NAME_LENGTH] = _C("");
 
 char cm_CachePath[MAX_PATH];
 DWORD cm_ValidateCache = 1;
@@ -87,9 +96,9 @@ BOOL reportSessionStartups = FALSE;
 
 cm_initparams_v1 cm_initParams;
 
-char *cm_sysName = 0;
-unsigned int   cm_sysNameCount = 0;
-char *cm_sysNameList[MAXNUMSYSNAMES];
+clientchar_t *cm_sysName = 0;
+unsigned int  cm_sysNameCount = 0;
+clientchar_t *cm_sysNameList[MAXNUMSYSNAMES];
 
 DWORD TraceOption = 0;
 
@@ -134,12 +143,6 @@ afsi_log(char *pattern, ...)
     }
 }
 
-extern initUpperCaseTable();
-void afsd_initUpperCaseTable() 
-{
-    initUpperCaseTable();
-}
-
 void
 afsi_start()
 {
@@ -296,10 +299,10 @@ configureBackConnectionHostNames(void)
                                 pHostNames, &dwSize) == ERROR_SUCCESS) 
             {
                for (pName = pHostNames; 
-                    (pName - pHostNames < dwSize) && *pName ; 
+                    (pName - pHostNames < (int) dwSize) && *pName ; 
                     pName += strlen(pName) + 1)
                {
-                   if ( !cm_stricmp_utf8(pName, cm_NetbiosName) ) {
+                   if ( !stricmp(pName, cm_NetbiosName) ) {
                        bNameFound = TRUE;
                        break;
                    }   
@@ -562,7 +565,7 @@ int afsd_InitCM(char **reasonP)
     long ltt, ltto;
     long rx_nojumbo;
     long virtualCache = 0;
-    char rootCellName[256];
+    fschar_t rootCellName[256];
     struct rx_service *serverp;
     static struct rx_securityClass *nullServerSecurityClassp;
     struct hostent *thp;
@@ -575,7 +578,6 @@ int afsd_InitCM(char **reasonP)
     /*int freelanceEnabled;*/
     WSADATA WSAjunk;
     int i;
-    char *p, *q; 
     int cm_noIPAddr;         /* number of client network interfaces */
     int cm_IPAddr[CM_MAXINTERFACE_ADDR];    /* client's IP address in host order */
     int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
@@ -584,7 +586,6 @@ int afsd_InitCM(char **reasonP)
 
     WSAStartup(0x0101, &WSAjunk);
 
-    afsd_initUpperCaseTable();
     init_et_to_sys_error();
 
     /* setup osidebug server at RPC slot 1000 */
@@ -612,7 +613,7 @@ int afsd_InitCM(char **reasonP)
 
     /* Look up configuration parameters in Registry */
     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
-                         0, KEY_QUERY_VALUE, &parmKey);
+                        0, KEY_QUERY_VALUE, &parmKey);
     if (code != ERROR_SUCCESS) {
         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
                        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
@@ -820,29 +821,32 @@ int afsd_InitCM(char **reasonP)
 
     dummyLen = sizeof(cm_rootVolumeName);
     code = RegQueryValueEx(parmKey, "RootVolume", NULL, NULL,
-                            cm_rootVolumeName, &dummyLen);
+                            (LPBYTE) cm_rootVolumeName, &dummyLen);
     if (code == ERROR_SUCCESS)
         afsi_log("Root volume %s", cm_rootVolumeName);
     else {
-        StringCbCopyA(cm_rootVolumeName, sizeof(cm_rootVolumeName), "root.afs");
+        cm_FsStrCpy(cm_rootVolumeName, lengthof(cm_rootVolumeName), "root.afs");
         afsi_log("Default root volume name root.afs");
     }
 
-    cm_mountRootLen = sizeof(cm_mountRoot);
-    code = RegQueryValueEx(parmKey, "MountRoot", NULL, NULL,
-                            cm_mountRoot, &cm_mountRootLen);
+    cm_mountRootCLen = sizeof(cm_mountRootC);
+    code = RegQueryValueExW(parmKey, L"MountRoot", NULL, NULL,
+                            (LPBYTE) cm_mountRootC, &cm_mountRootCLen);
     if (code == ERROR_SUCCESS) {
-        afsi_log("Mount root %s", cm_mountRoot);
-        cm_mountRootLen = (DWORD)strlen(cm_mountRoot);
+        afsi_log("Mount root %S", cm_mountRootC);
+        cm_mountRootCLen = cm_ClientStrLen(cm_mountRootC);
     } else {
-        StringCbCopyA(cm_mountRoot, sizeof(cm_mountRoot), "/afs");
-        cm_mountRootLen = 4;
+        cm_ClientStrCpy(cm_mountRootC, lengthof(cm_mountRootC), _C("/afs"));
+        cm_mountRootCLen = cm_ClientStrLen(cm_mountRootC);
         /* Don't log */
     }
 
+    cm_ClientStringToFsString(cm_mountRootC, -1, cm_mountRoot, lengthof(cm_mountRoot));
+    cm_mountRootLen = cm_FsStrLen(cm_mountRoot);
+
     dummyLen = sizeof(buf);
     code = RegQueryValueEx(parmKey, "CachePath", NULL, &regType,
-                            buf, &dummyLen);
+                           buf, &dummyLen);
     if (code == ERROR_SUCCESS && buf[0]) {
         if (regType == REG_EXPAND_SZ) {
             dummyLen = ExpandEnvironmentStrings(buf, cm_CachePath, sizeof(cm_CachePath));
@@ -907,47 +911,49 @@ int afsd_InitCM(char **reasonP)
     }
 
     for ( i=0; i < MAXNUMSYSNAMES; i++ ) {
-        cm_sysNameList[i] = osi_Alloc(MAXSYSNAME);
+        cm_sysNameList[i] = osi_Alloc(MAXSYSNAME * sizeof(clientchar_t));
         cm_sysNameList[i][0] = '\0';
     }
     cm_sysName = cm_sysNameList[0];
 
-    dummyLen = sizeof(buf);
-    code = RegQueryValueEx(parmKey, "SysName", NULL, NULL, buf, &dummyLen);
-    if (code != ERROR_SUCCESS || !buf[0]) {
+    {
+        clientchar_t *p, *q;
+        clientchar_t * cbuf = (clientchar_t *) buf;
+        dummyLen = sizeof(buf);
+        code = RegQueryValueExW(parmKey, L"SysName", NULL, NULL, (LPBYTE) cbuf, &dummyLen);
+        if (code != ERROR_SUCCESS || !cbuf[0]) {
 #if defined(_IA64_)
-        StringCbCopyA(buf, sizeof(buf), "ia64_win64");
+            cm_ClientStrCpy(cbuf, lengthof(buf), _C("ia64_win64"));
 #elif defined(_AMD64_)
-        StringCbCopyA(buf, sizeof(buf), "amd64_win64 x86_win32 i386_w2k");
+            cm_ClientStrCpy(cbuf, lengthof(buf), _C("amd64_win64 x86_win32 i386_w2k"));
 #else /* assume x86 32-bit */
-        StringCbCopyA(buf, sizeof(buf), "x86_win32 i386_w2k i386_nt40");
+            cm_ClientStrCpy(cbuf, lengthof(buf), _C("x86_win32 i386_w2k i386_nt40"));
 #endif
-    }
-    afsi_log("Sys name %s", buf); 
-
-    /* breakup buf into individual search string entries */
-    for (p = q = buf; p < buf + dummyLen; p++)
-    {
-        if (*p == '\0' || isspace(*p)) {
-            memcpy(cm_sysNameList[cm_sysNameCount],q,p-q);
-            cm_sysNameList[cm_sysNameCount][p-q] = '\0';
-            cm_sysNameCount++;
-
-            do {
-                if (*p == '\0')
-                    goto done_sysname;
-                p++;
-            } while (*p == '\0' || isspace(*p));
-            q = p;
-            p--;
+        }
+        afsi_log("Sys name %S", cbuf); 
+
+        /* breakup buf into individual search string entries */
+        for (p = q = cbuf; p < cbuf + dummyLen; p++) {
+            if (*p == '\0' || iswspace(*p)) {
+                memcpy(cm_sysNameList[cm_sysNameCount],q,(p-q) * sizeof(clientchar_t));
+                cm_sysNameList[cm_sysNameCount][p-q] = '\0';
+                cm_sysNameCount++;
+                do {
+                    if (*p == '\0')
+                        goto done_sysname;
+                    p++;
+                } while (*p == '\0' || isspace(*p));
+                q = p;
+                p--;
+            }
         }
     }
   done_sysname:
-    StringCbCopyA(cm_sysName, MAXSYSNAME, cm_sysNameList[0]);
+    cm_ClientStrCpy(cm_sysName, MAXSYSNAME, cm_sysNameList[0]);
 
     dummyLen = sizeof(cryptall);
     code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
-                            (BYTE *) &cryptall, &dummyLen);
+                           (BYTE *) &cryptall, &dummyLen);
     if (code == ERROR_SUCCESS) {
         afsi_log("SecurityLevel is %s", cryptall?"crypt":"clear");
     } else {
@@ -1150,28 +1156,27 @@ int afsd_InitCM(char **reasonP)
     afsi_log("CM BPlusTrees is not supported");
 #endif
 
-    if ((RegQueryValueEx( parmKey, "PrefetchExecutableExtensions", 0, 
-                          &regType, NULL, &dummyLen) == ERROR_SUCCESS) &&
+    if ((RegQueryValueExW( parmKey, L"PrefetchExecutableExtensions", 0, 
+                           &regType, NULL, &dummyLen) == ERROR_SUCCESS) &&
          (regType == REG_MULTI_SZ)) 
     {
-        char * pSz;
+        clientchar_t * pSz;
         dummyLen += 3; /* in case the source string is not nul terminated */
         pSz = malloc(dummyLen);
-        if ((RegQueryValueEx( parmKey, "PrefetchExecutableExtensions", 0, &regType, 
-                             pSz, &dummyLen) == ERROR_SUCCESS) &&
+        if ((RegQueryValueExW( parmKey, L"PrefetchExecutableExtensions", 0, &regType, 
+                               (LPBYTE) pSz, &dummyLen) == ERROR_SUCCESS) &&
              (regType == REG_MULTI_SZ))
         {
             int cnt;
-            char * p;
+            clientchar_t * p;
 
-            for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += strlen(p) + 1);
+            for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += cm_ClientStrLen(p) + 1);
 
-            smb_ExecutableExtensions = malloc(sizeof(char *) * (cnt+1));
+            smb_ExecutableExtensions = malloc(sizeof(clientchar_t *) * (cnt+1));
 
-            for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += strlen(p) + 1)
-            {
+            for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += cm_ClientStrLen(p) + 1) {
                 smb_ExecutableExtensions[cnt] = p;
-                afsi_log("PrefetchExecutableExtension: \"%s\"", p);
+                afsi_log("PrefetchExecutableExtension: \"%S\"", p);
             }
             smb_ExecutableExtensions[cnt] = NULL;
         }
@@ -1275,6 +1280,8 @@ int afsd_InitCM(char **reasonP)
     }
 
     if ( rx_mtu != -1 ) {
+        extern void rx_SetMaxMTU(int);
+
         rx_SetMaxMTU(rx_mtu);
         afsi_log("rx_SetMaxMTU %d successful", rx_mtu);
     }
@@ -1324,7 +1331,7 @@ int afsd_InitCM(char **reasonP)
 
     code = cm_GetRootCellName(rootCellName);
     afsi_log("cm_GetRootCellName code %d, cm_freelanceEnabled= %d, rcn= %s", 
-              code, cm_freelanceEnabled, (code ? "<none>" : rootCellName));
+             code, cm_freelanceEnabled, (code ? "<none>" : rootCellName));
     if (code != 0 && !cm_freelanceEnabled) 
     {
         *reasonP = "can't find root cell name in " AFS_CELLSERVDB;
@@ -1790,7 +1797,7 @@ void afsd_SetUnhandledExceptionFilter()
     SetUnhandledExceptionFilter(afsd_ExceptionFilter);
 #endif
 }
-  
+
 #ifdef _DEBUG
 void afsd_DbgBreakAllocInit()
 {
index c022b5d..5678bb3 100644 (file)
@@ -20,5 +20,5 @@ void afsd_SetUnhandledExceptionFilter();
 
 extern char cm_HostName[];
 extern char cm_NetbiosName[];
-
+extern clientchar_t cm_NetbiosNameC[];
 
index 2fe5344..8ca9c11 100644 (file)
@@ -14,6 +14,9 @@
 #include <stdlib.h>
 #include <winsock2.h>
 #include <WINNT\afsreg.h>
+#include "cm_btree.h"
+#include "cm_rpc.h"
+#include "smb.h"
 
 #include <osi.h>
 
@@ -1094,6 +1097,8 @@ afsd_Main(DWORD argc, LPTSTR *argv)
     HMODULE hAdvApi32;
 
 #ifdef _DEBUG
+    void afsd_DbgBreakAllocInit();
+
     afsd_DbgBreakAllocInit();
     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/ | 
                    _CRTDBG_CHECK_CRT_DF /* | _CRTDBG_DELAY_FREE_MEM_DF */ );
index e70fdb3..200525c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Secure Endpoints Inc.  
+ * Copyright 2007-2008 Secure Endpoints Inc.  
  * 
  * All Rights Reserved.
  *
@@ -15,6 +15,7 @@
 #include <stdlib.h>
 #include <assert.h>
 #include "afsd.h"
+#include <strsafe.h>
 
 #ifdef USE_BPLUS
 #include "cm_btree.h"
@@ -43,7 +44,7 @@ static void putFreeNode(Tree *B, Nptr self);
 static void cleanupNodePool(Tree *B);
 
 static Nptr descendToLeaf(Tree *B, Nptr curr);
-static int getSlot(Tree *B, Nptr curr);
+int getSlot(Tree *B, Nptr curr);
 static int findKey(Tree *B, Nptr curr, int lo, int hi);
 static int bestMatch(Tree *B, Nptr curr, int slot);
 
@@ -164,7 +165,7 @@ Tree *initBtree(unsigned int poolsz, unsigned int fanout, KeyCmp keyCmp)
     setcomparekeys(B, keyCmp);
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "INIT:  B+tree of fanout %d at %10p.\n", fanout, (void *)B);
+    StringCbPrintfA(B->message, sizeof(B->message), "INIT:  B+tree of fanout %d at %10p.\n", fanout, (void *)B);
     OutputDebugString(B->message);
 #endif
 
@@ -178,7 +179,7 @@ Tree *initBtree(unsigned int poolsz, unsigned int fanout, KeyCmp keyCmp)
 void freeBtree(Tree *B)
 {
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "FREE:  B+tree at %10p.\n", (void *) B);
+    StringCbPrintfA(B->message, sizeof(B->message), "FREE:  B+tree at %10p.\n", (void *) B);
     OutputDebugString(B->message);
 #endif
 
@@ -266,7 +267,7 @@ Nptr bplus_Lookup(Tree *B, keyT key)
     Nptr       leafNode;
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "LOOKUP:  key %s.\n", key.name);
+    StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP:  key %s.\n", key.name);
     OutputDebugString(B->message);
 #endif
 
@@ -286,14 +287,14 @@ Nptr bplus_Lookup(Tree *B, keyT key)
         dataNode = getnode(leafNode, slot);
         data = getdatavalue(dataNode);
 
-        sprintf(B->message, "LOOKUP: %s found on page %d value (%d.%d.%d).\n",
+        StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP: %s found on page %d value (%d.%d.%d).\n",
                  key.name,
                  getnodenumber(B, leafNode), 
                  data.fid.volume, 
                  data.fid.vnode,
                  data.fid.unique);
     } else 
-        sprintf(B->message, "LOOKUP: not found!\n");
+        StringCbPrintfA(B->message, sizeof(B->message), "LOOKUP: not found!\n");
     OutputDebugString(B->message);
 #endif
 
@@ -334,7 +335,7 @@ static Nptr descendToLeaf(Tree *B, Nptr curr)
 }
 
 /********************   find slot for search key   *********************/
-static int getSlot(Tree *B, Nptr curr)
+int getSlot(Tree *B, Nptr curr)
 {
     int slot, entries;
 
@@ -355,7 +356,7 @@ static int findKey(Tree *B, Nptr curr, int lo, int hi)
 
 #ifdef DEBUG_BTREE
         if (findslot == BTERROR) {
-            sprintf(B->message, "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n", 
+            StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n", 
                     lo, hi, getnodenumber(B, curr), curr);
             osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
         }
@@ -372,7 +373,7 @@ static int findKey(Tree *B, Nptr curr, int lo, int hi)
                 findslot = findKey(B, curr, mid + 1, hi);
             break;
         case BTERROR:
-            sprintf(B->message, "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n", 
+            StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) Bad key ordering on node %d (0x%p)\n", 
                     lo, hi, getnodenumber(B, curr), curr);
             osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
         }
@@ -380,7 +381,7 @@ static int findKey(Tree *B, Nptr curr, int lo, int hi)
 
     if (isleaf(curr) && findslot == 0)
     {
-        sprintf(B->message, "FINDKEY: (lo %d hi %d) findslot %d is invalid for leaf nodes, bad key ordering on node %d (0x%p)\n", 
+        StringCbPrintfA(B->message, sizeof(B->message), "FINDKEY: (lo %d hi %d) findslot %d is invalid for leaf nodes, bad key ordering on node %d (0x%p)\n", 
                 lo, hi, findslot, getnodenumber(B, curr), curr);
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
     }
@@ -435,7 +436,7 @@ static int bestMatch(Tree *B, Nptr curr, int slot)
 
     if (findslot == BTERROR || isleaf(curr) && findslot == 0)
     {
-        sprintf(B->message, "BESTMATCH: node %d (0x%p) slot %d diff %d comp %d findslot %d\n", 
+        StringCbPrintfA(B->message, sizeof(B->message), "BESTMATCH: node %d (0x%p) slot %d diff %d comp %d findslot %d\n", 
                 getnodenumber(B, curr), curr, slot, diff, comp, findslot);
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
     }
@@ -454,7 +455,7 @@ void insert(Tree *B, keyT key, dataT data)
     Nptr newNode;
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "INSERT:  key %s.\n", key.name);
+    StringCbPrintfA(B->message, sizeof(B->message), "INSERT:  key %s.\n", key.name);
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 #endif
 
@@ -528,7 +529,7 @@ insertEntry(Tree *B, Nptr currNode, int slot, Nptr sibling, Nptr downPtr)
     keyT key;
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "INSERT:  slot %d, down node %d.\n", slot, getnodenumber(B, downPtr));
+    StringCbPrintfA(B->message, sizeof(B->message), "INSERT:  slot %d, down node %d.\n", slot, getnodenumber(B, downPtr));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 #endif
 
@@ -732,7 +733,7 @@ void delete(Tree *B, keyT key)
     Nptr newNode;
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "DELETE:  key %s.\n", key.name);
+    StringCbPrintfA(B->message, sizeof(B->message), "DELETE:  key %s.\n", key.name);
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 #endif
 
@@ -741,7 +742,7 @@ void delete(Tree *B, keyT key)
     newNode = descendBalance(B, getroot(B), NONODE, NONODE, NONODE, NONODE, NONODE);
     if (isnode(newNode)) {
 #ifdef DEBUG_BTREE
-        sprintf(B->message, "DELETE: collapsing node %d", getnodenumber(B, newNode));
+        StringCbPrintfA(B->message, sizeof(B->message), "DELETE: collapsing node %d", getnodenumber(B, newNode));
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 #endif
         collapseRoot(B, getroot(B), newNode);  /* remove root when superfluous */
@@ -755,7 +756,7 @@ collapseRoot(Tree *B, Nptr oldRoot, Nptr newRoot)
 {
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "COLLAPSE:  old %d, new %d.\n", getnodenumber(B, oldRoot), getnodenumber(B, newRoot));
+    StringCbPrintfA(B->message, sizeof(B->message), "COLLAPSE:  old %d, new %d.\n", getnodenumber(B, oldRoot), getnodenumber(B, newRoot));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
     showNode(B, "collapseRoot oldRoot", oldRoot);
     showNode(B, "collapseRoot newRoot", newRoot);
@@ -777,7 +778,7 @@ descendBalance(Tree *B, Nptr curr, Nptr left, Nptr right, Nptr lAnc, Nptr rAnc,
     int        slot = 0, notleft = 0, notright = 0, fewleft = 0, fewright = 0, test = 0;
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "descendBalance curr %d, left %d, right %d, lAnc %d, rAnc %d, parent %d\n",
+    StringCbPrintfA(B->message, sizeof(B->message), "descendBalance curr %d, left %d, right %d, lAnc %d, rAnc %d, parent %d\n",
              curr ? getnodenumber(B, curr) : -1,
              left ? getnodenumber(B, left) : -1,
              right ? getnodenumber(B, right) : -1,
@@ -918,7 +919,7 @@ descendBalance(Tree *B, Nptr curr, Nptr left, Nptr right, Nptr lAnc, Nptr rAnc,
 
     if (newMe != NONODE) {     /* this node removal doesn't consider duplicates */
 #ifdef DEBUG_BTREE
-        sprintf(B->message, "descendBalance DELETE:  slot %d, node %d.\n", slot, getnodenumber(B, curr));
+        StringCbPrintfA(B->message, sizeof(B->message), "descendBalance DELETE:  slot %d, node %d.\n", slot, getnodenumber(B, curr));
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 #endif
 
@@ -972,7 +973,7 @@ descendBalance(Tree *B, Nptr curr, Nptr left, Nptr right, Nptr lAnc, Nptr rAnc,
     }
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "descendBalance returns %d\n", getnodenumber(B, newNode));
+    StringCbPrintfA(B->message, sizeof(B->message), "descendBalance returns %d\n", getnodenumber(B, newNode));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 #endif
     return newNode;
@@ -1004,7 +1005,7 @@ merge(Tree *B, Nptr left, Nptr right, Nptr anchor)
     int        x, y, z;
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "MERGE:  left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
+    StringCbPrintfA(B->message, sizeof(B->message), "MERGE:  left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
     showNode(B, "pre-merge anchor", anchor);
     showNode(B, "pre-merge left", left);
@@ -1061,7 +1062,7 @@ shift(Tree *B, Nptr left, Nptr right, Nptr anchor)
     int        i, x, y, z;
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "SHIFT:  left %d, right %d, anchor %d.\n", 
+    StringCbPrintfA(B->message, sizeof(B->message), "SHIFT:  left %d, right %d, anchor %d.\n", 
              getnodenumber(B, left), 
              getnodenumber(B, right), 
              getnodenumber(B, anchor));
@@ -1162,7 +1163,7 @@ shift(Tree *B, Nptr left, Nptr right, Nptr anchor)
     setmergepath(B, NONODE);
 
 #ifdef DEBUG_BTREE
-    sprintf(B->message, "SHIFT:  left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
+    StringCbPrintfA(B->message, sizeof(B->message), "SHIFT:  left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
     showNode(B, "post-shift anchor", anchor);
     showNode(B, "post-shift left", left);
@@ -1192,7 +1193,7 @@ _pushentry(Nptr node, int entry, int offset)
     if (entry == 0)
         DebugBreak();
 #endif
-    getkey(node,entry + offset).name = strdup(getkey(node,entry).name);
+    getkey(node,entry + offset).name = cm_NormStrDup(getkey(node,entry).name);
 #ifdef DEBUG_BTREE
     if ( getnode(node, entry) == NONODE )
         DebugBreak();
@@ -1205,7 +1206,7 @@ _pullentry(Nptr node, int entry, int offset)
 {
     if (getkey(node,entry).name != NULL)
         free(getkey(node,entry).name);
-    getkey(node,entry).name = strdup(getkey(node,entry + offset).name);
+    getkey(node,entry).name = cm_NormStrDup(getkey(node,entry + offset).name);
 #ifdef DEBUG_BTREE
     if ( getnode(node, entry + offset) == NONODE )
         DebugBreak();
@@ -1218,7 +1219,7 @@ _xferentry(Nptr srcNode, int srcEntry, Nptr destNode, int destEntry)
 {
     if (getkey(destNode,destEntry).name != NULL)
         free(getkey(destNode,destEntry).name);
-    getkey(destNode,destEntry).name = strdup(getkey(srcNode,srcEntry).name);
+    getkey(destNode,destEntry).name = cm_NormStrDup(getkey(srcNode,srcEntry).name);
 #ifdef DEBUG_BTREE
     if ( getnode(srcNode, srcEntry) == NONODE )
         DebugBreak();
@@ -1231,7 +1232,7 @@ _setentry(Nptr node, int entry, keyT key, Nptr downNode)
 {
     if (getkey(node,entry).name != NULL)
         free(getkey(node,entry).name);
-    getkey(node,entry).name = strdup(key.name);
+    getkey(node,entry).name = cm_NormStrDup(key.name);
 #ifdef DEBUG_BTREE
     if ( downNode == NONODE )
         DebugBreak();
@@ -1289,13 +1290,13 @@ cleanupNodePool(Tree *B)
                 free(getdatakey(node).name);
                 getdatakey(node).name = NULL;
             }
-            if ( getdatavalue(node).longname ) {
-                free(getdatavalue(node).longname);
-                getdatavalue(node).longname = NULL;
+            if ( getdatavalue(node).cname ) {
+                free(getdatavalue(node).cname);
+                getdatavalue(node).cname = NULL;
             }
-            if ( getdatavalue(node).origname ) {
-                free(getdatavalue(node).origname);
-                getdatavalue(node).origname = NULL;
+            if ( getdatavalue(node).fsname ) {
+                free(getdatavalue(node).fsname);
+                getdatavalue(node).fsname = NULL;
             }
         } else { /* data node */
             for ( j=1; j<=getfanout(B); j++ ) {
@@ -1345,8 +1346,10 @@ putFreeNode(Tree *B, Nptr node)
     if (isdata(node)) {
         if ( getdatakey(node).name )
             free(getdatakey(node).name);
-       if ( getdatavalue(node).longname )
-           free(getdatavalue(node).longname);
+       if ( getdatavalue(node).cname )
+           free(getdatavalue(node).cname);
+        if ( getdatavalue(node).fsname )
+            free(getdatavalue(node).fsname);
     } else {    /* data node */
         for ( i=1; i<=getfanout(B); i++ ) {
             if (getkey(node, i).name)
@@ -1368,7 +1371,7 @@ getDataNode(Tree *B, keyT key, dataT data)
     Nptr       newNode = getFreeNode(B);
 
     setflag(newNode, isDATA);
-    getdatakey(newNode).name = strdup(key.name);
+    getdatakey(newNode).name = cm_NormStrDup(key.name);
     getdatavalue(newNode) = data;
     getdatanext(newNode) = NONODE;
 
@@ -1386,61 +1389,61 @@ void showNode(Tree *B, const char * where, Nptr n)
 {
     int x;
 
-    sprintf(B->message, "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
+    StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "| %-20s                        |\n", where);
+    StringCbPrintfA(B->message, sizeof(B->message), "| %-20s                        |\n", where);
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "| node %6d                 ", getnodenumber(B, n));
+    StringCbPrintfA(B->message, sizeof(B->message), "| node %6d                 ", getnodenumber(B, n));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "  magic    %4x  |\n", getmagic(n));
+    StringCbPrintfA(B->message, sizeof(B->message), "  magic    %4x  |\n", getmagic(n));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
+    StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "| flags   %1d%1d%1d%1d ", isfew(n), isfull(n), isroot(n), isleaf(n));
+    StringCbPrintfA(B->message, sizeof(B->message), "| flags   %1d%1d%1d%1d ", isfew(n), isfull(n), isroot(n), isleaf(n));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "| keys = %5d ", numentries(n));
+    StringCbPrintfA(B->message, sizeof(B->message), "| keys = %5d ", numentries(n));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "| node = %6d  |\n", getnodenumber(B, getfirstnode(n)));
+    StringCbPrintfA(B->message, sizeof(B->message), "| node = %6d  |\n", getnodenumber(B, getfirstnode(n)));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
     for (x = 1; x <= numentries(n); x++) {
-        sprintf(B->message, "| entry %6d ", x);
+        StringCbPrintfA(B->message, sizeof(B->message), "| entry %6d ", x);
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-        sprintf(B->message, "| key = %6s ", getkey(n, x).name);
+        StringCbPrintfA(B->message, sizeof(B->message), "| key = %6s ", getkey(n, x).name);
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-        sprintf(B->message, "| node = %6d  |\n", getnodenumber(B, getnode(n, x)));
+        StringCbPrintfA(B->message, sizeof(B->message), "| node = %6d  |\n", getnodenumber(B, getnode(n, x)));
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
     }
-    sprintf(B->message, "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
+    StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  --  --  --  --  --  --  -\n");
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 }
 
 /******************   B+tree class variable printer   ******************/
 void showBtree(Tree *B)
 {
-    sprintf(B->message, "-  --  --  --  --  --  -\n");
+    StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  -\n");
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "|  B+tree  %10p  |\n", (void *) B);
+    StringCbPrintfA(B->message, sizeof(B->message), "|  B+tree  %10p  |\n", (void *) B);
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "-  --  --  --  --  --  -\n");
+    StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  -\n");
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "|  root        %6d  |\n", getnodenumber(B, getroot(B)));
+    StringCbPrintfA(B->message, sizeof(B->message), "|  root        %6d  |\n", getnodenumber(B, getroot(B)));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "|  leaf        %6d  |\n", getnodenumber(B, getleaf(B)));
+    StringCbPrintfA(B->message, sizeof(B->message), "|  leaf        %6d  |\n", getnodenumber(B, getleaf(B)));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "|  fanout         %3d  |\n", getfanout(B) + 1);
+    StringCbPrintfA(B->message, sizeof(B->message), "|  fanout         %3d  |\n", getfanout(B) + 1);
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "|  minfanout      %3d  |\n", getminfanout(B, getroot(B)) + 1);
+    StringCbPrintfA(B->message, sizeof(B->message), "|  minfanout      %3d  |\n", getminfanout(B, getroot(B)) + 1);
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "|  height         %3d  |\n", gettreeheight(B));
+    StringCbPrintfA(B->message, sizeof(B->message), "|  height         %3d  |\n", gettreeheight(B));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "|  freenode    %6d  |\n", getnodenumber(B, getfirstfreenode(B)));
+    StringCbPrintfA(B->message, sizeof(B->message), "|  freenode    %6d  |\n", getnodenumber(B, getfirstfreenode(B)));
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "|  theKey      %6s  |\n", getfunkey(B).name);
+    StringCbPrintfA(B->message, sizeof(B->message), "|  theKey      %6s  |\n", getfunkey(B).name);
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "|  theData     %d.%d.%d |\n", getfundata(B).volume,
+    StringCbPrintfA(B->message, sizeof(B->message), "|  theData     %d.%d.%d |\n", getfundata(B).volume,
              getfundata(B).vnode, getfundata(B).unique);
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
-    sprintf(B->message, "-  --  --  --  --  --  -\n");
+    StringCbPrintfA(B->message, sizeof(B->message), "-  --  --  --  --  --  -\n");
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 }
 
@@ -1452,7 +1455,7 @@ listBtreeNodes(Tree *B, const char * parent_desc, Nptr node)
     dataT data;
 
     if (isntnode(node)) {
-        sprintf(B->message, "%s - NoNode!!!\n");
+        StringCbPrintfA(B->message, sizeof(B->message), "%s - NoNode!!!\n");
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
         return;
     } 
@@ -1460,7 +1463,7 @@ listBtreeNodes(Tree *B, const char * parent_desc, Nptr node)
     if (!isnode(node))
     {
         data = getdatavalue(node);
-        sprintf(B->message, "%s - data node %d (%d.%d.%d)\n", 
+        StringCbPrintfA(B->message, sizeof(B->message), "%s - data node %d (%d.%d.%d)\n", 
                  parent_desc, getnodenumber(B, node),
                  data.fid.volume, data.fid.vnode, data.fid.unique);
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
@@ -1469,7 +1472,7 @@ listBtreeNodes(Tree *B, const char * parent_desc, Nptr node)
         showNode(B, parent_desc, node);
 
     if ( isinternal(node) || isroot(node) ) {
-        sprintf(thisnode, "parent %6d", getnodenumber(B , node));
+        StringCbPrintfA(thisnode, sizeof(thisnode), "parent %6d", getnodenumber(B , node));
 
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
         for ( i= isinternal(node) ? 0 : 1; i <= numentries(node); i++ ) {
@@ -1483,24 +1486,24 @@ void
 listBtreeValues(Tree *B, Nptr n, int num)
 {
     int slot;
-    keyT prev = {""};
+    keyT prev = {L""};
     dataT data;
 
     for (slot = 1; (n != NONODE) && num && numentries(n); num--) {
         if (comparekeys(B)(getkey(n, slot),prev, 0) < 0) {
-            sprintf(B->message, "BOMB %8s\n", getkey(n, slot).name);
+            StringCbPrintfA(B->message, sizeof(B->message), "BOMB %8s\n", getkey(n, slot).name);
             osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
             DebugBreak();
         }
         prev = getkey(n, slot);
         data = getdatavalue(getnode(n, slot));
-        sprintf(B->message, "%8s (%d.%d.%d)\n", 
+        StringCbPrintfA(B->message, sizeof(B->message), "%8S (%d.%d.%d)\n", 
                 prev.name, data.fid.volume, data.fid.vnode, data.fid.unique);
         osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
         if (++slot > numentries(n))
             n = getnextnode(n), slot = 1;
-    }   
-    sprintf(B->message, "\n\n");
+    }
+    StringCbPrintfA(B->message, sizeof(B->message), "\n\n");
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 }
 
@@ -1518,11 +1521,11 @@ findAllBtreeValues(Tree *B)
     int num = -1;
     Nptr n = getleaf(B), l;
     int slot;
-    keyT prev = {""};
+    keyT prev = {L""};
 
     for (slot = 1; (n != NONODE) && num && numentries(n); num--) {
         if (comparekeys(B)(getkey(n, slot),prev, 0) < 0) {
-            sprintf(B->message,"BOMB %8s\n", getkey(n, slot).name);
+            StringCbPrintfA(B->message, sizeof(B->message),"BOMB %8s\n", getkey(n, slot).name);
             osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 #ifdef DEBUG_BTREE
             DebugBreak();
@@ -1532,9 +1535,9 @@ findAllBtreeValues(Tree *B)
         l = bplus_Lookup(B, prev);
         if ( l != n ){
             if (l == NONODE)
-                sprintf(B->message,"BOMB %8s cannot be found\n", prev.name);
+                StringCbPrintfA(B->message, sizeof(B->message),"BOMB %8S cannot be found\n", prev.name);
             else 
-                sprintf(B->message,"BOMB lookup(%8s) finds wrong node\n", prev.name);
+                StringCbPrintfA(B->message, sizeof(B->message),"BOMB lookup(%8S) finds wrong node\n", prev.name);
             osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, B->message));
 #ifdef DEBUG_BTREE
             DebugBreak();
@@ -1556,26 +1559,27 @@ findAllBtreeValues(Tree *B)
  * match.  Otherwise, the search order might be considered 
  * to be inconsistent when the EXACT_MATCH flag is set.
  */
-static int
-compareKeys(keyT key1, keyT key2, int flags)
+int
+cm_BPlusCompareNormalizedKeys(keyT key1, keyT key2, int flags)
 {
     int comp;
 
-    comp = cm_stricmp_utf8(key1.name, key2.name);
+    comp = cm_NormStrCmpI(key1.name, key2.name);
     if (comp == 0 && (flags & EXACT_MATCH))
-        comp = strcmp(key1.name, key2.name);
+        comp = cm_NormStrCmp(key1.name, key2.name);
     return (comp < 0 ? -1 : (comp > 0 ? 1 : 0));
 }
 
 int
-cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, char * entry,
-                              char ** originalNameRetp)
+cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, clientchar_t *centry,
+                              fschar_t **fsnameRetp)
 {
     int rc = EINVAL;
-    keyT key = {entry};
+    keyT key = {NULL};
     Nptr leafNode = NONODE;
     LARGE_INTEGER start, end;
-    char * originalName = NULL;
+    fschar_t * fsname = NULL;
+    normchar_t * entry = NULL;
 
     if (op->scp->dirBplus == NULL || 
         op->dataVersion != op->scp->dirDataVersion) {
@@ -1583,6 +1587,9 @@ cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, char * entry,
         goto done;
     }
 
+    entry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+    key.name = entry;
+
     lock_AssertAny(&op->scp->dirlock);
 
     QueryPerformanceCounter(&start);
@@ -1618,11 +1625,11 @@ cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, char * entry,
         }
 
         if (exact) {
-            originalName = getdatavalue(dataNode).origname;
+            fsname = getdatavalue(dataNode).fsname;
             rc = 0;
             bplus_lookup_hits++;
         } else if (count == 1) {
-            originalName = getdatavalue(firstDataNode).origname;
+            fsname = getdatavalue(firstDataNode).fsname;
             rc = CM_ERROR_INEXACT_MATCH;
             bplus_lookup_hits_inexact++;
         } else {
@@ -1634,14 +1641,17 @@ cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, char * entry,
         bplus_lookup_misses++;
     }
 
-    if (originalName)
-        *originalNameRetp = strdup(originalName);
+    if (fsname)
+        *fsnameRetp = cm_FsStrDup(fsname);
 
     QueryPerformanceCounter(&end);
 
     bplus_lookup_time += (end.QuadPart - start.QuadPart);
 
   done:
+    if (entry)
+        free(entry);
+
     return rc;
 
 }
@@ -1655,10 +1665,11 @@ cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, char * entry,
        op->scp->dirlock is read locked
 */
 int
-cm_BPlusDirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
+cm_BPlusDirLookup(cm_dirOp_t * op, clientchar_t * centry, cm_fid_t * cfid)
 {
     int rc = EINVAL;
-    keyT key = {entry};
+    normchar_t * entry = NULL;
+    keyT key = {NULL};
     Nptr leafNode = NONODE;
     LARGE_INTEGER start, end;
 
@@ -1668,6 +1679,9 @@ cm_BPlusDirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
         goto done;
     }
 
+    entry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+    key.name = entry;
+
     lock_AssertAny(&op->scp->dirlock);
 
     QueryPerformanceCounter(&start);
@@ -1724,6 +1738,9 @@ cm_BPlusDirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
     bplus_lookup_time += (end.QuadPart - start.QuadPart);
 
   done:
+    if (entry)
+        free(entry);
+
     return rc;
 }
 
@@ -1735,13 +1752,13 @@ cm_BPlusDirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
    On exit:
        op->scp->dirlock is write locked
 */
-long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
+long cm_BPlusDirCreateEntry(cm_dirOp_t * op, clientchar_t * entry, cm_fid_t * cfid)
 {
     long rc = 0;
-    keyT key = {entry};
+    keyT key = {NULL};
     dataT  data;
     LARGE_INTEGER start, end;
-    char shortName[13];
+    normchar_t * normalizedName = NULL;
 
     if (op->scp->dirBplus == NULL || 
         op->dataVersion != op->scp->dirDataVersion) {
@@ -1749,26 +1766,36 @@ long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
         goto done;
     }
 
+    normalizedName = cm_ClientStringToNormStringAlloc(entry, -1, NULL);
+    key.name = normalizedName;
 
     lock_AssertWrite(&op->scp->dirlock);
 
     cm_SetFid(&data.fid, cfid->cell, cfid->volume, cfid->vnode, cfid->unique);
-    data.longname = NULL;
-    data.origname = NULL;
+    data.cname = cm_ClientStrDup(entry);
+    data.fsname = cm_ClientStringToFsStringAlloc(entry, -1, NULL);
+    data.shortform = FALSE;
 
     QueryPerformanceCounter(&start);
     bplus_create_entry++;
 
     insert(op->scp->dirBplus, key, data);
+
     if (!cm_Is8Dot3(entry)) {
         cm_dirFid_t dfid;
+        clientchar_t wshortName[13];
+
         dfid.vnode = htonl(data.fid.vnode);
         dfid.unique = htonl(data.fid.unique);
 
-        cm_Gen8Dot3NameInt(entry, &dfid, shortName, NULL);
+        cm_Gen8Dot3NameIntW(entry, &dfid, wshortName, NULL);
+
+        key.name = wshortName;
+
+        data.cname = cm_ClientStrDup(entry);
+        data.fsname = cm_ClientStringToFsStringAlloc(entry, -1, NULL);
+        data.shortform = TRUE;
 
-        key.name = shortName;
-        data.longname = strdup(entry);
         insert(op->scp->dirBplus, key, data);
     }
 
@@ -1778,6 +1805,9 @@ long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
 
   done:
 
+    if (normalizedName != NULL)
+        free(normalizedName);
+
     return rc;
 }
 
@@ -1788,12 +1818,13 @@ long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
    On exit:
        op->scp->dirlock is write locked
 */
-int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
+int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, clientchar_t *centry)
 {
     long rc = 0;
-    keyT key = {entry};
+    keyT key = {NULL};
     Nptr leafNode = NONODE;
     LARGE_INTEGER start, end;
+    normchar_t * normalizedEntry = NULL;
 
     if (op->scp->dirBplus == NULL || 
         op->dataVersion != op->scp->dirDataVersion) {
@@ -1801,6 +1832,9 @@ int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
         goto done;
     }
 
+    normalizedEntry = cm_ClientStringToNormStringAlloc(centry, -1, NULL);
+    key.name = normalizedEntry;
+
     lock_AssertWrite(&op->scp->dirlock);
 
     QueryPerformanceCounter(&start);
@@ -1808,10 +1842,10 @@ int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
     bplus_remove_entry++;
 
     if (op->scp->dirBplus) {
-        if (!cm_Is8Dot3(entry)) {
+        if (!cm_Is8Dot3(centry)) {
             cm_dirFid_t dfid;
             cm_fid_t fid;
-            char shortName[13];
+            clientchar_t shortName[13];
 
             leafNode = bplus_Lookup(op->scp->dirBplus, key);
             if (leafNode != NONODE) {
@@ -1858,7 +1892,7 @@ int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
             if (rc != CM_ERROR_AMBIGUOUS_FILENAME) {
                 dfid.vnode = htonl(fid.vnode);
                 dfid.unique = htonl(fid.unique);
-                cm_Gen8Dot3NameInt(entry, &dfid, shortName, NULL);
+                cm_Gen8Dot3NameIntW(centry, &dfid, shortName, NULL);
 
                 /* delete first the long name and then the short name */
                 delete(op->scp->dirBplus, key);
@@ -1866,7 +1900,8 @@ int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
                 delete(op->scp->dirBplus, key);
             }
         } else {
-            char * longname = NULL;
+            clientchar_t * cname = NULL;
+
             /* We need to lookup the 8dot3 name to determine what the 
              * matching long name is
              */
@@ -1902,10 +1937,10 @@ int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
                 }
 
                 if (exact) {
-                    longname = getdatavalue(dataNode).longname;
+                    cname = getdatavalue(dataNode).cname;
                     rc = 0;
                 } else if (count == 1) {
-                    longname = getdatavalue(firstDataNode).longname;
+                    cname = getdatavalue(firstDataNode).cname;
                     rc = CM_ERROR_INEXACT_MATCH;
                 } else {
                     rc = CM_ERROR_AMBIGUOUS_FILENAME;
@@ -1913,11 +1948,16 @@ int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
             }
 
             if (rc != CM_ERROR_AMBIGUOUS_FILENAME) {
-                if (longname) {
-                    key.name = longname;
+                if (cname) {
+                    normchar_t * longNName = cm_NormalizeStringAlloc(cname, -1, NULL);
+
+                    key.name = longNName;
                     delete(op->scp->dirBplus, key);
-                    key.name = entry;
+                    key.name = normalizedEntry;
+
+                    free(longNName);
                 }
+
                 delete(op->scp->dirBplus, key);
             }
         }
@@ -1928,6 +1968,9 @@ int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
     bplus_remove_time += (end.QuadPart - start.QuadPart);
 
   done:
+    if (normalizedEntry)
+        free(normalizedEntry);
+
     return rc;
       
 }
@@ -1936,39 +1979,47 @@ static
 int cm_BPlusDirFoo(struct cm_scache *scp, struct cm_dirEntry *dep,
                    void *dummy, osi_hyper_t *entryOffsetp)
 {
-    keyT   key = {dep->name};
+    keyT   key = {NULL};
     dataT  data;
-    char   shortName[13];
-    long   normalized_len;
-    char  *normalized_name=NULL;
-    cm_SetFid(&data.fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
-    data.longname = NULL;
-    data.origname = NULL;
-
-    normalized_len = cm_NormalizeUtf8String(dep->name, -1, NULL, 0);
-    if (normalized_len)
-        normalized_name = malloc(normalized_len);
+    normchar_t *normalized_name=NULL;
+
+    cm_SetFid(&data.fid, scp->fid.cell, scp->fid.volume,
+              ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
+    data.cname = NULL;
+    data.fsname = NULL;
+
+    normalized_name = cm_FsStringToNormStringAlloc(dep->name, -1, NULL);
+
     if (normalized_name) {
-        cm_NormalizeUtf8String(dep->name, -1, normalized_name, normalized_len);
         key.name = normalized_name;
-        if (strcmp(normalized_name, dep->name))
-            data.origname = strdup(dep->name);
     } else {
-        key.name = dep->name;
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        return 0;
     }
 
+    data.cname = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
+    data.fsname = cm_FsStrDup(dep->name);
+    data.shortform = FALSE;
+
     /* the Write lock is held in cm_BPlusDirBuildTree() */
     insert(scp->dirBplus, key, data);
-    if (!cm_Is8Dot3(dep->name)) {
+
+    if (!cm_Is8Dot3(data.cname)) {
         cm_dirFid_t dfid;
+        wchar_t wshortName[13];
+
         dfid.vnode = dep->fid.vnode;
         dfid.unique = dep->fid.unique;
 
-        cm_Gen8Dot3NameInt(dep->name, &dfid, shortName, NULL);
+        cm_Gen8Dot3NameIntW(data.cname, &dfid, wshortName, NULL);
+
+        key.name = wshortName;
+        data.cname = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
+        data.fsname = cm_FsStrDup(dep->name);
+        data.shortform = TRUE;
 
-        data.longname = strdup(key.name);
-        data.origname = NULL;
-        key.name = shortName;
         insert(scp->dirBplus, key, data);
     }
 
@@ -2001,7 +2052,7 @@ long cm_BPlusDirBuildTree(cm_scache_t *scp, cm_user_t *userp, cm_req_t* reqp)
     bplus_build_tree++;
 
     if (scp->dirBplus == NULL) {
-        scp->dirBplus = initBtree(64, MAX_FANOUT, compareKeys);
+        scp->dirBplus = initBtree(64, MAX_FANOUT, cm_BPlusCompareNormalizedKeys);
     }
     if (scp->dirBplus == NULL) {
         rc = ENOMEM;
@@ -2026,34 +2077,34 @@ int cm_MemDumpBPlusStats(FILE *outputFile, char *cookie, int lock)
     int zilch;
     char output[128];
 
-    sprintf(output, "%s - B+ Lookup    Hits: %-8d\r\n", cookie, bplus_lookup_hits);
+    StringCbPrintfA(output, sizeof(output), "%s - B+ Lookup    Hits: %-8d\r\n", cookie, bplus_lookup_hits);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -      Inexact Hits: %-8d\r\n", cookie, bplus_lookup_hits_inexact);
+    StringCbPrintfA(output, sizeof(output), "%s -      Inexact Hits: %-8d\r\n", cookie, bplus_lookup_hits_inexact);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -    Ambiguous Hits: %-8d\r\n", cookie, bplus_lookup_ambiguous);
+    StringCbPrintfA(output, sizeof(output), "%s -    Ambiguous Hits: %-8d\r\n", cookie, bplus_lookup_ambiguous);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -            Misses: %-8d\r\n", cookie, bplus_lookup_misses);
+    StringCbPrintfA(output, sizeof(output), "%s -            Misses: %-8d\r\n", cookie, bplus_lookup_misses);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -            Create: %-8d\r\n", cookie, bplus_create_entry);
+    StringCbPrintfA(output, sizeof(output), "%s -            Create: %-8d\r\n", cookie, bplus_create_entry);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -            Remove: %-8d\r\n", cookie, bplus_remove_entry);
+    StringCbPrintfA(output, sizeof(output), "%s -            Remove: %-8d\r\n", cookie, bplus_remove_entry);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -        Build Tree: %-8d\r\n", cookie, bplus_build_tree);
+    StringCbPrintfA(output, sizeof(output), "%s -        Build Tree: %-8d\r\n", cookie, bplus_build_tree);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -         Free Tree: %-8d\r\n", cookie, bplus_free_tree);
+    StringCbPrintfA(output, sizeof(output), "%s -         Free Tree: %-8d\r\n", cookie, bplus_free_tree);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -          DV Error: %-8d\r\n", cookie, bplus_dv_error);
+    StringCbPrintfA(output, sizeof(output), "%s -          DV Error: %-8d\r\n", cookie, bplus_dv_error);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
-    sprintf(output, "%s - B+ Time    Lookup: %-16I64d\r\n", cookie, bplus_lookup_time);
+    StringCbPrintfA(output, sizeof(output), "%s - B+ Time    Lookup: %-16I64d\r\n", cookie, bplus_lookup_time);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -            Create: %-16I64d\r\n", cookie, bplus_create_time);
+    StringCbPrintfA(output, sizeof(output), "%s -            Create: %-16I64d\r\n", cookie, bplus_create_time);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -            Remove: %-16I64d\r\n", cookie, bplus_remove_time);
+    StringCbPrintfA(output, sizeof(output), "%s -            Remove: %-16I64d\r\n", cookie, bplus_remove_time);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -             Build: %-16I64d\r\n", cookie, bplus_build_time);
+    StringCbPrintfA(output, sizeof(output), "%s -             Build: %-16I64d\r\n", cookie, bplus_build_time);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    sprintf(output, "%s -              Free: %-16I64d\r\n", cookie, bplus_free_time);
+    StringCbPrintfA(output, sizeof(output), "%s -              Free: %-16I64d\r\n", cookie, bplus_free_time);
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
     return(0);
@@ -2096,7 +2147,7 @@ cm_BPlusEnumAlloc(afs_uint32 entries)
 
 long 
 cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked, 
-                     char * maskp, cm_direnum_t **enumpp)
+                     clientchar_t * maskp, cm_direnum_t **enumpp)
 {
     afs_uint32 count = 0, slot, numentries;
     Nptr leafNode = NONODE, nextLeafNode;
@@ -2123,16 +2174,17 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
            firstDataNode = getnode(leafNode, slot);
 
            for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
+
+                /* There can be two data nodes for one file.  One for
+                   the long name and one for the short name.  We only
+                   include one of these for the enumeration */
+
                 if (maskp == NULL) {
-                    /* name is in getdatakey(dataNode) */
-                    if (getdatavalue(dataNode).longname != NULL ||
-                        cm_Is8Dot3(getdatakey(dataNode).name))
+                    if (!getdatavalue(dataNode).shortform)
                         count++;
                 } else {
-                   if (cm_Is8Dot3(getdatakey(dataNode).name) && 
-                        smb_V3MatchMask(getdatakey(dataNode).name, maskp, CM_FLAG_CASEFOLD) ||
-                        getdatavalue(dataNode).longname == NULL &&
-                        smb_V3MatchMask(getdatavalue(dataNode).longname, maskp, CM_FLAG_CASEFOLD))
+                   if (!getdatavalue(dataNode).shortform &&
+                        cm_MatchMask(getdatavalue(dataNode).cname, maskp, CM_FLAG_CASEFOLD))
                         count++;
                 }
                nextDataNode = getdatanext(dataNode);
@@ -2140,9 +2192,9 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
        }
 
        nextLeafNode = getnextnode(leafNode);
-    }   
+    }
 
-    sprintf(buffer, "BPlusTreeEnumerate count = %d", count);
+    StringCbPrintfA(buffer, sizeof(buffer), "BPlusTreeEnumerate count = %d", count);
     osi_Log1(afsd_logp, "BPlus: %s", osi_LogSaveString(afsd_logp, buffer));
 
     /* Allocate the enumeration object */
@@ -2152,55 +2204,53 @@ cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked,
        rc = ENOMEM;
        goto done;
     }
-       
-    /* Copy the name and fid for each longname entry into the enumeration */
+
+    /* Copy the name and fid for each cname entry into the enumeration */
     for (count = 0, leafNode = getleaf(scp->dirBplus); leafNode; leafNode = nextLeafNode) {
 
        for ( slot = 1, numentries = numentries(leafNode); slot <= numentries; slot++) {
            firstDataNode = getnode(leafNode, slot);
 
            for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
-                char * name;
-                int hasShortName;
+                clientchar_t * name;
                 int includeIt = 0;
 
                 if (maskp == NULL) {
-                    if (getdatavalue(dataNode).longname != NULL ||
-                         cm_Is8Dot3(getdatakey(dataNode).name)) 
-                    {
+                    if (!getdatavalue(dataNode).shortform) {
                         includeIt = 1;
                     }
                 } else {
-                   if (cm_Is8Dot3(getdatakey(dataNode).name) && 
-                        smb_V3MatchMask(getdatakey(dataNode).name, maskp, CM_FLAG_CASEFOLD) ||
-                        getdatavalue(dataNode).longname == NULL &&
-                         smb_V3MatchMask(getdatavalue(dataNode).longname, maskp, CM_FLAG_CASEFOLD)) 
-                    {
+                   if (!getdatavalue(dataNode).shortform &&
+                        cm_MatchMask(getdatavalue(dataNode).cname, maskp, CM_FLAG_CASEFOLD)) {
                         includeIt = 1;
                     }
                 }
 
                 if (includeIt) {
-                    if (getdatavalue(dataNode).longname) {
-                        name = strdup(getdatavalue(dataNode).longname);
-                        hasShortName = 1;
-                    } else {
-                        name = strdup(getdatakey(dataNode).name);
-                        hasShortName = 0;
-                    }
+                    name = cm_ClientStrDup(getdatavalue(dataNode).cname);
 
                     if (name == NULL) {
                         osi_Log0(afsd_logp, "cm_BPlusDirEnumerate strdup failed");
                         rc = ENOMEM;
                         goto done;
                     }
+
                     enump->entry[count].name = name;
                     enump->entry[count].fid  = getdatavalue(dataNode).fid;
-                    if (hasShortName)
-                        strncpy(enump->entry[count].shortName, getdatakey(dataNode).name, 
-                                sizeof(enump->entry[count].shortName));
-                    else
-                        enump->entry[count].shortName[0] = '\0';
+
+                    if (!cm_Is8Dot3(name)) {
+                        cm_dirFid_t dfid;
+
+                        dfid.vnode = htonl(getdatavalue(dataNode).fid.vnode);
+                        dfid.unique = htonl(getdatavalue(dataNode).fid.unique);
+
+                        cm_Gen8Dot3NameIntW(name, &dfid, enump->entry[count].shortName, NULL);
+                    } else {
+                        StringCbCopyW(enump->entry[count].shortName,
+                                      sizeof(enump->entry[count].shortName),
+                                      name);
+                    }
+
                     count++;
                 }
                nextDataNode = getdatanext(dataNode);
@@ -2315,7 +2365,7 @@ cm_BPlusDirEnumTest(cm_scache_t * dscp, afs_uint32 locked)
                 cm_ReleaseSCache(scp);
            }
 
-           sprintf(buffer, "'%s' Fid = (%d,%d,%d,%d) Short = '%s' Type %s DV %I64d",
+           StringCbPrintfA(buffer, sizeof(buffer), "'%S' Fid = (%d,%d,%d,%d) Short = '%S' Type %s DV %I64d",
                    entryp->name,
                    entryp->fid.cell, entryp->fid.volume, entryp->fid.vnode, entryp->fid.unique,
                    entryp->shortName,
index 3e37191..e19b1da 100644 (file)
 typedef struct node    *Nptr;
 
 typedef struct key {
-    char *name;
+    normchar_t  *name;           /* Normalized name */
 } keyT;
 
-
 typedef struct dirdata {
     cm_fid_t    fid;
-    char * longname;
-    char * origname;
+    int         shortform;      /* This is the short form entry.  If
+                                   this value is non-zero, then there
+                                   is another entry in the B-Plus tree
+                                   corresponding to the long name of
+                                   this fid. */
+    clientchar_t  *cname;          /* Client name (long) */
+    fschar_t * fsname;         /* FileServer name */
 } dataT;
 
 typedef struct entry {
@@ -138,20 +142,20 @@ Nptr      lookup(Tree *B, keyT key);
 
 /******************* cache manager directory operations ***************/
 
-int  cm_BPlusDirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid);
-int  cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, char * entry, char ** originalNameRetp);
-long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid);
-int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry);
+int  cm_BPlusCompareNormalizedKeys(keyT key1, keyT key2, int flags);
+int  cm_BPlusDirLookup(cm_dirOp_t * op, clientchar_t *entry, cm_fid_t * cfid);
+int  cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, clientchar_t *entry, fschar_t **originalNameRetp);
+long cm_BPlusDirCreateEntry(cm_dirOp_t * op, clientchar_t *entry, cm_fid_t * cfid);
+int  cm_BPlusDirDeleteEntry(cm_dirOp_t * op, clientchar_t *entry);
 long cm_BPlusDirBuildTree(cm_scache_t *scp, cm_user_t *userp, cm_req_t* reqp);
 void cm_BPlusDumpStats(void);
-int cm_MemDumpBPlusStats(FILE *outputFile, char *cookie, int lock);
-
+int  cm_MemDumpBPlusStats(FILE *outputFile, char *cookie, int lock);
 
 /******************* directory enumeration operations ****************/
 typedef struct cm_direnum_entry {
-    char *     name;
-    cm_fid_t   fid;
-    char        shortName[13];
+    clientchar_t *name;
+    cm_fid_t    fid;
+    normchar_t   shortName[13];
 } cm_direnum_entry_t;
 
 typedef struct cm_direnum {
@@ -160,7 +164,7 @@ typedef struct cm_direnum {
     cm_direnum_entry_t         entry[1];
 } cm_direnum_t;
 
-long cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked, char *maskp, cm_direnum_t **enumpp);
+long cm_BPlusDirEnumerate(cm_scache_t *scp, afs_uint32 locked, clientchar_t *maskp, cm_direnum_t **enumpp);
 long cm_BPlusDirNextEnumEntry(cm_direnum_t *enump, cm_direnum_entry_t **entrypp);
 long cm_BPlusDirFreeEnumeration(cm_direnum_t *enump);
 long cm_BPlusDirEnumTest(cm_scache_t * dscp, afs_uint32 locked);
@@ -182,7 +186,7 @@ extern afs_uint64 bplus_free_time;
 /* access keys and pointers in a node */
 #define getkey(j, q) (nAdr(j).e[(q)].key)
 #define getnode(j, q) (nAdr(j).e[(q)].downNode)
-#define setkey(j, q, v) ((q > 0) ? nAdr(j).e[(q)].key.name = strdup((v).name) : NULL)
+#define setkey(j, q, v) ((q > 0) ? nAdr(j).e[(q)].key.name = cm_NormStrDup((v).name) : NULL)
 #define setnode(j, q, v) (nAdr(j).e[(q)].downNode = (v))
 
 /* access tree flag values */
index 683b152..09d49ed 100644 (file)
@@ -203,6 +203,8 @@ extern long buf_CleanDirtyBuffers(cm_scache_t *scp);
 
 extern long buf_ForceDataVersion(cm_scache_t * scp, afs_uint64 fromVersion, afs_uint64 toVersion);
 
+extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
+
 /* error codes */
 #define CM_BUF_EXISTS  1       /* buffer exists, and shouldn't */
 #endif /*  _BUF_H__ENV_ */
index 1649423..ffa1306 100644 (file)
@@ -18,6 +18,7 @@
 #include <stdlib.h>
 
 #include "afsd.h"
+#include "smb.h"
 #include <osi.h>
 #include <rx_pthread.h>
 
@@ -744,8 +745,10 @@ SRXAFSCB_GetCE(struct rx_call *callp, long index, AFSDBCacheEntry *cep)
             cep->cbExpires = volp->cbExpiresRO;
             cm_PutVolume(volp);
         }
-    } else
-        cep->cbExpires = scp->cbExpires;
+    } else {
+        /* TODO: deal with time_t below */
+        cep->cbExpires = (afs_int32) scp->cbExpires;
+    }
     cep->refCount = scp->refCount;
     cep->opens = scp->openReads;
     cep->writers = scp->openWrites;
@@ -859,8 +862,10 @@ SRXAFSCB_GetCE64(struct rx_call *callp, long index, AFSDBCacheEntry64 *cep)
             cep->cbExpires = volp->cbExpiresRO;
             cm_PutVolume(volp);
         }
-    } else
-        cep->cbExpires = scp->cbExpires;
+    } else {
+        /* TODO: handle time_t */
+        cep->cbExpires = (afs_int32) scp->cbExpires;
+    }
     cep->refCount = scp->refCount;
     cep->opens = scp->openReads;
     cep->writers = scp->openWrites;
@@ -1313,8 +1318,7 @@ int SRXAFSCB_GetLocalCell(struct rx_call *callp, char **a_name)
              ntohl(host), ntohs(port));
 
     if (cm_data.rootCellp) {
-       t_name = (char *)malloc(strlen(cm_data.rootCellp->name)+1);
-        strcpy(t_name, cm_data.rootCellp->name);
+        t_name = strdup(cm_data.rootCellp->name);
     } else {
        t_name = (char *)malloc(1);
        t_name[0] = '\0';
index 6220592..30121f3 100644 (file)
@@ -39,16 +39,16 @@ typedef struct cm_conn {
  * to the cache manager functions.
  */
 typedef struct cm_req {
-       DWORD startTime;                /* Quit before RDR times us out */
-       int rpcError;                   /* RPC error code */
-       int volumeError;                /* volume error code */
-       int accessError;                /* access error code */
-        struct cm_server * tokenIdleErrorServp;  /* server that reported a token/idle error other than expired */
-        int tokenError;
-        int idleError;
-       afs_uint32 flags;
-        char * tidPathp;
-        char * relPathp;
+    DWORD startTime;           /* Quit before RDR times us out */
+    int rpcError;                      /* RPC error code */
+    int volumeError;           /* volume error code */
+    int accessError;           /* access error code */
+    struct cm_server * tokenIdleErrorServp;  /* server that reported a token/idle error other than expired */
+    int tokenError;
+    int idleError;
+    afs_uint32 flags;
+    clientchar_t * tidPathp;
+    clientchar_t * relPathp;
 } cm_req_t;
 
 /* flags in cm_req structure */
index 7cb8afc..bcecf59 100644 (file)
@@ -105,27 +105,27 @@ InsertEntry(cm_nc_t *tnc)
 
 void 
 cm_dnlcEnter ( cm_scache_t *adp,
-               char        *aname,
+               normchar_t  *nname,
                cm_scache_t *avc )
 {
     cm_nc_t *tnc;
     unsigned int key, skey, new=0;
-    char *ts = aname;
+    normchar_t *ts = nname;
     int safety;
     int writeLocked = 0;
 
     if (!cm_useDnlc)
        return ;
 
-    if (!strcmp(aname,".") || !strcmp(aname,".."))
+    if (!cm_NormStrCmp(nname,_C(".")) || !cm_NormStrCmp(nname,_C("..")))
        return ;
 
     if ( cm_debugDnlc ) 
-       osi_Log3(afsd_logp,"cm_dnlcEnter dir %x name %s scache %x", 
-           adp, osi_LogSaveString(afsd_logp,aname), avc);
+       osi_Log3(afsd_logp,"cm_dnlcEnter dir %x name %S scache %x", 
+           adp, osi_LogSaveStringW(afsd_logp,nname), avc);
 
     dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
-    if (ts - aname >= CM_AFSNCNAMESIZE) 
+    if (ts - nname >= CM_AFSNCNAMESIZE) 
        return ;
     skey = key & (NHSIZE -1);
 
@@ -133,7 +133,7 @@ cm_dnlcEnter ( cm_scache_t *adp,
     lock_ObtainRead(&cm_dnlcLock);
   retry:
     for (tnc = cm_data.nameHash[skey], safety=0; tnc; tnc = tnc->next, safety++ )
-       if ((tnc->dirp == adp) && (!strcmp(tnc->name, aname)))
+       if ((tnc->dirp == adp) && (!cm_NormStrCmp(tnc->name, nname)))
            break;                              /* preexisting entry */
        else if ( tnc->next == cm_data.nameHash[skey])  /* end of list */
        {
@@ -169,10 +169,10 @@ cm_dnlcEnter ( cm_scache_t *adp,
        tnc->dirp = adp;
        tnc->vp = avc;
        tnc->key = key;
-       memcpy (tnc->name, aname, ts-aname+1); /* include the NULL */
+       memcpy (tnc->name, nname, (ts-nname+1)*sizeof(normchar_t)); /* include the NULL */
 
        if ( new )      /* insert entry only if it is newly created */ 
-               InsertEntry(tnc);
+            InsertEntry(tnc);
 
     }
     if (writeLocked)
@@ -192,8 +192,8 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
 {
     cm_scache_t * tvc;
     unsigned int key, skey;
-    char* aname = sp->searchNamep;
-    char *ts = aname;
+    normchar_t* nname = sp->nsearchNamep;
+    normchar_t *ts = nname;
     cm_nc_t * tnc, * tnc_begin;
     int safety, match;
   
@@ -201,12 +201,12 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
        return NULL;
 
     if ( cm_debugDnlc ) 
-       osi_Log2(afsd_logp, "cm_dnlcLookup dir %x name %s", 
-               adp, osi_LogSaveString(afsd_logp,aname));
+       osi_Log2(afsd_logp, "cm_dnlcLookup dir %x name %S", 
+               adp, osi_LogSaveStringW(afsd_logp,nname));
 
     dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
 
-    if (ts - aname >= CM_AFSNCNAMESIZE) {
+    if (ts - nname >= CM_AFSNCNAMESIZE) {
         InterlockedIncrement(&dnlcstats.lookups);
         InterlockedIncrement(&dnlcstats.misses);
        return NULL;
@@ -225,26 +225,26 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
        if (tnc->dirp == adp) 
        {
         if( cm_debugDnlc ) 
-            osi_Log1(afsd_logp,"Looking at [%s]",
-                     osi_LogSaveString(afsd_logp,tnc->name));
+            osi_Log1(afsd_logp,"Looking at [%S]",
+                     osi_LogSaveStringW(afsd_logp,tnc->name));
 
            if ( sp->caseFold )         /* case insensitive */
            {
-            match = cm_stricmp_utf8(tnc->name, aname);
+            match = cm_NormStrCmpI(tnc->name, nname);
             if ( !match )      /* something matches */
             {
                 tvc = tnc->vp;
                 ts = tnc->name;
 
                 /* determine what type of match it is */
-                if ( !strcmp(tnc->name, aname))
+                if ( !cm_NormStrCmp(tnc->name, nname))
                 {      
                     /* exact match. */
                     sp->ExactFound = 1;
 
                     if( cm_debugDnlc )
-                        osi_Log1(afsd_logp,"DNLC found exact match [%s]",
-                                 osi_LogSaveString(afsd_logp,tnc->name));
+                        osi_Log1(afsd_logp,"DNLC found exact match [%S]",
+                                 osi_LogSaveStringW(afsd_logp,tnc->name));
                     break;
                 }
                 else if ( cm_NoneUpper(tnc->name))
@@ -258,7 +258,7 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
            }
            else                        /* case sensitive */
            {
-            match = strcmp(tnc->name, aname);
+            match = cm_NormStrCmp(tnc->name, nname);
             if ( !match ) /* found a match */
             {
                 sp->ExactFound = 1;
@@ -285,9 +285,9 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
     }
 
     if(cm_debugDnlc && ts) {
-        osi_Log3(afsd_logp, "DNLC matched [%s] for [%s] with vnode[%ld]",
-                 osi_LogSaveString(afsd_logp,ts),
-                 osi_LogSaveString(afsd_logp,aname),
+        osi_Log3(afsd_logp, "DNLC matched [%S] for [%W] with vnode[%ld]",
+                 osi_LogSaveStringW(afsd_logp,ts),
+                 osi_LogSaveStringW(afsd_logp,nname),
                  (long) tvc->fid.vnode);
     }
 
@@ -337,22 +337,22 @@ RemoveEntry (cm_nc_t *tnc, unsigned int key)
 
 
 void 
-cm_dnlcRemove (cm_scache_t *adp, char *aname)
+cm_dnlcRemove (cm_scache_t *adp, normchar_t *nname)
 {
     unsigned int key, skey, error=0;
     int found= 0, safety;
-    char *ts = aname;
+    normchar_t *ts = nname;
     cm_nc_t *tnc, *tmp;
   
     if (!cm_useDnlc)
        return ;
 
     if ( cm_debugDnlc )
-       osi_Log2(afsd_logp, "cm_dnlcRemove dir %x name %s", 
-               adp, osi_LogSaveString(afsd_logp,aname));
+       osi_Log2(afsd_logp, "cm_dnlcRemove dir %x name %S", 
+               adp, osi_LogSaveStringW(afsd_logp,nname));
 
     dnlcHash( ts, key );  /* leaves ts pointing at the NULL */
-    if (ts - aname >= CM_AFSNCNAMESIZE) 
+    if (ts - nname >= CM_AFSNCNAMESIZE) 
        return ;
 
     skey = key & (NHSIZE -1);
@@ -362,7 +362,7 @@ cm_dnlcRemove (cm_scache_t *adp, char *aname)
     for (tnc = cm_data.nameHash[skey], safety=0; tnc; safety++) 
     {
        if ( (tnc->dirp == adp) && (tnc->key == key) 
-                       && !strcmp(tnc->name,aname) )
+             && !cm_NormStrCmp(tnc->name,nname) )
        {
            tmp = tnc->next;
            error = RemoveEntry(tnc, skey);
index c1c0ba3..d8a8890 100644 (file)
@@ -20,7 +20,7 @@ typedef struct nc {
     unsigned int key;
     struct nc *next, *prev;
     cm_scache_t *dirp, *vp;
-    unsigned char name[CM_AFSNCNAMESIZE];   
+    normchar_t name[CM_AFSNCNAMESIZE];   
 } cm_nc_t;
 
 typedef struct {
@@ -29,12 +29,12 @@ typedef struct {
     afs_int32 cycles, lookuprace;
 } cm_dnlcstats_t;
 
-#define dnlcHash(ts, hval) for (hval=0; *ts; ts++) {    \
-                                hval *= 173;            \
-                                hval += cm_foldUpper[(unsigned char)(*ts)]; \
-                           }
-extern void cm_dnlcEnter(cm_scache_t *adp, char *name, cm_scache_t *avc);
-extern void cm_dnlcRemove(cm_scache_t *adp, char *name);
+#define dnlcHash(ts, hval) for (hval=0; *ts; ts++) {                    \
+        hval *= 173;                                                    \
+        hval += cm_NormCharUpr(*ts);                                   \
+    }
+extern void cm_dnlcEnter(cm_scache_t *adp, normchar_t *name, cm_scache_t *avc);
+extern void cm_dnlcRemove(cm_scache_t *adp, normchar_t *name);
 extern void cm_dnlcPurgedp(cm_scache_t *adp);
 extern void cm_dnlcPurgevp(cm_scache_t *avc);
 extern void cm_dnlcPurge(void);
index 2cd822f..ee92c6e 100644 (file)
@@ -14,8 +14,8 @@
 #include <windows.h>
 #include <winsock2.h>
 #include "cm_dns_private.h"
-#include "cm_dns.h"
 #include "cm_nls.h"
+#include "cm_dns.h"
 #include <lwp.h>
 #include <afs/afsint.h>
 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
@@ -23,6 +23,7 @@
 #define DNSAPI_ENV
 #endif
 #include <errno.h>
+#include <strsafe.h>
 
 /*extern void afsi_log(char *pattern, ...);*/
 
@@ -31,51 +32,56 @@ static int cm_dnsEnabled = -1;
 
 void DNSlowerCase(char *str)
 {
-  int i;
+    unsigned int i;
 
-  for (i=0; i<strlen(str); i++)
-    /*str[i] = tolower(str[i]);*/
-    if (str[i] >= 'A' && str[i] <= 'Z')
-      str[i] += 'a' - 'A';
+    for (i=0; i<strlen(str); i++)
+        /*str[i] = tolower(str[i]);*/
+        if (str[i] >= 'A' && str[i] <= 'Z')
+            str[i] += 'a' - 'A';
 }
 
 int cm_InitDNS(int enabled)
 {
 #ifndef DNSAPI_ENV
-  char configpath[100];
-  int len;
-  int code;
-  char *addr;
-  
-  if (!enabled) { fprintf(stderr, "DNS support disabled\n"); cm_dnsEnabled = 0; return 0; }
-
-  /* First try AFS_NS environment var. */
-  addr = getenv("AFS_NS");
-  if (addr && inet_addr(addr) != -1) {
-    strcpy(dns_addr, addr);
-  } else {
-    /* Now check for the AFSDNS.INI file */
-    code = GetWindowsDirectory(configpath, sizeof(configpath));
-    if (code == 0 || code > sizeof(configpath)) return -1;
-    strcat(configpath, "\\afsdns.ini");
-
-    /* Currently we only get (and query) the first nameserver.  Getting
-       list of mult. nameservers should be easy to do. */
-    len = GetPrivateProfileString("AFS Domain Name Servers", "ns1", NULL,
-                           dns_addr, sizeof(dns_addr),
-                           configpath);
-  
-    if (len == 0 || inet_addr(dns_addr) == -1) {
-      fprintf(stderr, "No valid name server addresses found, DNS lookup is "
-                      "disabled\n");
-      cm_dnsEnabled = 0;  /* failed */
-      return -1;     /* No name servers defined */
+    char configpath[100];
+    int len;
+    int code;
+    char *addr;
+  
+    if (!enabled) { 
+        fprintf(stderr, "DNS support disabled\n"); 
+        cm_dnsEnabled = 0; 
+        return 0; 
+    }
+
+    /* First try AFS_NS environment var. */
+    addr = getenv("AFS_NS");
+    if (addr && inet_addr(addr) != -1) {
+        strcpy(dns_addr, addr);
+    } else {
+        /* Now check for the AFSDNS.INI file */
+        code = GetWindowsDirectory(configpath, sizeof(configpath));
+        if (code == 0 || code > sizeof(configpath)) return -1;
+        strcat(configpath, "\\afsdns.ini");
+
+        /* Currently we only get (and query) the first nameserver.  Getting
+        list of mult. nameservers should be easy to do. */
+        len = GetPrivateProfileString("AFS Domain Name Servers", "ns1", NULL,
+                                       dns_addr, sizeof(dns_addr),
+                                       configpath);
+  
+        if (len == 0 || inet_addr(dns_addr) == -1) {
+            fprintf(stderr, "No valid name server addresses found, DNS lookup is "
+                     "disabled\n");
+            cm_dnsEnabled = 0;  /* failed */
+            return -1;     /* No name servers defined */
+        }
+        else 
+            fprintf(stderr, "Found DNS server %s\n", dns_addr);
     }
-    else fprintf(stderr, "Found DNS server %s\n", dns_addr);
-  }
 #endif /* DNSAPI_ENV */
-  cm_dnsEnabled = 1;
-  return 0;
+    cm_dnsEnabled = 1;
+    return 0;
 }
 
 #ifndef DNSAPI_ENV
@@ -618,72 +624,67 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
                  int *numServers, int *ttl)
 {
 #ifndef DNSAPI_ENV
-   /*static AFS_SRV_LIST srvList;
-    static int ans = 0;*/
-  SOCKET commSock;
-  SOCKADDR_IN sockAddr;
-  PDNS_HDR  pDNShdr;
-  char buffer[BUFSIZE];
-  char query[1024];
-  int rc;
+    SOCKET commSock;
+    SOCKADDR_IN sockAddr;
+    PDNS_HDR  pDNShdr;
+    char buffer[BUFSIZE];
+    char query[1024];
+    int rc;
 
 #ifdef DEBUG
-  fprintf(stderr, "getAFSServer: cell %s, cm_dnsEnabled=%d\n", cellName, cm_dnsEnabled);
+    fprintf(stderr, "getAFSServer: cell %s, cm_dnsEnabled=%d\n", cellName, cm_dnsEnabled);
 #endif
 
 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-  if (cm_dnsEnabled == -1) { /* not yet initialized, eg when called by klog */
-    cm_InitDNS(1);    /* assume enabled */
-  }
+    if (cm_dnsEnabled == -1) { /* not yet initialized, eg when called by klog */
+        cm_InitDNS(1);         /* assume enabled */
+    }
 #endif
-  if (cm_dnsEnabled == 0) {  /* possibly we failed in cm_InitDNS above */
-    fprintf(stderr, "DNS initialization failed, disabled\n");
-    *numServers = 0;
-    return -1;
-  }
+    if (cm_dnsEnabled == 0) {  /* possibly we failed in cm_InitDNS above */
+        fprintf(stderr, "DNS initialization failed, disabled\n");
+        *numServers = 0;
+        return -1;
+    }
   
-  sockAddr = setSockAddr(dns_addr, DNS_PORT);
+    sockAddr = setSockAddr(dns_addr, DNS_PORT);
   
-  commSock = socket( AF_INET, SOCK_DGRAM, 0 );
-  if ( commSock < 0 )
+    commSock = socket( AF_INET, SOCK_DGRAM, 0 );
+    if ( commSock < 0 )
     {
-      /*afsi_log("socket() failed\n");*/
-      fprintf(stderr, "getAFSServer: socket() failed, errno=%d\n", errno);
-      *numServers = 0;
-      return (-1);
+        /*afsi_log("socket() failed\n");*/
+        fprintf(stderr, "getAFSServer: socket() failed, errno=%d\n", errno);
+        *numServers = 0;
+        return (-1);
     } 
-  
-  strncpy(query, cellName, 1024);
-  query[1023] = 0;
-  if (query[strlen(query)-1] != '.') {
-    strncat(query,".",1024);
-    query[1023] = 0;
-  }
 
-  rc = send_DNS_AFSDB_Query(cellName,commSock,sockAddr, buffer);
-  if (rc < 0) {
-    fprintf(stderr,"getAFSServer: send_DNS_AFSDB_Query failed\n");
-    *numServers = 0;
-    return -1;
-  }
+    StringCbCopyA(query, sizeof(query), cellName);
+    if (query[strlen(query)-1] != '.') {
+        StringCbCatA(query, sizeof(query), ".");
+    }
+
+    rc = send_DNS_AFSDB_Query(cellName,commSock,sockAddr, buffer);
+    if (rc < 0) {
+        fprintf(stderr,"getAFSServer: send_DNS_AFSDB_Query failed\n");
+        *numServers = 0;
+        return -1;
+    }
     
-  pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
-  
-  /*printReplyBuffer_AFSDB(pDNShdr);*/
-  if (pDNShdr)
-    processReplyBuffer_AFSDB(commSock, pDNShdr, cellHostAddrs, cellHostNames, numServers, ttl);
-  else
-    *numServers = 0;
+    pDNShdr = get_DNS_Response(commSock,sockAddr, buffer);
   
-  closesocket(commSock);
-  if (*numServers == 0)
-    return(-1);
+    /*printReplyBuffer_AFSDB(pDNShdr);*/
+    if (pDNShdr)
+        processReplyBuffer_AFSDB(commSock, pDNShdr, cellHostAddrs, cellHostNames, numServers, ttl);
+    else
+        *numServers = 0;
 
-  else
-    return 0;
+    closesocket(commSock);
+    if (*numServers == 0)
+        return(-1);
+    else
+        return 0;
 #else /* DNSAPI_ENV */
     PDNS_RECORD pDnsCell, pDnsIter, pDnsVol,pDnsVolIter, pDnsCIter;
-    DWORD i;
+    int i;
     struct sockaddr_in vlSockAddr;
     char query[1024];
 
@@ -696,22 +697,20 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
     *ttl = 0;
 
     /* query the AFSDB records of cell */
-    strncpy(query, cellName, 1024);
-    query[1023] = 0;
+    StringCbCopyA(query, sizeof(query), cellName);
     if (query[strlen(query)-1] != '.') {
-        strncat(query,".",1024);
-        query[1023] = 0;
+        StringCbCatA(query, sizeof(query), ".");
     }
 
     if (DnsQuery_A(query, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, &pDnsCell, NULL) == ERROR_SUCCESS) {
         memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
-               
+
         /* go through the returned records */
         for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
             /* if we find an AFSDB record with Preference set to 1, we found a volserver */
             if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
-                strncpy(cellHostNames[*numServers], pDnsIter->Data.Afsdb.pNameExchange, MAXHOSTCHARS);
-                cellHostNames[*numServers][MAXHOSTCHARS-1]='\0';
+                StringCbCopyA(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
+                              pDnsIter->Data.Afsdb.pNameExchange);
                 (*numServers)++;
                 
                 if (!*ttl) 
@@ -731,7 +730,7 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
                 for (i=0;i<*numServers;i++)
                     if(cm_stricmp_utf8(pDnsIter->pName, cellHostNames[i]) == 0)
                         cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
-        }       
+        }
 
         for (i=0;i<*numServers;i++) {
             /* if we don't have an IP yet, then we should try resolving the volserver hostname
@@ -771,4 +770,100 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
         return -1;
 #endif /* DNSAPI_ENV */
 }
+
+int getAFSServerW(cm_unichar_t *cellName, int *cellHostAddrs,
+                  cm_unichar_t cellHostNames[][MAXHOSTCHARS], 
+                  int *numServers, int *ttl)
+{
+#ifdef DNSAPI_ENV
+    PDNS_RECORDW pDnsCell, pDnsIter, pDnsVol,pDnsVolIter, pDnsCIter;
+    int i;
+    struct sockaddr_in vlSockAddr;
+    cm_unichar_t query[1024];
+
+#ifdef AFS_FREELANCE_CLIENT
+    if ( cm_stricmp_utf16(cellName, L"Freelance.Local.Root") == 0 )
+        return -1;
+#endif /* AFS_FREELANCE_CLIENT */
+
+    *numServers = 0; 
+    *ttl = 0;
+
+    /* query the AFSDB records of cell */
+    StringCbCopyW(query, sizeof(query), cellName);
+    if (query[wcslen(query)-1] != L'.') {
+        StringCbCatW(query, sizeof(query), L".");
+    }
+
+    if (DnsQuery_W(query, DNS_TYPE_AFSDB, DNS_QUERY_STANDARD, NULL, (PDNS_RECORD *) &pDnsCell,
+                   NULL) == ERROR_SUCCESS) {
+        memset((void*) &vlSockAddr, 0, sizeof(vlSockAddr));
+
+        /* go through the returned records */
+        for (pDnsIter = pDnsCell;pDnsIter; pDnsIter = pDnsIter->pNext) {
+            /* if we find an AFSDB record with Preference set to 1, we found a volserver */
+            if (pDnsIter->wType == DNS_TYPE_AFSDB && pDnsIter->Data.Afsdb.wPreference == 1) {
+                StringCbCopyW(cellHostNames[*numServers], sizeof(cellHostNames[*numServers]),
+                              pDnsIter->Data.Afsdb.pNameExchange);
+                (*numServers)++;
+                
+                if (!*ttl) 
+                    *ttl = pDnsIter->dwTtl;
+                if (*numServers == AFSMAXCELLHOSTS) 
+                    break;
+            }
+        }
+
+        for (i=0;i<*numServers;i++) 
+            cellHostAddrs[i] = 0;
+
+        /* now check if there are any A records in the results */
+        for (pDnsIter = pDnsCell; pDnsIter; pDnsIter = pDnsIter->pNext) {
+            if(pDnsIter->wType == DNS_TYPE_A)
+                /* check if its for one of the volservers */
+                for (i=0;i<*numServers;i++)
+                    if(cm_stricmp_utf16(pDnsIter->pName, cellHostNames[i]) == 0)
+                        cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
+        }
+
+        for (i=0;i<*numServers;i++) {
+            /* if we don't have an IP yet, then we should try resolving the volserver hostname
+               in a separate query. */
+            if (!cellHostAddrs[i]) {
+                if (DnsQuery_W(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL,
+                               (PDNS_RECORD *) &pDnsVol, NULL) == ERROR_SUCCESS) {
+                    for (pDnsVolIter = pDnsVol; pDnsVolIter; pDnsVolIter=pDnsVolIter->pNext) {
+                        /* if we get an A record, keep it */
+                        if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
+                            cellHostAddrs[i] = pDnsVolIter->Data.A.IpAddress;
+                            break;
+                        }
+                        /* if we get a CNAME, look for a corresponding A record */
+                        if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf16(cellHostNames[i], pDnsVolIter->pName)==0) {
+                            for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
+                                if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf16(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
+                                    cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
+                                    break;
+                                }
+                            }
+                            if (cellHostAddrs[i]) 
+                                break;
+                            /* TODO: if the additional section is missing, then do another lookup for the CNAME */
+                        }
+                    }
+                    /* we are done with the volserver lookup */
+                    DnsRecordListFree((PDNS_RECORD) pDnsVol, DnsFreeRecordListDeep);
+                }
+            }
+        }
+        DnsRecordListFree((PDNS_RECORD) pDnsCell, DnsFreeRecordListDeep);
+    }
+
+    if ( *numServers > 0 )
+        return 0;
+    else        
+#endif  /* DNSAPI_ENV */
+        return -1;
+}
 #endif /* AFS_AFSDB_ENV */
+
index 6bfa381..ed41d9c 100644 (file)
    names for the given cell, ending in null */
 int getAFSServer(char *cellname, int *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], int *numServers, int *ttl);
 
+/* Same as above, but using cm_unichar_t.  Note that this functon will
+   only be defined for DNSAPI_ENV. */
+int getAFSServerW(cm_unichar_t *cellName, int *cellHostAddrs,
+                  cm_unichar_t cellHostNames[][MAXHOSTCHARS], 
+                  int *numServers, int *ttl);
+
 /* a supplement for the DJGPP gethostbyname ... which 
    never bothers calling a DNS server ... so this function
    takes care of that. This should be called when you
index fcb20b0..3457bb1 100644 (file)
@@ -54,6 +54,7 @@ osi_mutex_t cm_Afsdsbmt_Lock;
 
 extern afs_int32 cryptall;
 extern char cm_NetbiosName[];
+extern clientchar_t cm_NetbiosNameC[];
 
 extern void afsi_log(char *pattern, ...);
 
@@ -211,22 +212,86 @@ TranslateExtendedChars(char *str)
     if (!str || !*str)
         return;
 
-    CharToOem(str, str);
+    CharToOemA(str, str);
 }
 
-
-/*
- * Utility function.
- * If the IoctlPath is not parsed then it must be skipped.
- */
-void 
-cm_SkipIoctlPath(cm_ioctl_t *ioctlp)
+void cm_SkipIoctlPath(cm_ioctl_t *ioctlp)
 {
     size_t temp;
-        
+
     temp = strlen(ioctlp->inDatap) + 1;
     ioctlp->inDatap += temp;
-}       
+}
+
+
+clientchar_t * cm_ParseIoctlStringAlloc(cm_ioctl_t *ioctlp, const char * ext_instrp)
+{
+    clientchar_t * rs = NULL;
+    const char * instrp;
+
+    instrp = (ext_instrp)?ext_instrp:ioctlp->inDatap;
+
+    if ((ioctlp->flags & CM_IOCTLFLAG_USEUTF8) == CM_IOCTLFLAG_USEUTF8) {
+        rs = cm_Utf8ToClientStringAlloc(instrp, -1, NULL);
+    } else {
+        int cch;
+
+        /* Not a UTF-8 string */
+        if (smb_StoreAnsiFilenames) {
+            cch = cm_AnsiToClientString(instrp, -1, NULL, 0);
+#ifdef DEBUG
+            osi_assert(cch > 0);
+#endif
+            rs = malloc(cch * sizeof(clientchar_t));
+            cm_AnsiToClientString(instrp, -1, rs, cch);
+        } else {
+            cch = cm_OemToClientString(instrp, -1, NULL, 0);
+#ifdef DEBUG
+            osi_assert(cch > 0);
+#endif
+            rs = malloc(cch * sizeof(clientchar_t));
+            cm_OemToClientString(instrp, -1, rs, cch);
+        }
+    }
+
+    if (ext_instrp == NULL) {
+        ioctlp->inDatap += strlen(ioctlp->inDatap) + 1;
+    }
+    return rs;
+}
+
+int cm_UnparseIoctlString(cm_ioctl_t *ioctlp,
+                          char * ext_outp,
+                          const clientchar_t * cstr, int cchlen)
+{
+    char *outp;
+    int cchout;
+
+    outp = ((ext_outp == NULL)? ioctlp->outDatap : ext_outp);
+
+    if ((ioctlp->flags & CM_IOCTLFLAG_USEUTF8) == CM_IOCTLFLAG_USEUTF8) {
+        cchout = cm_ClientStringToUtf8(cstr, cchlen, outp,
+                                       SMB_IOCTL_MAXDATA - (outp - ioctlp->outAllocp));
+    } else {
+        if (smb_StoreAnsiFilenames) {
+            cchout = WideCharToMultiByte(CP_ACP, 0, cstr, cchlen,
+                                         outp,
+                                         SMB_IOCTL_MAXDATA - (outp - ioctlp->outAllocp),
+                                         NULL, NULL);
+        } else {
+            cchout = WideCharToMultiByte(CP_OEMCP, 0, cstr, cchlen,
+                                         outp,
+                                         SMB_IOCTL_MAXDATA - (outp - ioctlp->outAllocp),
+                                         NULL, NULL);
+        }
+    }
+
+    if (cchout > 0 && ext_outp == NULL) {
+        ioctlp->outDatap += cchout;
+    }
+
+    return cchout;
+}
 
 /* 
  * Must be called before XXX_ParseIoctlPath or cm_SkipIoctlPath 
@@ -267,34 +332,35 @@ cm_IoctlSkipQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp)
  * the AFS path that should be written into afsdsbmt.ini).
  */
 void 
-cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp)
+cm_NormalizeAfsPath(clientchar_t *outpathp, long cchlen, clientchar_t *inpathp)
 {
-    char *cp;
-    char bslash_mountRoot[256];
+    clientchar_t *cp;
+    clientchar_t bslash_mountRoot[256];
        
-    strncpy(bslash_mountRoot, cm_mountRoot, sizeof(bslash_mountRoot) - 1);
+    cm_ClientStrCpy(bslash_mountRoot, lengthof(bslash_mountRoot), cm_mountRootC);
     bslash_mountRoot[0] = '\\';
-       
-    if (!strnicmp (inpathp, cm_mountRoot, strlen(cm_mountRoot)))
-        StringCbCopy(outpathp, outlen, inpathp);
-    else if (!strnicmp (inpathp, bslash_mountRoot, strlen(bslash_mountRoot)))
-        StringCbCopy(outpathp, outlen, inpathp);
+
+    if (!cm_ClientStrCmpNI(inpathp, cm_mountRootC, cm_mountRootCLen))
+        cm_ClientStrCpy(outpathp, cchlen, inpathp);
+    else if (!cm_ClientStrCmpNI(inpathp, bslash_mountRoot,
+                                cm_ClientStrLen(bslash_mountRoot)))
+        cm_ClientStrCpy(outpathp, cchlen, inpathp);
     else if ((inpathp[0] == '/') || (inpathp[0] == '\\'))
-        StringCbPrintfA(outpathp, outlen, "%s%s", cm_mountRoot, inpathp);
+        cm_ClientStrPrintfN(outpathp, cchlen, _C("%s%s"), cm_mountRootC, inpathp);
     else // inpathp looks like "<cell>/usr"
-        StringCbPrintfA(outpathp, outlen, "%s/%s", cm_mountRoot, inpathp);
+        cm_ClientStrPrintfN(outpathp, cchlen, _C("%s/%s"), cm_mountRootC, inpathp);
 
     for (cp = outpathp; *cp != 0; ++cp) {
         if (*cp == '\\')
             *cp = '/';
-    }       
+    }
 
-    if (strlen(outpathp) && (outpathp[strlen(outpathp)-1] == '/')) {
-        outpathp[strlen(outpathp)-1] = 0;
+    if (cm_ClientStrLen(outpathp) && (outpathp[cm_ClientStrLen(outpathp)-1] == '/')) {
+        outpathp[cm_ClientStrLen(outpathp)-1] = 0;
     }
 
-    if (!strcmpi (outpathp, cm_mountRoot)) {
-        StringCbCopy(outpathp, outlen, cm_mountRoot);
+    if (!cm_ClientStrCmpI(outpathp, cm_mountRootC)) {
+        cm_ClientStrCpy(outpathp, cchlen, cm_mountRootC);
     }
 }
 
@@ -379,11 +445,13 @@ cm_IoctlGetFileCellName(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scach
     {
         cellp = cm_FindCellByID(scp->fid.cell, CM_FLAG_NOPROBE);
         if (cellp) {
-            StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cellp->name);
-            ioctlp->outDatap += strlen(ioctlp->outDatap) + 1;
+            clientchar_t * cellname;
+
+            cellname = cm_FsStringToClientStringAlloc(cellp->name, -1, NULL); 
+            cm_UnparseIoctlString(ioctlp, NULL, cellname, -1);
+            free(cellname);
             code = 0;
-        }
-        else 
+        } else
             code = CM_ERROR_NOSUCHCELL;
     }
 
@@ -539,10 +607,10 @@ cm_IoctlSetVolumeStatus(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scach
     AFSFetchVolumeStatus volStat;
     AFSStoreVolumeStatus storeStat;
     cm_volume_t *tvp;
-    char *cp;
     cm_cell_t *cellp;
+    char *cp;
+    clientchar_t *strp;
     struct rx_connection * callp;
-    int len;
 
 #ifdef AFS_FREELANCE_CLIENT
     if ( scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID ) {
@@ -564,20 +632,23 @@ cm_IoctlSetVolumeStatus(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scach
         cm_PutVolume(tvp);
 
         /* Copy the junk out, using cp as a roving pointer. */
-        cp = ioctlp->inDatap;
-        memcpy((char *)&volStat, cp, sizeof(AFSFetchVolumeStatus));
-        cp += sizeof(AFSFetchVolumeStatus);
+        memcpy((char *)&volStat, ioctlp->inDatap, sizeof(AFSFetchVolumeStatus));
+        ioctlp->inDatap += sizeof(AFSFetchVolumeStatus);
+
+        strp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
+        cm_ClientStringToFsString(strp, -1, volName, lengthof(volName));
+        free(strp);
 
-        len = strlen(cp) + 1;
-        cm_NormalizeUtf8String(cp, len, volName, sizeof(volName));
-        cp += len;
+        strp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
+        cm_ClientStringToFsString(strp, -1, offLineMsg, lengthof(offLineMsg));
+        free(strp);
 
-        len = strlen(cp) + 1;
-        cm_NormalizeUtf8String(cp, len, offLineMsg, sizeof(offLineMsg));
-        cp +=  len;
+        strp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
+        cm_ClientStringToFsString(strp, -1, motd, lengthof(motd));
+        free(strp);
+
+        strp = NULL;
 
-        len = strlen(cp) + 1;
-        cm_NormalizeUtf8String(cp, len, motd, sizeof(motd));
         storeStat.Mask = 0;
         if (volStat.MinQuota != -1) {
             storeStat.MinQuota = volStat.MinQuota;
@@ -595,7 +666,7 @@ cm_IoctlSetVolumeStatus(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scach
 
             callp = cm_GetRxConn(tcp);
             code = RXAFS_SetVolumeStatus(callp, scp->fid.volume,
-                                          &storeStat, volName, offLineMsg, motd);
+                                         &storeStat, volName, offLineMsg, motd);
             rx_PutConnection(callp);
 
         } while (cm_Analyze(tcp, userp, reqp, &scp->fid, NULL, NULL, NULL, code));
@@ -882,13 +953,12 @@ cm_IoctlStatMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache
 {
     afs_int32 code;
     cm_scache_t *scp;
-    char *cp;
-
-    cp = ioctlp->inDatap;
+    clientchar_t *cp;
 
+    cp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
     if (code) 
-        return code;
+        goto done_2;
 
     lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, reqp, 0,
@@ -906,16 +976,21 @@ cm_IoctlStatMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache
 
     code = cm_ReadMountPoint(scp, userp, reqp);
     if (code == 0) {
-        cp = ioctlp->outDatap;
-        StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), scp->mountPointStringp);
-        cp += strlen(cp) + 1;
-        ioctlp->outDatap = cp;
+        char * strp;
+        strp = ioctlp->outDatap;
+        StringCbCopyA(strp, SMB_IOCTL_MAXDATA - (strp - ioctlp->outAllocp), scp->mountPointStringp);
+        strp += strlen(strp) + 1;
+        ioctlp->outDatap = strp;
     }
 
   done:
     lock_ReleaseWrite(&scp->rw);
     cm_ReleaseSCache(scp);
 
+ done_2:
+    if (cp)
+        free(cp);
+
     return code;
 }       
 
@@ -930,11 +1005,11 @@ cm_IoctlDeleteMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scac
 {
     afs_int32 code;
     cm_scache_t *scp;
-    char *cp;
-    char *originalName = NULL;
+    clientchar_t *cp = NULL;
+    fschar_t *originalName = NULL;
     cm_dirOp_t dirop;
 
-    cp = ioctlp->inDatap;
+    cp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
 
     code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
         
@@ -944,7 +1019,7 @@ cm_IoctlDeleteMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scac
         
     lock_ObtainWrite(&scp->rw);
     code = cm_SyncOp(scp, NULL, userp, reqp, 0,
-                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+                     CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     if (code)  
         goto done2;
 
@@ -973,15 +1048,15 @@ cm_IoctlDeleteMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scac
        the file server. */
 
     if (originalName == NULL) {
-        originalName = cp;
+        originalName = cm_ClientStringToFsStringAlloc(cp, -1, NULL);
     }
 
     /* cp is a normalized name.  originalName is the actual name we
        saw on the fileserver. */
 #ifdef AFS_FREELANCE_CLIENT
     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
-        /* we are adding the mount point to the root dir., so call
-         * the freelance code to do the add. */
+        /* we are removing the mount point to the root dir., so call
+         * the freelance code to do the deletion. */
         osi_Log0(afsd_logp,"IoctlDeleteMountPoint from Freelance root dir");
         code = cm_FreelanceRemoveMount(originalName);
     } else 
@@ -992,13 +1067,8 @@ cm_IoctlDeleteMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scac
     }
     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
         smb_NotifyChange(FILE_ACTION_REMOVED,
-                          FILE_NOTIFY_CHANGE_DIR_NAME,
-                          dscp, cp, NULL, TRUE);
-
-    if (originalName != NULL && originalName != cp) {
-        free(originalName);
-        originalName = NULL;
-    }
+                         FILE_NOTIFY_CHANGE_DIR_NAME,
+                         dscp, cp, NULL, TRUE);
 
     lock_ObtainWrite(&scp->rw);
   done1:
@@ -1010,6 +1080,12 @@ cm_IoctlDeleteMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scac
     cm_ReleaseSCache(scp);
 
   done3:
+    if (originalName != NULL)
+        free(originalName);
+
+    if (cp != NULL)
+        free(cp);
+
     return code;
 }
 
@@ -1055,7 +1131,7 @@ cm_IoctlCheckServers(struct cm_ioctl *ioctlp, struct cm_user *userp)
         ioctlp->inDatap = cp = ioctlp->inDatap + sizeof(long);
         if (cp - ioctlp->inAllocp < ioctlp->inCopied)  /* still more data available */
             haveCell = 1;
-    }       
+    }
 
     /* 
      * 1: fast check, don't contact servers.
@@ -1067,18 +1143,18 @@ cm_IoctlCheckServers(struct cm_ioctl *ioctlp, struct cm_user *userp)
         if (!cellp) 
             return CM_ERROR_NOSUCHCELL;
     }
-    else cellp = (cm_cell_t *) 0;
+    else 
+        cellp = (cm_cell_t *) 0;
     if (!cellp && (temp & 2)) {
         /* use local cell */
-        char wscell[CELL_MAXNAMELEN+1];
+        fschar_t wscell[CELL_MAXNAMELEN+1];
         cm_GetRootCellName(wscell);
         cellp = cm_GetCell(wscell, 0);
     }
     if (!(temp & 1)) { /* if not fast, call server checker routine */
         /* check down servers */
-        cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS,
-                         cellp);
-    }       
+        cm_CheckServers(CM_FLAG_CHECKDOWNSERVERS | CM_FLAG_CHECKUPSERVERS, cellp);
+    }
 
     /* now return the current down server list */
     cp = ioctlp->outDatap;
@@ -1087,7 +1163,7 @@ cm_IoctlCheckServers(struct cm_ioctl *ioctlp, struct cm_user *userp)
         if (cellp && tsp->cellp != cellp) 
             continue;  /* cell spec'd and wrong */
         if ((tsp->flags & CM_SERVERFLAG_DOWN)
-             && tsp->type == CM_SERVER_FILE) {
+            && tsp->type == CM_SERVER_FILE) {
             memcpy(cp, (char *)&tsp->addr.sin_addr.s_addr, sizeof(long));
             cp += sizeof(long);
         }
@@ -1246,6 +1322,7 @@ cm_IoctlGetCell(struct cm_ioctl *ioctlp, struct cm_user *userp)
     lock_ReleaseRead(&cm_cellLock);
     if (tcellp) {
         int max = 8;
+        clientchar_t * cellnamep;
 
         cp = ioctlp->outDatap;
 
@@ -1264,10 +1341,11 @@ cm_IoctlGetCell(struct cm_ioctl *ioctlp, struct cm_user *userp)
             cp += sizeof(long);
         }
         lock_ReleaseRead(&cm_serverLock);
-        cp = basep + max * sizeof(afs_int32);
-        StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), tcellp->name);
-        cp += strlen(tcellp->name)+1;
-        ioctlp->outDatap = cp;
+        ioctlp->outDatap = basep + max * sizeof(afs_int32);
+
+        cellnamep = cm_FsStringToClientStringAlloc(tcellp->name, -1, NULL);
+        cm_UnparseIoctlString(ioctlp, NULL, cellnamep, -1);
+        free(cellnamep);
     }
 
     if (tcellp) 
@@ -1352,9 +1430,10 @@ cm_IoctlGetWsCell(cm_ioctl_t *ioctlp, cm_user_t *userp)
             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), "Freelance.Local.Root");
         ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
     } else if (cm_data.rootCellp) {
+        clientchar_t * cellnamep = cm_FsStringToClientStringAlloc(cm_data.rootCellp->name, -1, NULL);
         /* return the default cellname to the caller */
-        StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), cm_data.rootCellp->name);
-        ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
+        cm_UnparseIoctlString(ioctlp, NULL, cellnamep, -1);
+        free(cellnamep);
     } else {
         /* if we don't know our default cell, return failure */
         code = CM_ERROR_NOSUCHCELL;
@@ -1371,21 +1450,22 @@ cm_IoctlGetWsCell(cm_ioctl_t *ioctlp, cm_user_t *userp)
 afs_int32 
 cm_IoctlSysName(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    afs_uint32 setSysName, foundname = 0;
-    char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
-    int t, count, num = 0;
-    char **sysnamelist[MAXSYSNAME];
-        
+    afs_uint32 setSysName;
+    char *cp, *cp2;
+    clientchar_t *inname = NULL;
+    int t, count;
+
     memcpy(&setSysName, ioctlp->inDatap, sizeof(afs_uint32));
     ioctlp->inDatap += sizeof(afs_uint32);
-        
+
     if (setSysName) {
         /* check my args */
         if ( setSysName < 0 || setSysName > MAXNUMSYSNAMES )
             return EINVAL;
         cp2 = ioctlp->inDatap;
         for ( cp=ioctlp->inDatap, count = 0; count < setSysName; count++ ) {
-            /* won't go past end of ioctlp->inDatap since maxsysname*num < ioctlp->inDatap length */
+            /* won't go past end of ioctlp->inDatap since
+               maxsysname*num < ioctlp->inDatap length */
             t = (int)strlen(cp);
             if (t >= MAXSYSNAME || t <= 0)
                 return EINVAL;
@@ -1398,64 +1478,59 @@ cm_IoctlSysName(struct cm_ioctl *ioctlp, struct cm_user *userp)
 
         /* inname gets first entry in case we're being a translator */
         /* (we are never a translator) */
-        t = (int)strlen(ioctlp->inDatap);
-        memcpy(inname, ioctlp->inDatap, t + 1);
-        ioctlp->inDatap += t + 1;
-        num = count;
+        inname = cm_ParseIoctlStringAlloc(ioctlp, NULL);
     }
 
     /* Not xlating, so local case */
     if (!cm_sysName)
         osi_panic("cm_IoctlSysName: !cm_sysName\n", __FILE__, __LINE__);
 
-    if (!setSysName) {      /* user just wants the info */
-        StringCbCopyA(outname, sizeof(outname), cm_sysName);
-        foundname = cm_sysNameCount;
-        *sysnamelist = cm_sysNameList;
-    } else {        
+    if (setSysName) {
         /* Local guy; only root can change sysname */
         /* clear @sys entries from the dnlc, once afs_lookup can
          * do lookups of @sys entries and thinks it can trust them */
         /* privs ok, store the entry, ... */
-        StringCbCopyA(cm_sysName, sizeof(cm_sysName), inname);
-        StringCbCopyA(cm_sysNameList[0], MAXSYSNAME, inname);
+
+        cm_ClientStrCpy(cm_sysName, lengthof(cm_sysName), inname);
+        cm_ClientStrCpy(cm_sysNameList[0], MAXSYSNAME, inname);
+
         if (setSysName > 1) {       /* ... or list */
-            cp = ioctlp->inDatap;
             for (count = 1; count < setSysName; ++count) {
+                clientchar_t * newsysname;
+
                 if (!cm_sysNameList[count])
                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to write\n",
-                               __FILE__, __LINE__);
-                t = (int)strlen(cp);
-                StringCbCopyA(cm_sysNameList[count], MAXSYSNAME, cp);
-                cp += t + 1;
+                              __FILE__, __LINE__);
+
+                newsysname = cm_ParseIoctlStringAlloc(ioctlp, NULL);
+                cm_ClientStrCpy(cm_sysNameList[count], MAXSYSNAME, newsysname);
+                free(newsysname);
             }
         }
         cm_sysNameCount = setSysName;
-    }
+    } else {
+        afs_int32 i32;
 
-    if (!setSysName) {
         /* return the sysname to the caller */
-        cp = ioctlp->outDatap;
-        memcpy(cp, (char *)&foundname, sizeof(afs_int32));
-        cp += sizeof(afs_int32);       /* skip found flag */
-        if (foundname) {
-            StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), outname);
-            cp += strlen(outname) + 1; /* skip name and terminating null char */
-            for ( count=1; count < foundname ; ++count) {   /* ... or list */
-                if ( !(*sysnamelist)[count] )
+        i32 = cm_sysNameCount;
+        memcpy(ioctlp->outDatap, &i32, sizeof(afs_int32));
+        ioctlp->outDatap += sizeof(afs_int32); /* skip found flag */
+
+        if (cm_sysNameCount) {
+            for ( count=0; count < cm_sysNameCount ; ++count) {   /* ... or list */
+                if ( !cm_sysNameList[count] || *cm_sysNameList[count] == _C('\0'))
                     osi_panic("cm_IoctlSysName: no cm_sysNameList entry to read\n", 
-                               __FILE__, __LINE__);
-                t = (int)strlen((*sysnamelist)[count]);
-                if (t >= MAXSYSNAME)
-                    osi_panic("cm_IoctlSysName: sysname entry garbled\n", 
-                               __FILE__, __LINE__);
-                StringCbCopyA(cp, SMB_IOCTL_MAXDATA - (cp - ioctlp->outAllocp), (*sysnamelist)[count]);
-                cp += t + 1;
+                              __FILE__, __LINE__);
+                cm_UnparseIoctlString(ioctlp, NULL, cm_sysNameList[count], -1);
             }
         }
-        ioctlp->outDatap = cp;
     }
-        
+
+    if (inname) {
+        free(inname);
+        inname = NULL;
+    }
+
     /* done: success */
     return 0;
 }
@@ -1470,8 +1545,15 @@ cm_IoctlGetCellStatus(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
     afs_uint32 temp;
     cm_cell_t *cellp;
+    clientchar_t * cellnamep;
+    fschar_t     * fscellnamep;
+
+    cellnamep = cm_ParseIoctlStringAlloc(ioctlp, NULL);
+    fscellnamep = cm_ClientStringToFsStringAlloc(cellnamep, -1, NULL);
+    cellp = cm_GetCell(fscellnamep, 0);
+    free(fscellnamep);
+    free(cellnamep);
 
-    cellp = cm_GetCell(ioctlp->inDatap, 0);
     if (!cellp) 
         return CM_ERROR_NOSUCHCELL;
 
@@ -1480,7 +1562,7 @@ cm_IoctlGetCellStatus(struct cm_ioctl *ioctlp, struct cm_user *userp)
     if (cellp->flags & CM_CELLFLAG_SUID)
         temp |= CM_SETCELLFLAG_SUID;
     lock_ReleaseMutex(&cellp->mx);
-        
+
     /* now copy out parm */
     memcpy(ioctlp->outDatap, &temp, sizeof(afs_uint32));
     ioctlp->outDatap += sizeof(afs_uint32);
@@ -1496,17 +1578,24 @@ cm_IoctlGetCellStatus(struct cm_ioctl *ioctlp, struct cm_user *userp)
 afs_int32 
 cm_IoctlSetCellStatus(struct cm_ioctl *ioctlp, struct cm_user *userp)
 {
-    afs_uint32 temp;
+    afs_uint32 flags;
     cm_cell_t *cellp;
+    clientchar_t *temp;
+    fschar_t * cellnamep;
+
+    temp = cm_ParseIoctlStringAlloc(ioctlp, ioctlp->inDatap + 2*sizeof(afs_uint32));
+    cellnamep = cm_ClientStringToFsStringAlloc(temp, -1, NULL);
+    cellp = cm_GetCell(cellnamep, 0);
+    free(temp);
+    free(cellnamep);
 
-    cellp = cm_GetCell(ioctlp->inDatap + 2*sizeof(afs_uint32), 0);
     if (!cellp) 
         return CM_ERROR_NOSUCHCELL;
 
-    memcpy((char *)&temp, ioctlp->inDatap, sizeof(afs_uint32));
+    memcpy((char *)&flags, ioctlp->inDatap, sizeof(afs_uint32));
 
     lock_ObtainMutex(&cellp->mx);
-    if (temp & CM_SETCELLFLAG_SUID)
+    if (flags & CM_SETCELLFLAG_SUID)
         cellp->flags |= CM_CELLFLAG_SUID;
     else
         cellp->flags &= ~CM_CELLFLAG_SUID;
@@ -1635,22 +1724,20 @@ cm_IoctlGetSPrefs(struct cm_ioctl *ioctlp, struct cm_user *userp)
  * dscp is held but not locked.
  */
 afs_int32
-cm_IoctlCreateMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp, char *leaf)
+cm_IoctlCreateMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp, clientchar_t *leaf)
 {
     afs_int32 code;
     cm_attr_t tattr;
-    char *cp;
-    char mpInfo[256];
-    char fullCell[256];
-    char volume[256];
-    char cell[256];
+    clientchar_t *cp;
+    fschar_t mpInfo[512];           /* mount point string */
+    fschar_t fullCell[MAXCELLCHARS];
+    fschar_t *fscell = NULL;
+    fschar_t *fsvolume = NULL;
+    clientchar_t volume[VL_MAXNAMELEN];
+    clientchar_t *mpp = NULL;
+    clientchar_t *cell = NULL;
     int ttl;
 
-    /* Translate chars for the mount point name */
-    if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
-        TranslateExtendedChars(leaf);
-    }
-
    /* 
      * The fs command allows the user to specify partial cell names on NT.  These must
      * be expanded to the full cell name for mount points so that the mount points will
@@ -1658,37 +1745,46 @@ cm_IoctlCreateMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scac
      */
 
     /* Extract the possibly partial cell name */
-    StringCbCopyA(cell, sizeof(cell), ioctlp->inDatap + 1);      /* Skip the mp type character */
-        
-    if (cp = strchr(cell, ':')) {
+    mpp = cm_ParseIoctlStringAlloc(ioctlp, NULL);
+    cell = cm_ClientCharNext(mpp);
+    if (cp = cm_ClientStrChr(cell, ':')) {
+
         /* Extract the volume name */
         *cp = 0;
-        StringCbCopyA(volume,  sizeof(volume), cp + 1);
-       
+        cm_ClientStrCpy(volume, lengthof(volume), cm_ClientCharNext(cp));
+
+        fscell = cm_ClientStringToFsStringAlloc(cell, -1, NULL);
+        fsvolume = cm_ClientStringToFsStringAlloc(volume, -1, NULL);
+
         /* Get the full name for this cell */
-        code = cm_SearchCellFile(cell, fullCell, 0, 0);
+        code = cm_SearchCellFile(fscell, fullCell, 0, 0);
 #ifdef AFS_AFSDB_ENV
         if (code && cm_dnsEnabled)
-            code = cm_SearchCellByDNS(cell, fullCell, &ttl, 0, 0);
+            code = cm_SearchCellByDNS(fscell, fullCell, &ttl, 0, 0);
 #endif
         if (code) {
-            return CM_ERROR_NOSUCHCELL;
+            code = CM_ERROR_NOSUCHCELL;
+            goto done;
         }
-       
-        StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", *ioctlp->inDatap, fullCell, volume);
+
+        StringCbPrintfA(mpInfo, sizeof(mpInfo), "%c%s:%s", (char) *mpp,
+                        fullCell, fsvolume);
+
     } else {
-        /* No cell name specified */
-        StringCbCopyA(mpInfo, sizeof(mpInfo), ioctlp->inDatap);
+        /* No cell name specified, so cell points at the volume instead. */
+        fsvolume = cm_ClientStringToFsStringAlloc(cell, -1, NULL);
+        cm_ClientStringToFsString(mpp, -1, mpInfo, lengthof(mpInfo));
     }
 
 #ifdef AFS_FREELANCE_CLIENT
     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
-        /* we are adding the mount point to the root dir., so call
+        /* we are adding the mount point to the root dir, so call
          * the freelance code to do the add. */
+        fschar_t * fsleaf = cm_ClientStringToFsStringAlloc(leaf, -1, NULL);
         osi_Log0(afsd_logp,"IoctlCreateMountPoint within Freelance root dir");
-        code = cm_FreelanceAddMount(leaf, fullCell, volume, 
-                                    *ioctlp->inDatap == '%', NULL);
-    } else 
+        code = cm_FreelanceAddMount(fsleaf, fullCell, fsvolume, *mpInfo == '%', NULL);
+        free(fsleaf);
+    } else
 #endif
     {
         /* create the symlink with mode 644.  The lack of X bits tells
@@ -1706,6 +1802,14 @@ cm_IoctlCreateMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scac
                          FILE_NOTIFY_CHANGE_DIR_NAME,
                          dscp, leaf, NULL, TRUE);
 
+  done:
+    if (mpp)
+        free(mpp);
+    if (fscell)
+        free(fscell);
+    if (fsvolume)
+        free(fsvolume);
+
     return code;
 }
 
@@ -1716,7 +1820,7 @@ cm_IoctlCreateMountPoint(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scac
  * dscp is held but not locked.
  */
 afs_int32 
-cm_IoctlSymlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp, char *leaf)
+cm_IoctlSymlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp, cm_req_t *reqp, clientchar_t *leaf)
 {
     afs_int32 code;
     cm_attr_t tattr;
@@ -1725,41 +1829,18 @@ cm_IoctlSymlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dsc
     int free_syml = FALSE;
 
     if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
-        /* Translate chars for the link name */
-        TranslateExtendedChars(leaf);
-
         /* Translate chars for the linked to name */
         TranslateExtendedChars(ioctlp->inDatap);
     }
 
-    symlp = ioctlp->inDatap;           /* contents of link */
-
-    {
-        char * normalized;
-        int normalized_len;
-
-        int len = strlen(symlp) + 1;
-
-        normalized_len = cm_NormalizeUtf8String(symlp, len, NULL, 0);
-        if (normalized_len > len) {
-            normalized = malloc(normalized_len);
-            free_syml = TRUE;
-        } else {
-            normalized = symlp;
-        }
-
-        cm_NormalizeUtf8String(symlp, len, normalized, normalized_len);
-
-        if (symlp != normalized)
-            symlp = normalized;
-    }
-
-    cp = symlp;
+    cp = symlp = ioctlp->inDatap;              /* contents of link */
 
 #ifdef AFS_FREELANCE_CLIENT
     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
         /* we are adding the symlink to the root dir., so call
          * the freelance code to do the add. */
+        fschar_t *fsleaf;
+
         if (cp[0] == cp[1] && cp[1] == '\\' && 
             !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName))) 
         {
@@ -1770,8 +1851,11 @@ cm_IoctlSymlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dsc
                 p += 4;
             cp = p;
         }
+
         osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir");
-        code = cm_FreelanceAddSymlink(leaf, cp, NULL);
+        fsleaf = cm_ClientStringToFsStringAlloc(leaf, -1, NULL);
+        code = cm_FreelanceAddSymlink(fsleaf, cp, NULL);
+        free(fsleaf);
     } else
 #endif
     {
@@ -1787,10 +1871,6 @@ cm_IoctlSymlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dsc
                           FILE_NOTIFY_CHANGE_FILE_NAME
                           | FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, leaf, NULL, TRUE);
-
-    if (free_syml)
-        free(symlp);
-
     return code;
 }
 
@@ -1809,6 +1889,7 @@ cm_IoctlListlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *ds
     char *cp;
     cm_space_t *spacep;
     cm_scache_t *newRootScp;
+    clientchar_t *clientp;
 
     if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
         /* Translate chars for the link name */
@@ -1816,7 +1897,9 @@ cm_IoctlListlink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *ds
     }
     cp = ioctlp->inDatap;
 
-    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
+    code = cm_Lookup(dscp, clientp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    free(clientp);
     if (code) 
         return code;
 
@@ -1871,6 +1954,7 @@ cm_IoctlIslink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp
     afs_int32 code;
     cm_scache_t *scp;
     char *cp;
+    clientchar_t *clientp;
 
     if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
         /* Translate chars for the link name */
@@ -1879,7 +1963,9 @@ cm_IoctlIslink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *dscp
     cp = ioctlp->inDatap;
     osi_LogEvent("cm_IoctlListlink",NULL," name[%s]",cp);
 
-    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
+    code = cm_Lookup(dscp, clientp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    free(clientp);
     if (code)
         return code;
 
@@ -1906,6 +1992,7 @@ cm_IoctlDeletelink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *
     char *cp;
     char * originalName = NULL;
     cm_dirOp_t dirop;
+    clientchar_t *clientp;
 
     if (!(ioctlp->flags & CM_IOCTLFLAG_USEUTF8)) {
         /* Translate chars for the link name */
@@ -1913,8 +2000,9 @@ cm_IoctlDeletelink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *
     }
     cp = ioctlp->inDatap;
 
-    code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
-        
+    clientp = cm_Utf8ToClientStringAlloc(cp, -1, NULL);
+    code = cm_Lookup(dscp, clientp, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+
     /* if something went wrong, bail out now */
     if (code)
         goto done3;
@@ -1939,7 +2027,7 @@ cm_IoctlDeletelink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *
 #ifdef USE_BPLUS
     code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
     if (code == 0) {
-        code = cm_BPlusDirLookupOriginalName(&dirop, cp, &originalName);
+        code = cm_BPlusDirLookupOriginalName(&dirop, clientp, &originalName);
         /* cm_Dir*() functions can't be used to lookup the original
            name since those functions only know of the original
            name. */
@@ -1968,13 +2056,13 @@ cm_IoctlDeletelink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *
 #endif
     {
         /* easier to do it this way */
-        code = cm_Unlink(dscp, originalName, cp, userp, reqp);
+        code = cm_Unlink(dscp, originalName, clientp, userp, reqp);
     }
     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
         smb_NotifyChange(FILE_ACTION_REMOVED,
                           FILE_NOTIFY_CHANGE_FILE_NAME
                           | FILE_NOTIFY_CHANGE_DIR_NAME,
-                          dscp, cp, NULL, TRUE);
+                          dscp, clientp, NULL, TRUE);
 
     if (originalName != NULL && originalName != cp) {
         free(originalName);
@@ -1991,6 +2079,8 @@ cm_IoctlDeletelink(struct cm_ioctl *ioctlp, struct cm_user *userp, cm_scache_t *
     cm_ReleaseSCache(scp);
 
   done3:
+    free(clientp);
+
     return code;
 }
 
@@ -2494,7 +2584,6 @@ cm_IoctlMakeSubmount(cm_ioctl_t *ioctlp, cm_user_t *userp)
     /* Parse the input parameters--first the required afs path,
      * then the requested submount name (which may be "").
      */
-    cm_NormalizeAfsPath (afspath, sizeof(afspath), ioctlp->inDatap);
     submountreqp = ioctlp->inDatap + (strlen(ioctlp->inDatap)+1);
 
     /* If the caller supplied a suggested submount name, see if
@@ -2513,7 +2602,6 @@ cm_IoctlMakeSubmount(cm_ioctl_t *ioctlp, cm_user_t *userp)
                     NULL );
 
     if (submountreqp && *submountreqp) {
-        char submountPathNormalized[MAX_PATH];
         char submountPath[MAX_PATH];
 
         dwSize = sizeof(submountPath);
@@ -2545,8 +2633,7 @@ cm_IoctlMakeSubmount(cm_ioctl_t *ioctlp, cm_user_t *userp)
          * supplied path matches the submount's path, we can still
          * use the suggested submount name.
          */
-        cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
-        if (!strcmp (submountPathNormalized, afspath)) {
+        if (!strcmp (submountPath, afspath)) {
             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountreqp);
             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
             RegCloseKey( hkSubmounts );
@@ -2579,7 +2666,6 @@ cm_IoctlMakeSubmount(cm_ioctl_t *ioctlp, cm_user_t *userp)
     nextAutoSubmount = 1;
 
     for ( dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
-        char submountPathNormalized[MAX_PATH];
         char submountPath[MAX_PATH] = "";
         DWORD submountPathLen = sizeof(submountPath);
         char submountName[MAX_PATH];
@@ -2614,8 +2700,7 @@ cm_IoctlMakeSubmount(cm_ioctl_t *ioctlp, cm_user_t *userp)
          * that our caller specified. If so, we can return
          * this submount.
          */
-        cm_NormalizeAfsPath (submountPathNormalized, sizeof(submountPathNormalized), submountPath);
-        if (!strcmp (submountPathNormalized, afspath)) {
+        if (!strcmp (submountPath, afspath)) {
             StringCbCopyA(ioctlp->outDatap, SMB_IOCTL_MAXDATA - (ioctlp->outDatap - ioctlp->outAllocp), submountName);
             ioctlp->outDatap += strlen(ioctlp->outDatap) +1;
             RegCloseKey(hkSubmounts);
@@ -2804,7 +2889,6 @@ cm_IoctlUUIDControl(struct cm_ioctl * ioctlp, struct cm_user *userp)
  */
 extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
 extern int cm_DumpBufHashTable(FILE *outputFile, char *cookie, int lock);
-extern int smb_DumpVCP(FILE *outputFile, char *cookie, int lock);
 
 /* 
  * VIOC_TRACEMEMDUMP internals.
@@ -3078,5 +3162,3 @@ cm_IoctlVolStatTest(struct cm_ioctl *ioctlp, struct cm_user *userp)
 
     return code;
 }       
-
-
index bb188f2..c2ab26a 100644 (file)
@@ -117,9 +117,9 @@ typedef struct cm_IoctlQueryOptions {
 
 #define MAXNUMSYSNAMES    16      /* max that current constants allow */
 #define   MAXSYSNAME      128     /* max sysname (i.e. @sys) size */
-extern char *         cm_sysName;
+extern clientchar_t  *cm_sysName;
 extern unsigned int   cm_sysNameCount;
-extern char *         cm_sysNameList[MAXNUMSYSNAMES];
+extern clientchar_t  *cm_sysNameList[MAXNUMSYSNAMES];
 
 /* Paths that are passed into pioctl calls can be specified using
    UTF-8.  These strings are prefixed with UTF8_PREFIX defined below.
@@ -143,14 +143,21 @@ extern void cm_InitIoctl(void);
 
 extern void cm_ResetACLCache(cm_user_t *userp);
 
-extern cm_ioctlQueryOptions_t * cm_IoctlGetQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp);
+extern cm_ioctlQueryOptions_t *
+cm_IoctlGetQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp);
 
-extern void cm_IoctlSkipQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp);
+extern void
+cm_IoctlSkipQueryOptions(struct cm_ioctl *ioctlp, struct cm_user *userp);
 
-extern void cm_NormalizeAfsPath(char *outpathp, long outlen, char *inpathp);
+extern void
+cm_NormalizeAfsPath(clientchar_t *outpathp, long outlen, clientchar_t *inpathp);
 
 extern void cm_SkipIoctlPath(cm_ioctl_t *ioctlp);
 
+extern clientchar_t * cm_ParseIoctlStringAlloc(cm_ioctl_t *ioctlp, const char * ext_instrp);
+
+extern int cm_UnparseIoctlString(cm_ioctl_t *ioctlp, char * ext_outp, const clientchar_t * cstr, int cchlen);
+
 extern afs_int32 cm_IoctlGetACL(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
 extern afs_int32 cm_IoctlGetFileCellName(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
@@ -205,7 +212,7 @@ extern afs_int32 cm_IoctlGetSPrefs(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
 extern afs_int32 cm_IoctlStoreBehind(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern afs_int32 cm_IoctlCreateMountPoint(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp, char *leaf);
+extern afs_int32 cm_IoctlCreateMountPoint(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp, clientchar_t *leaf);
 
 extern afs_int32 cm_CleanFile(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
 
@@ -227,7 +234,7 @@ extern afs_int32 cm_IoctlDelToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
 extern afs_int32 cm_IoctlDelAllToken(cm_ioctl_t *ioctlp, cm_user_t *userp);
 
-extern afs_int32 cm_IoctlSymlink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp, char *leaf);
+extern afs_int32 cm_IoctlSymlink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *dscp, cm_req_t *reqp, clientchar_t *leaf);
 
 extern afs_int32 cm_IoctlIslink(cm_ioctl_t *ioctlp, cm_user_t *userp, cm_scache_t *scp, cm_req_t *reqp);
 
@@ -263,6 +270,8 @@ extern afs_int32 cm_IoctlVolStatTest(struct cm_ioctl *ioctlp, struct cm_user *us
 
 extern afs_int32 cm_IoctlUnicodeControl(struct cm_ioctl *ioctlp, struct cm_user * userp);
 
+extern void TranslateExtendedChars(char *str);
+
 #endif /* __CM_IOCTL_INTERFACES_ONLY__ */
 
 #endif /*  __CM_IOCTL_H_ENV__ */
index cdeb9e3..0e9e48c 100644 (file)
 #include <strsafe.h>
 #include <errno.h>
 
-#define DEBUG_UNICODE
+#include "cm_nls.h"
+
+#ifdef DEBUG_UNICODE
+#include <assert.h>
+#endif
 
 /* This is part of the Microsoft Internationalized Domain Name
    Mitigation APIs. */
 #include <normalization.h>
 
+/* TODO: All the normalization and conversion code should NUL
+   terminate destination strings. */
+
 int
 (WINAPI *pNormalizeString)( __in NORM_FORM NormForm,
                             __in_ecount(cwSrcLength) LPCWSTR lpSrcString,
@@ -65,8 +72,15 @@ long cm_InitNormalization(void)
         return 1;
     }
 
-    pNormalizeString = GetProcAddress(h_Nls, "NormalizeString");
-    pIsNormalizedString = GetProcAddress(h_Nls, "IsNormalizedString");
+    pNormalizeString =
+        (int (WINAPI *)( NORM_FORM, LPCWSTR,
+                         int, LPWSTR, int))
+        GetProcAddress(h_Nls, "NormalizeString");
+
+    pIsNormalizedString =
+        (BOOL
+         (WINAPI *)( NORM_FORM, LPCWSTR, int ))
+        GetProcAddress(h_Nls, "IsNormalizedString");
 
     return (pNormalizeString && pIsNormalizedString);
 }
@@ -100,6 +114,13 @@ long cm_InitNormalization(void)
 static wchar_t * 
 NormalizeUtf16String(const wchar_t * src, int cch_src, wchar_t * ext_dest, int *pcch_dest)
 {
+#ifdef DEBUG_UNICODE
+    assert (pNormalizeString != NULL && pIsNormalizedString != NULL);
+#endif
+
+    if (cch_src == -1)
+        cch_src = wcslen(src) + 1;
+
     if ((pIsNormalizedString && (*pIsNormalizedString)(AFS_NORM_FORM, src, cch_src)) ||
         (!pNormalizeString)) {
 
@@ -109,7 +130,8 @@ NormalizeUtf16String(const wchar_t * src, int cch_src, wchar_t * ext_dest, int *
         }
 
         /* No need to or unable to normalize.  Just copy the string.
-           Note that the string is not necessarily NULL terminated. */
+           Note that the string is not NUL terminated if the source
+           string is not NUL terminated. */
 
         if (ext_dest) {
             memcpy(ext_dest, src, cch_src * sizeof(wchar_t));
@@ -169,6 +191,13 @@ NormalizeUtf16String(const wchar_t * src, int cch_src, wchar_t * ext_dest, int *
                 }
 
                 *pcch_dest = rv;
+                if (cch_dest > rv)
+                    dest[rv] = 0;
+                else {
+                    /* Can't NUL terminate */
+                    cch_dest = max(rv,cch_dest) + NLSERRCCH;
+                    goto cont;
+                }
 
                 /* Success! */
                 return dest;
@@ -190,6 +219,111 @@ NormalizeUtf16String(const wchar_t * src, int cch_src, wchar_t * ext_dest, int *
     }
 }
 
+/*! \brief Normalize a Unicode string into a newly allocated buffer
+
+  The input string will be normalized using NFC.
+
+  \param[in] s UTF-16 string to be normalized.
+
+  \param[in] cch_src The number of characters in the input string.  If
+      this is -1, then the input string is assumed to be NUL
+      terminated.
+
+  \param[out] pcch_dest Receives the number of characters copied to
+      the output buffer.  Note that the character count is the number
+      of wchar_t characters copied, and not the count of Unicode code
+      points.  This includes the terminating NUL if cch_src was -1 or
+      included the terminating NUL.
+
+  \return A newly allocated buffer holding the normalized string or
+      NULL if the call failed.
+ */
+cm_normchar_t * cm_NormalizeStringAlloc(const cm_unichar_t * s, int cch_src, int *pcch_dest)
+{
+    int cch_dest = 0;
+    cm_normchar_t * r;
+
+    r = NormalizeUtf16String(s, cch_src, NULL, &cch_dest);
+
+    if (pcch_dest)
+        *pcch_dest = cch_dest;
+
+    return r;
+}
+
+int cm_NormalizeString(const cm_unichar_t * s, int cch_src,
+                       cm_normchar_t * dest, int cch_dest)
+{
+    int tcch = cch_dest;
+    cm_normchar_t * r;
+
+    r = NormalizeUtf16String(s, cch_src, dest, &tcch);
+
+    if (r != dest) {
+        /* The supplied buffer was insufficient */
+        free(r);
+        return 0;
+    } else {
+        return tcch;
+    }
+}
+
+/*! \brief Convert a UTF-16 string to a UTF-8 string using a newly allocated buffer
+
+  \param[in] s UTF-16 source string
+
+  \param[in] cch_src Number of characters in \a s. This can be set to
+      -1 if \a s is NUL terminated.
+
+  \param[out] pcch_dest Receives a count of characters that were
+      copied to the target buffer.
+
+  \return A newly allocated buffer holding the UTF-8 string.
+
+ */
+cm_utf8char_t * cm_Utf16ToUtf8Alloc(const cm_unichar_t * s, int cch_src, int *pcch_dest)
+{
+    int cch_dest;
+    cm_utf8char_t * dest;
+
+    cch_dest = WideCharToMultiByte(CP_UTF8, 0, s, cch_src, NULL, 0, NULL, FALSE);
+
+    if (cch_dest == 0) {
+        if (pcch_dest)
+            *pcch_dest = cch_dest;
+        return NULL;
+    }
+
+    dest = malloc((cch_dest + 1) * sizeof(cm_utf8char_t));
+
+    WideCharToMultiByte(CP_UTF8, 0, s, cch_src, dest, cch_dest, NULL, FALSE);
+    dest[cch_dest] = 0;
+
+    if (pcch_dest)
+        *pcch_dest = cch_dest;
+
+    return dest;
+}
+
+int cm_Utf16ToUtf8(const cm_unichar_t * src, int cch_src,
+                   cm_utf8char_t * dest, int cch_dest)
+{
+    return WideCharToMultiByte(CP_UTF8, 0, src, cch_src, dest, cch_dest, NULL, FALSE);
+}
+
+int cm_Utf16ToUtf16(const cm_unichar_t * src, int cch_src,
+                    cm_unichar_t * dest, int cch_dest)
+{
+    if (cch_src == -1) {
+        StringCchCopyW(dest, cch_dest, src);
+        return wcslen(dest) + 1;
+    } else {
+        int cch_conv = min(cch_src, cch_dest);
+        memcpy(dest, src, cch_conv * sizeof(cm_unichar_t));
+        return cch_conv;
+    }
+}
+
 /* \brief Normalize a UTF-16 string into a UTF-8 string.
 
    \param[in] src : Source string.
@@ -305,7 +439,7 @@ static const short sanitized_escapes_1252[] = {
 };
 
 static int sanitize_bytestring(const char * src, int cch_src,
-                                char * odest, int cch_dest)
+                               char * odest, int cch_dest)
 {
     char * dest = odest;
     while (cch_src > 0 && *src && cch_dest > 0) {
@@ -348,6 +482,282 @@ static int sanitize_bytestring(const char * src, int cch_src,
 #undef IS_ESCAPED
 #undef ESCVAL
 
+long cm_NormalizeUtf8StringToUtf16(const char * src, int cch_src,
+                                   wchar_t * dest, int cch_dest)
+{
+    wchar_t wsrcbuf[NLSMAXCCH];
+    wchar_t *wnorm;
+    int cch;
+    int cch_norm;
+
+    /* Get some edge cases out first, so we don't have to worry about
+       cch_src being 0 etc. */
+    if (cch_src == 0) {
+        return 0;
+    } else if (*src == '\0') {
+        if (cch_dest >= 1)
+            *dest = L'\0';
+        return 1;
+    }
+
+    if (cch_src == -1) {
+        cch_src = strlen(src) + 1;
+    }
+
+    cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                              cch_src * sizeof(char), wsrcbuf, NLSMAXCCH);
+
+    if (cch == 0) {
+        if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+            char sanitized[NLSMAXCCH];
+            int cch_sanitized;
+
+            /* If src doesn't have a unicode translation, then it
+               wasn't valid UTF-8.  In this case, we assume that src
+               is CP-1252 and then try to convert again.  But before
+               that, we use a translation table to "sanitize" the
+               input. */
+
+            cch_sanitized = sanitize_bytestring(src, cch_src, sanitized,
+                                                sizeof(sanitized)/sizeof(char));
+
+            if (cch_sanitized == 0) {
+#ifdef DEBUG_UNICODE
+                DebugBreak();
+#endif
+                return 0;
+            }
+
+            cch = MultiByteToWideChar(1252, 0, sanitized,
+                                      cch_sanitized * sizeof(char), wsrcbuf, NLSMAXCCH);
+            if (cch == 0) {
+                /* Well, that didn't work either.  Something is very wrong. */
+#ifdef DEBUG_UNICODE
+                DebugBreak();
+#endif
+                return 0;
+            }
+        } else {
+            return 0;
+        }
+    }
+
+    cch_norm = cch_dest;
+    wnorm = NormalizeUtf16String(wsrcbuf, cch, dest, &cch_norm);
+    if (wnorm == NULL) {
+#ifdef DEBUG_UNICODE
+        DebugBreak();
+#endif
+        return 0;
+    }
+
+    if (wnorm != dest) {
+        /* The buffer was insufficient */
+        if (dest != NULL && cch_dest > 1) {
+            *dest = L'\0';
+            cch_norm = 0;
+        }
+
+        free(wnorm);
+    }
+
+    return cch_norm;
+}
+
+cm_normchar_t *cm_NormalizeUtf8StringToUtf16Alloc(const cm_utf8char_t * src, int cch_src,
+                                                  int *pcch_dest)
+{
+    wchar_t wsrcbuf[NLSMAXCCH];
+    wchar_t *wnorm;
+    int cch;
+    int cch_norm;
+
+    /* Get some edge cases out first, so we don't have to worry about
+       cch_src being 0 etc. */
+    if (cch_src == 0) {
+        return NULL;
+    } else if (*src == '\0') {
+        return wcsdup(L"");
+    }
+
+    if (cch_src == -1) {
+        cch_src = strlen(src) + 1;
+    }
+
+    cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                              cch_src * sizeof(char), wsrcbuf, NLSMAXCCH);
+
+    if (cch == 0) {
+        if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+            char sanitized[NLSMAXCCH];
+            int cch_sanitized;
+
+            /* If src doesn't have a unicode translation, then it
+               wasn't valid UTF-8.  In this case, we assume that src
+               is CP-1252 and then try to convert again.  But before
+               that, we use a translation table to "sanitize" the
+               input. */
+
+            cch_sanitized = sanitize_bytestring(src, cch_src, sanitized,
+                                                sizeof(sanitized)/sizeof(char));
+
+            if (cch_sanitized == 0) {
+#ifdef DEBUG_UNICODE
+                DebugBreak();
+#endif
+                return NULL;
+            }
+
+            cch = MultiByteToWideChar(1252, 0, sanitized,
+                                      cch_sanitized * sizeof(char), wsrcbuf, NLSMAXCCH);
+            if (cch == 0) {
+                /* Well, that didn't work either.  Something is very wrong. */
+#ifdef DEBUG_UNICODE
+                DebugBreak();
+#endif
+                return NULL;
+            }
+        } else {
+            return NULL;
+        }
+    }
+
+    cch_norm = 0;
+    wnorm = NormalizeUtf16String(wsrcbuf, cch, NULL, &cch_norm);
+    if (wnorm == NULL) {
+#ifdef DEBUG_UNICODE
+        DebugBreak();
+#endif
+        return NULL;
+    }
+
+    if (pcch_dest)
+        *pcch_dest = cch_norm;
+
+    return wnorm;
+}
+
+int cm_Utf8ToUtf16(const cm_utf8char_t * src, int cch_src,
+                   cm_unichar_t * dest, int cch_dest)
+{
+    int cch;
+
+    if (cch_src == -1) {
+        cch_src = strlen(src) + 1;
+    }
+
+    cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                              cch_src * sizeof(char), dest, cch_dest);
+
+    if (cch == 0) {
+        if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+            char sanitized[NLSMAXCCH];
+            int cch_sanitized;
+
+            /* If src doesn't have a unicode translation, then it
+               wasn't valid UTF-8.  In this case, we assume that src
+               is CP-1252 and then try to convert again.  But before
+               that, we use a translation table to "sanitize" the
+               input. */
+
+            cch_sanitized = sanitize_bytestring(src, cch_src, sanitized,
+                                                sizeof(sanitized)/sizeof(char));
+
+            if (cch_sanitized == 0) {
+#ifdef DEBUG_UNICODE
+                DebugBreak();
+#endif
+                return 0;
+            }
+
+            cch = MultiByteToWideChar(1252, 0, sanitized,
+                                      cch_sanitized * sizeof(char), dest, cch_dest);
+            if (cch == 0) {
+                /* Well, that didn't work either.  Something is very wrong. */
+#ifdef DEBUG_UNICODE
+                DebugBreak();
+#endif
+                return 0;
+            } else {
+                return cch;
+            }
+
+        } else {
+            return 0;
+        }
+    } else {
+        return cch;
+    }
+}
+
+cm_unichar_t  * cm_Utf8ToUtf16Alloc(const cm_utf8char_t * src, int cch_src, int *pcch_dest)
+{
+    cm_unichar_t * ustr = NULL;
+    int cch;
+
+    if (cch_src == -1) {
+        cch_src = strlen(src) + 1;
+    }
+
+    cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                              cch_src * sizeof(char), NULL, 0);
+
+    if (cch == 0) {
+        if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+            char sanitized[NLSMAXCCH];
+            int cch_sanitized;
+
+            /* If src doesn't have a unicode translation, then it
+               wasn't valid UTF-8.  In this case, we assume that src
+               is CP-1252 and then try to convert again.  But before
+               that, we use a translation table to "sanitize" the
+               input. */
+
+            cch_sanitized = sanitize_bytestring(src, cch_src, sanitized,
+                                                sizeof(sanitized)/sizeof(char));
+
+            if (cch_sanitized == 0) {
+#ifdef DEBUG_UNICODE
+                DebugBreak();
+#endif
+                return NULL;
+            }
+
+            cch = MultiByteToWideChar(1252, 0, sanitized,
+                                      cch_sanitized * sizeof(char), NULL, 0);
+            if (cch == 0) {
+                /* Well, that didn't work either.  Something is very wrong. */
+#ifdef DEBUG_UNICODE
+                DebugBreak();
+#endif
+                return NULL;
+            }
+
+            ustr = malloc((cch + 1) * sizeof(wchar_t));
+
+            cch = MultiByteToWideChar(1252, 0, sanitized,
+                                      cch_sanitized * sizeof(char), ustr, cch);
+            ustr[cch] = 0;
+        } else {
+            return NULL;
+        }
+    } else {
+
+        ustr = malloc((cch + 1) * sizeof(wchar_t));
+
+        cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
+                                  cch_src * sizeof(char), ustr, cch);
+        ustr[cch] = 0;
+    }
+
+    if (pcch_dest)
+        *pcch_dest = cch;
+
+    return ustr;
+}
+
+
+
 /* \brief Normalize a UTF-8 string.
 
    \param[in] src String to normalize.
@@ -391,7 +801,7 @@ long cm_NormalizeUtf8String(const char * src, int cch_src,
         cch_src = strlen(src) + 1;
     }
 
-    cch = MultiByteToWideChar(CP_UTF8, 0, src,
+    cch = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, src,
                               cch_src * sizeof(char), wsrcbuf, NLSMAXCCH);
 
     if (cch == 0) {
@@ -465,7 +875,7 @@ int cm_strnicmp_utf8(const char * str1, const char * str2, int n)
     wchar_t wstr2[NLSMAXCCH];
     int rv;
 
-    /* first check for NULL pointers */
+    /* first check for NULL pointers (assume NULL < "") */
     if (str1 == NULL) {
         if (str2 == NULL)
             return 0;
@@ -475,7 +885,7 @@ int cm_strnicmp_utf8(const char * str1, const char * str2, int n)
         return 1;
     }
 
-    len1 = MultiByteToWideChar(CP_UTF8, 0, str1, n, wstr1, NLSMAXCCH);
+    len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str1, n, wstr1, NLSMAXCCH);
     if (len1 == 0) {
 #ifdef DEBUG
         DebugBreak();
@@ -483,7 +893,7 @@ int cm_strnicmp_utf8(const char * str1, const char * str2, int n)
         wstr1[0] = L'\0';
     }
 
-    len2 = MultiByteToWideChar(CP_UTF8, 0, str2, n, wstr2, NLSMAXCCH);
+    len2 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str2, n, wstr2, NLSMAXCCH);
     if (len2 == 0) {
 #ifdef DEBUG
         DebugBreak();
@@ -502,6 +912,97 @@ int cm_strnicmp_utf8(const char * str1, const char * str2, int n)
     }
 }
 
+int cm_strnicmp_utf16(const cm_unichar_t * str1, const cm_unichar_t * str2, int len)
+{
+    int rv;
+    size_t cch1;
+    size_t cch2;
+
+    /* first check for NULL pointers */
+    if (str1 == NULL) {
+        if (str2 == NULL)
+            return 0;
+        else
+            return -1;
+    } else if (str2 == NULL) {
+        return 1;
+    }
+
+    if (FAILED(StringCchLengthW(str1, len, &cch1)))
+        cch1 = len;
+
+    if (FAILED(StringCchLengthW(str2, len, &cch2)))
+        cch2 = len;
+
+    rv = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, str1, cch1, str2, cch2);
+    if (rv > 0)
+        return (rv - 2);
+    else {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        return 0;
+    }
+}
+
+int cm_stricmp_utf16(const cm_unichar_t * str1, const cm_unichar_t * str2)
+{
+    int rv;
+
+    /* first check for NULL pointers */
+    if (str1 == NULL) {
+        if (str2 == NULL)
+            return 0;
+        else
+            return -1;
+    } else if (str2 == NULL) {
+        return 1;
+    }
+
+    rv = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, str1, -1, str2, -1);
+    if (rv > 0)
+        return (rv - 2);
+    else {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        return 0;
+    }
+}
+
+cm_unichar_t *cm_strlwr_utf16(cm_unichar_t * str)
+{
+    int rv;
+    int len;
+
+    len = wcslen(str) + 1;
+    rv = LCMapStringW(LOCALE_INVARIANT, LCMAP_LOWERCASE, str, len, str, len);
+#ifdef DEBUG
+    if (rv == 0) {
+        DebugBreak();
+    }
+#endif
+
+    return str;
+}
+
+cm_unichar_t *cm_strupr_utf16(cm_unichar_t * str)
+{
+    int rv;
+    int len;
+
+    len = wcslen(str) + 1;
+    rv = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, str, len, str, len);
+#ifdef DEBUG
+    if (rv == 0) {
+        DebugBreak();
+    }
+#endif
+
+    return str;
+}
+
+
 int cm_stricmp_utf8(const char * str1, const char * str2)
 {
     wchar_t wstr1[NLSMAXCCH];
@@ -520,7 +1021,7 @@ int cm_stricmp_utf8(const char * str1, const char * str2)
         return 1;
     }
 
-    len1 = MultiByteToWideChar(CP_UTF8, 0, str1, -1, wstr1, NLSMAXCCH);
+    len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str1, -1, wstr1, NLSMAXCCH);
     if (len1 == 0) {
 #ifdef DEBUG
         DebugBreak();
@@ -528,7 +1029,7 @@ int cm_stricmp_utf8(const char * str1, const char * str2)
         wstr1[0] = L'\0';
     }
 
-    len2 = MultiByteToWideChar(CP_UTF8, 0, str2, -1, wstr2, NLSMAXCCH);
+    len2 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str2, -1, wstr2, NLSMAXCCH);
     if (len2 == 0) {
 #ifdef DEBUG
         DebugBreak();
@@ -547,6 +1048,7 @@ int cm_stricmp_utf8(const char * str1, const char * str2)
     }
 }
 
+#if 0
 wchar_t * strupr_utf16(wchar_t * wstr, size_t cbstr)
 {
     wchar_t wstrd[NLSMAXCCH];
@@ -558,15 +1060,15 @@ wchar_t * strupr_utf16(wchar_t * wstr, size_t cbstr)
 
     return wstr;
 }
+#endif
 
 char * strupr_utf8(char * str, size_t cbstr)
 {
     wchar_t wstr[NLSMAXCCH];
     wchar_t wstrd[NLSMAXCCH];
     int len;
-    int r;
 
-    len = MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, NLSMAXCCH);
+    len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, wstr, NLSMAXCCH);
     if (len == 0)
         return str;
 
@@ -618,3 +1120,31 @@ char * char_prev_utf8(const char * c)
 
 #undef CH
 }
+
+wchar_t * char_next_utf16(const wchar_t * c)
+{
+    unsigned short sc = (unsigned short) *c;
+
+    if (sc >= 0xd800 && sc <= 0xdbff)
+        return (wchar_t *) c+2;
+    return (wchar_t *) c+1;
+}
+
+wchar_t * char_prev_utf16(const wchar_t * c)
+{
+    unsigned short sc = (unsigned short) *(--c);
+
+    if (sc >= 0xdc00 && sc <= 0xdfff)
+        return (wchar_t *) --c;
+    return (wchar_t *) c;
+}
+
+wchar_t * char_this_utf16(const wchar_t * c)
+{
+    unsigned short sc = (unsigned short) *c;
+
+    if (sc >= 0xdc00 && sc <= 0xdfff)
+        return (wchar_t *) --c;
+    return (wchar_t *) c;
+}
+
index ba7add3..017d271 100644 (file)
 #ifndef __CM_NLS_H_ENV__
 #define __CM_NLS_H_ENV__
 
+/* Character types
+
+   There are three character types that we use as implementation
+   types.  These should generally only be referenced by the
+   nationalization code.
+
+   - ::cm_unichar_t
+
+   - ::cm_normchar_t
+
+   - ::cm_utf8char_t
+
+   The character types that are used by code are :
+
+   - ::clientchar_t
+
+   - ::normchar_t
+
+   - ::fschar_t
+
+ */
+
+/*! \brief Unicode UTF-16 Character */
+typedef wchar_t cm_unichar_t;
+
+/*! \brief Unicode UTF-16 Normalized Character (NF-C) */
+typedef wchar_t cm_normchar_t;
+
+/*! \brief Unicode UTF-8 Character */
+typedef unsigned char cm_utf8char_t;
+
+/*! \brief Client name */
+typedef cm_unichar_t  clientchar_t;
+
+/*! \brief File Server name */
+typedef cm_utf8char_t fschar_t;
+
+/*! \brief Normalized name */
+typedef cm_normchar_t normchar_t;
+
+#define __paste(a,b) a ## b
+#define _C(s) __paste(L,s)
+#define _FS(s) s
+#define _N(s) __paste(L,s)
+
+#define cm_ClientStringToNormStringAlloc cm_NormalizeStringAlloc
+#define cm_ClientStringToFsStringAlloc cm_Utf16ToUtf8Alloc
+#define cm_ClientStringToUtf8Alloc cm_Utf16ToUtf8Alloc
+#define cm_FsStringToClientStringAlloc cm_Utf8ToUtf16Alloc
+#define cm_FsStringToNormStringAlloc cm_NormalizeUtf8StringToUtf16Alloc
+#define cm_Utf8ToNormStringAlloc cm_NormalizeUtf8StringToUtf16Alloc
+#define cm_Utf8ToClientStringAlloc cm_Utf8ToUtf16Alloc
+
+#define cm_ClientStringToUtf16 cm_Utf16ToUtf16
+#define cm_ClientStringToUtf8  cm_Utf16ToUtf8
+#define cm_ClientStringToFsString cm_Utf16ToUtf8
+#define cm_ClientStringToNormString cm_NormalizeString
+#define cm_FsStringToClientString cm_Utf8ToUtf16
+#define cm_FsStringToNormString cm_NormalizeUtf8StringToUtf16
+#define cm_Utf8ToClientString cm_Utf8ToUtf16
+#define cm_OemToClientString(s,cchs,d,cchd) MultiByteToWideChar(CP_OEMCP, 0, s, cchs, d, cchd)
+#define cm_AnsiToClientString(s,cchs,d,cchd) MultiByteToWideChar(CP_ACP, 0, s, cchs, d, cchd)
+
+#define cm_ClientStrCmp wcscmp
+#define cm_ClientStrCmpI cm_stricmp_utf16
+#define cm_ClientStrCmpIA cm_stricmp_utf16
+#define cm_ClientStrCmpNI cm_strnicmp_utf16
+#define cm_ClientStrCmpN wcsncmp
+#define cm_ClientStrChr wcschr
+#define cm_ClientStrRChr wcsrchr
+#define cm_ClientStrCpy(d,cch,s) StringCchCopyW(d,cch,s)
+#define cm_ClientStrCpyN(d,cch,s,n) StringCchCopyNW(d,cch,s,n)
+#define cm_ClientStrDup wcsdup
+#define cm_ClientStrCat(d,cch,s) StringCchCatW(d,cch,s)
+#define cm_ClientStrCatN(d,cch,s,n) StringCchCatNW(d,cch,s,n)
+#define cm_ClientStrPrintfN StringCchPrintfW
+#define cm_ClientStrPrintfV StringCchVPrintfW
+//#define cm_ClientStrPrintf  swprintf
+#define cm_ClientStrLen wcslen
+#define cm_ClientStrLwr cm_strlwr_utf16
+#define cm_ClientStrUpr cm_strupr_utf16
+#define cm_ClientStrSpn wcsspn
+#define cm_ClientStrCSpn wcscspn
+#define osi_LogSaveClientString osi_LogSaveStringW
+#define cm_ClientCharThis char_this_utf16
+#define cm_ClientCharNext char_next_utf16
+#define cm_ClientCharPrev char_prev_utf16
+
+#define cm_FsStrDup strdup
+#define cm_FsStrLen strlen
+#define cm_FsStrCat StringCchCatA
+#define cm_FsStrPrintf StringCchPrintfA
+#define cm_FsStrRChr strrchr
+#define cm_FsStrChr  strchr
+#define cm_FsStrCmpIA cm_stricmp_utf8
+#define cm_FsStrCmpI cm_stricmp_utf8
+#define cm_FsStrCmpA  strcmp
+#define cm_FsStrCmp  strcmp
+#define cm_FsStrCpy(d,cch,s) StringCchCopyA(d,cch,s)
+#define osi_LogSaveFsString osi_LogSaveString
+#define cm_FsStrCpyN(d,cch,s,n) StringCchCopyN(d,cch,s,n)
+
+#define cm_NormStrDup wcsdup
+#define cm_NormStrCmpI cm_stricmp_utf16
+#define cm_NormStrCmp wcscmp
+#define cm_NormCharUpr towupper
+
+#define cm_Utf16ToClientString cm_Utf16ToUtf16
+
 extern long cm_InitNormalization(void);
 
-extern long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
-                                          char * adest, int cch_adest);
+/* Functions annotated in accordance with sal.h */
+
+extern __out_ecount_full_z(*pcch_dest) __checkReturn __success(return != NULL) cm_normchar_t *
+    cm_NormalizeStringAlloc
+    (__in_ecount(cch_src) const cm_unichar_t * s,
+     int cch_src,
+     __out_ecount_full_opt(1) int *pcch_dest);
+
+extern __success(return != 0) int
+    cm_NormalizeString
+    (__in_ecount(cch_src) const cm_unichar_t * s,
+     int cch_src,
+     __out_ecount_full_z_opt(cch_dest) cm_normchar_t * dest,
+     int cch_dest);
+
+extern __out_ecount_full_z(*pcch_dest) __checkReturn __success(return != NULL) cm_utf8char_t *
+    cm_Utf16ToUtf8Alloc
+    (__in_ecount(cch_src) const cm_unichar_t * s,
+     int cch_src, 
+     __out_ecount_full_opt(1) int *pcch_dest);
+
+extern __out_ecount_full_z(*pcch_dest) __checkReturn __success(return != NULL) cm_unichar_t *
+    cm_Utf8ToUtf16Alloc
+    (__in_ecount(cch_src) const cm_utf8char_t * src,
+     int cch_src,
+     __out_ecount_full_opt(1) int *pcch_dest);
+
+extern __success(return != 0) long
+    cm_NormalizeUtf8StringToUtf16
+    (__in_ecount(cch_src) const char * src,
+     int cch_src,
+     __out_ecount_full_z_opt(cch_dest) cm_normchar_t * dest,
+     int cch_dest);
+
+extern __out_ecount_full_z(*pcch_dest) __checkReturn __success(return != NULL) cm_normchar_t *
+    cm_NormalizeUtf8StringToUtf16Alloc
+    (__in_ecount(cch_src) const cm_utf8char_t * src,
+     int cch_src,
+     __out_ecount_full_opt(1) int *pcch_dest);
+
+extern __success(return != 0) int
+    cm_Utf8ToUtf16
+    (__in_ecount(cch_src) const cm_utf8char_t * src,
+     int cch_src,
+     __out_ecount_full_z_opt(cch_dest) cm_unichar_t * dest,
+     int cch_dest);
+
+extern __success(return != 0) int
+    cm_Utf16ToUtf8
+    (__in_ecount(cch_src) const cm_unichar_t * src,
+     int cch_src,
+     __out_ecount_full_z_opt(cch_dest) cm_utf8char_t * dest,
+     int cch_dest);
+
+extern __success(return != 0) int
+    cm_Utf16ToUtf16
+    (__in_ecount(cch_src) const cm_unichar_t * src,
+     int cch_src,
+     __out_ecount_full_z_opt(cch_dest) cm_unichar_t * dest,
+     int cch_dest);
+
+extern int
+    cm_strnicmp_utf16
+    (__in_z const cm_unichar_t * str1,
+     __in_z const cm_unichar_t * str2,
+     int len);
 
-extern long cm_NormalizeUtf8String(const char * src, int cch_src,
-                                   char * adest, int cch_adest);
+extern int
+    cm_stricmp_utf16
+    (__in_z const cm_unichar_t * str1,
+     __in_z const cm_unichar_t * str2);
 
 /* The cm_stricmp_utf8N function is identical to cm_stricmp_utf8
    except it is used in instances where one of the strings is always
    known to be ASCII. */
-extern int cm_stricmp_utf8N(const char * str1, const char * str2);
+extern int
+    cm_stricmp_utf8N
+    (__in_z const char * str1,
+     __in_z const char * str2);
 #define cm_stricmp_utf8N cm_stricmp_utf8
 
-extern int cm_stricmp_utf8(const char * str1, const char * str2);
+extern int
+    cm_stricmp_utf8
+    (__in_z const char * str1,
+     __in_z const char * str2);
 
 /* The cm_strnicmp_utf8N function is identical to cm_strnicmp_utf8
    except it is used in instances where one of the strings is always
    known to be ASCII. */
-extern int cm_strnicmp_utf8N(const char * str1, const char * str2, int n);
+extern int
+    cm_strnicmp_utf8N
+    (__in_z const char * str1,
+     __in_z const char * str2, int n);
 #define cm_strnicmp_utf8N cm_strnicmp_utf8
 
-extern int cm_strnicmp_utf8(const char * str1, const char * str2, int n);
+extern int
+    cm_strnicmp_utf8
+    (__in_z const char * str1,
+     __in_z const char * str2, int n);
+
+extern __out_z wchar_t *
+char_next_utf16
+(__in_z const wchar_t * c);
+
+extern __out_z wchar_t *
+char_prev_utf16
+(__in_z const wchar_t * c);
+
+extern __out_z wchar_t *
+char_this_utf16
+(__in_z const wchar_t * c);
+
+extern __out_z cm_unichar_t *
+cm_strlwr_utf16(__inout_z cm_unichar_t * str);
+
+extern __out_z cm_unichar_t *
+cm_strupr_utf16(__inout_z cm_unichar_t * str);
+
+#if 0
+
+extern long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
+                                          char * adest, int cch_adest);
 
 extern char * char_next_utf8(const char * c);
 
@@ -56,3 +266,6 @@ extern char * char_prev_utf8(const char * c);
 extern char * strupr_utf8(char * str, size_t cbstr);
 
 #endif
+
+#define lengthof(a) (sizeof(a)/sizeof(a[0]))
+#endif
index ac4990b..2320807 100644 (file)
@@ -407,4 +407,6 @@ extern long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags);
 extern void cm_RemoveSCacheFromHashTable(cm_scache_t *scp);
 
 extern void cm_AdjustScacheLRU(cm_scache_t *scp);
+
+extern int cm_DumpSCache(FILE *outputFile, char *cookie, int lock);
 #endif /*  __CM_SCACHE_H_ENV__ */
index 361bec1..9284934 100644 (file)
@@ -31,7 +31,7 @@ typedef struct cm_ucell {
     int gen;                           /* generation number */
     int iterator;                      /* for use as ListTokens cookie */
     long flags;                                /* flags */
-    char userName[MAXKTCNAMELEN];      /* user name */
+    fschar_t userName[MAXKTCNAMELEN];   /* user name */
 #ifdef QUERY_AFSID
     afs_uint32 uid;                    /* User's AFS ID in this cell */
 #endif
index 68b03de..bb849b3 100644 (file)
@@ -363,3 +363,372 @@ void cm_FreeSpace(cm_space_t *tsp)
         lock_ReleaseWrite(&cm_utilsLock);
 }
 
+/* characters that are legal in an 8.3 name */
+/*
+ * We used to have 1's for all characters from 128 to 254.  But
+ * the NT client behaves better if we create an 8.3 name for any
+ * name that has a character with the high bit on, and if we
+ * delete those characters from 8.3 names.  In particular, see
+ * Sybase defect 10859.
+ */
+char cm_LegalChars[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+#define ISLEGALCHAR(c) ((c) < 256 && (c) > 0 && cm_LegalChars[(c)] != 0)
+
+/* return true iff component is a valid 8.3 name */
+int cm_Is8Dot3(clientchar_t *namep)
+{
+    int sawDot = 0;
+    clientchar_t tc;
+    int charCount = 0;
+        
+    /*
+     * can't have a leading dot;
+     * special case for . and ..
+     */
+    if (namep[0] == '.') {
+        if (namep[1] == 0)
+            return 1;
+        if (namep[1] == '.' && namep[2] == 0)
+            return 1;
+        return 0;
+    }
+    while (tc = *namep++) {
+        if (tc == '.') {
+            /* saw another dot */
+            if (sawDot) return 0;      /* second dot */
+            sawDot = 1;
+            charCount = 0;
+            continue;
+        }
+        if (!ISLEGALCHAR(tc))
+            return 0;
+        charCount++;
+        if (!sawDot && charCount > 8)
+            /* more than 8 chars in name */
+            return 0;
+        if (sawDot && charCount > 3)
+            /* more than 3 chars in extension */
+            return 0;
+    }
+    return 1;
+}
+
+/*
+ * Number unparsing map for generating 8.3 names;
+ * The version taken from DFS was on drugs.  
+ * You can't include '&' and '@' in a file name.
+ */
+char cm_8Dot3Mapping[42] =
+{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
+ 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
+ 'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '+', '='
+};
+int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
+
+void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
+                        clientchar_t *shortName, clientchar_t **shortNameEndp)
+{
+    char number[12];
+    int i, nsize = 0;
+    int vnode = ntohl(pfid->vnode);
+    char *lastDot;
+    int validExtension = 0;
+    char tc, *temp;
+    const char *name;
+
+    /* Unparse the file's vnode number to get a "uniquifier" */
+    do {
+        number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
+        nsize++;
+        vnode /= cm_8Dot3MapSize;
+    } while (vnode);
+
+    /*
+     * Look for valid extension.  There has to be a dot, and
+     * at least one of the characters following has to be legal.
+     */
+    lastDot = strrchr(longname, '.');
+    if (lastDot) {
+        temp = lastDot; temp++;
+        while (tc = *temp++)
+            if (ISLEGALCHAR(tc))
+                break;
+        if (tc)
+            validExtension = 1;
+    }
+
+    /* Copy name characters */
+    for (i = 0, name = longname;
+          i < (7 - nsize) && name != lastDot; ) {
+        tc = *name++;
+
+        if (tc == 0)
+            break;
+        if (!ISLEGALCHAR(tc))
+            continue;
+        i++;
+        *shortName++ = toupper(tc);
+    }
+
+    /* tilde */
+    *shortName++ = '~';
+
+    /* Copy uniquifier characters */
+    for (i=0; i < nsize; i++) {
+        *shortName++ = number[i];
+    }
+
+    if (validExtension) {
+        /* Copy extension characters */
+        *shortName++ = *lastDot++;     /* copy dot */
+        for (i = 0, tc = *lastDot++;
+             i < 3 && tc;
+             tc = *lastDot++) {
+            if (ISLEGALCHAR(tc)) {
+                i++;
+                *shortName++ = toupper(tc);
+            }
+        }
+    }
+
+    /* Trailing null */
+    *shortName = 0;
+
+    if (shortNameEndp)
+        *shortNameEndp = shortName;
+}
+
+void cm_Gen8Dot3NameIntW(const clientchar_t * longname, cm_dirFid_t * pfid,
+                         clientchar_t *shortName, clientchar_t **shortNameEndp)
+{
+    clientchar_t number[12];
+    int i, nsize = 0;
+    int vnode = ntohl(pfid->vnode);
+    clientchar_t *lastDot;
+    int validExtension = 0;
+    clientchar_t tc, *temp;
+    const clientchar_t *name;
+
+    /* Unparse the file's vnode number to get a "uniquifier" */
+    do {
+        number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
+        nsize++;
+        vnode /= cm_8Dot3MapSize;
+    } while (vnode);
+
+    /*
+     * Look for valid extension.  There has to be a dot, and
+     * at least one of the characters following has to be legal.
+     */
+    lastDot = cm_ClientStrRChr(longname, '.');
+    if (lastDot) {
+        temp = lastDot; temp++;
+        while (tc = *temp++)
+            if (ISLEGALCHAR(tc))
+                break;
+        if (tc)
+            validExtension = 1;
+    }
+
+    /* Copy name characters */
+    for (i = 0, name = longname;
+          i < (7 - nsize) && name != lastDot; ) {
+        tc = *name++;
+
+        if (tc == 0)
+            break;
+        if (!ISLEGALCHAR(tc))
+            continue;
+        i++;
+        *shortName++ = toupper((char) tc);
+    }
+
+    /* tilde */
+    *shortName++ = '~';
+
+    /* Copy uniquifier characters */
+    for (i=0; i < nsize; i++) {
+        *shortName++ = number[i];
+    }
+
+    if (validExtension) {
+        /* Copy extension characters */
+        *shortName++ = *lastDot++;     /* copy dot */
+        for (i = 0, tc = *lastDot++;
+             i < 3 && tc;
+             tc = *lastDot++) {
+            if (ISLEGALCHAR(tc)) {
+                i++;
+                *shortName++ = toupper(tc);
+            }
+        }
+    }
+
+    /* Trailing null */
+    *shortName = 0;
+
+    if (shortNameEndp)
+        *shortNameEndp = shortName;
+}
+
+/*! \brief Compare 'pattern' (containing metacharacters '*' and '?') with the file name 'name'.
+
+  \note This procedure works recursively calling itself.
+
+  \param[in] pattern string containing metacharacters.
+  \param[in] name File name to be compared with 'pattern'.
+
+  \return BOOL : TRUE/FALSE (match/mistmatch)
+*/
+static BOOL 
+szWildCardMatchFileName(clientchar_t * pattern, clientchar_t * name, int casefold) 
+{
+    clientchar_t upattern[MAX_PATH];
+    clientchar_t uname[MAX_PATH];
+
+    clientchar_t * pename;         // points to the last 'name' character
+    clientchar_t * p;
+    clientchar_t * pattern_next;
+
+    if (casefold) {
+        cm_ClientStrCpy(upattern, lengthof(upattern), pattern);
+        cm_ClientStrUpr(upattern);
+        pattern = upattern;
+
+        cm_ClientStrCpy(uname, lengthof(uname), name);
+        cm_ClientStrUpr(uname);
+        name = uname;
+
+        /* The following translations all work on single byte
+           characters */
+        for (p=upattern; *p; p++) {
+            if (*p == '"') *p = '.'; continue;
+            if (*p == '<') *p = '*'; continue;
+            if (*p == '>') *p = '?'; continue;
+        }
+
+        for (p=uname; *p; p++) {
+            if (*p == '"') *p = '.'; continue;
+            if (*p == '<') *p = '*'; continue;
+            if (*p == '>') *p = '?'; continue;
+        }
+    }
+
+    pename = cm_ClientCharThis(name + cm_ClientStrLen(name));
+
+    while (*name) {
+        switch (*pattern) {
+        case '?':
+           pattern = cm_ClientCharNext(pattern);
+            if (*name == '.')
+               continue;
+            name = cm_ClientCharNext(name);
+            break;
+
+         case '*':
+            pattern = cm_ClientCharNext(pattern);
+            if (*pattern == '\0')
+                return TRUE;
+
+            pattern_next = cm_ClientCharNext(pattern);
+
+            for (p = pename; p >= name; p = cm_ClientCharPrev(p)) {
+                if (*p == *pattern &&
+                    szWildCardMatchFileName(pattern_next,
+                                            cm_ClientCharNext(p), FALSE))
+                    return TRUE;
+            } /* endfor */
+            return FALSE;
+
+        default:
+            if (*name != *pattern)
+                return FALSE;
+            pattern = cm_ClientCharNext(pattern);
+            name = cm_ClientCharNext(name);
+            break;
+        } /* endswitch */
+    } /* endwhile */
+
+    /* if all we have left are wildcards, then we match */
+    for (;*pattern; pattern = cm_ClientCharNext(pattern)) {
+       if (*pattern != '*' && *pattern != '?')
+           return FALSE;
+    }
+    return TRUE;
+}
+
+/* do a case-folding search of the star name mask with the name in namep.
+ * Return 1 if we match, otherwise 0.
+ */
+int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags) 
+{
+    clientchar_t * newmask;
+    int    i, j, star, qmark, casefold, retval;
+
+    /* make sure we only match 8.3 names, if requested */
+    if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
+        return 0;
+
+    casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
+
+    /* optimize the pattern:
+     * if there is a mixture of '?' and '*',
+     * for example  the sequence "*?*?*?*"
+     * must be turned into the form "*"
+     */
+    newmask = (clientchar_t *)malloc((cm_ClientStrLen(maskp)+1)*sizeof(clientchar_t));
+    for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
+        switch ( maskp[i] ) {
+        case '?':
+        case '>':
+            qmark++;
+            break;
+        case '<':
+        case '*':
+            star++;
+            break;
+        default:
+            if ( star ) {
+                newmask[j++] = '*';
+            } else if ( qmark ) {
+                while ( qmark-- )
+                    newmask[j++] = '?';
+            }
+            newmask[j++] = maskp[i];
+            star = 0;
+            qmark = 0;
+        }
+    }
+    if ( star ) {
+        newmask[j++] = '*';
+    } else if ( qmark ) {
+        while ( qmark-- )
+            newmask[j++] = '?';
+    }
+    newmask[j++] = '\0';
+
+    retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
+
+    free(newmask);
+    return retval;
+}
+
index a157d92..eced1a0 100644 (file)
 
 #define CM_UTILS_SPACESIZE             8192    /* space to allocate */
 typedef struct cm_space {
-       char data[CM_UTILS_SPACESIZE];
-        struct cm_space *nextp;
+    union {
+        clientchar_t wdata[CM_UTILS_SPACESIZE];
+        char data[CM_UTILS_SPACESIZE];
+    };
+    struct cm_space *nextp;
 } cm_space_t;
 
 /* error code hack */
@@ -30,4 +33,22 @@ extern long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp);
 
 extern long cm_MapVLRPCError(long error, cm_req_t *reqp);
 
+extern void init_et_to_sys_error(void);
+
+extern int cm_Is8Dot3(clientchar_t *namep);
+
+extern void cm_Gen8Dot3Name(struct cm_dirEntry *dep, clientchar_t *shortName,
+                            clientchar_t **shortNameEndp);
+
+#define cm_Gen8Dot3Name(dep,shortName,shortNameEndp)                  \
+cm_Gen8Dot3NameInt((dep)->name, &(dep)->fid, shortName, shortNameEndp)
+
+extern void cm_Gen8Dot3NameInt(const fschar_t * longname, cm_dirFid_t * pfid,
+                               clientchar_t *shortName, clientchar_t **shortNameEndp);
+
+extern void cm_Gen8Dot3NameIntW(const clientchar_t* longname, cm_dirFid_t * pfid,
+                                clientchar_t *shortName, clientchar_t **shortNameEndp);
+
+extern int cm_MatchMask(clientchar_t *namep, clientchar_t *maskp, int flags);
+
 #endif /*  __CM_UTILS_H_ENV__ */
index 7116555..4ec27a1 100644 (file)
@@ -24,6 +24,8 @@
 #include "smb.h"
 #include "cm_btree.h"
 
+#include <strsafe.h>
+
 #ifdef DEBUG
 extern void afsi_log(char *pattern, ...);
 #endif
@@ -97,156 +99,7 @@ int cm_stricmp(const char *str1, const char *str2)
     }
 }
 
-/* characters that are legal in an 8.3 name */
-/*
- * We used to have 1's for all characters from 128 to 254.  But
- * the NT client behaves better if we create an 8.3 name for any
- * name that has a character with the high bit on, and if we
- * delete those characters from 8.3 names.  In particular, see
- * Sybase defect 10859.
- */
-char cm_LegalChars[256] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* return true iff component is a valid 8.3 name */
-int cm_Is8Dot3(char *namep)
-{
-    int sawDot = 0;
-    unsigned char tc;
-    int charCount = 0;
-        
-    /*
-     * can't have a leading dot;
-     * special case for . and ..
-     */
-    if (namep[0] == '.') {
-        if (namep[1] == 0)
-            return 1;
-        if (namep[1] == '.' && namep[2] == 0)
-            return 1;
-        return 0;
-    }
-    while (tc = *namep++) {
-        if (tc == '.') {
-            /* saw another dot */
-            if (sawDot) return 0;      /* second dot */
-            sawDot = 1;
-            charCount = 0;
-            continue;
-        }
-        if (cm_LegalChars[tc] == 0)
-            return 0;
-        charCount++;
-        if (!sawDot && charCount > 8)
-            /* more than 8 chars in name */
-            return 0;
-        if (sawDot && charCount > 3)
-            /* more than 3 chars in extension */
-            return 0;
-    }
-    return 1;
-}
-
-/*
- * Number unparsing map for generating 8.3 names;
- * The version taken from DFS was on drugs.  
- * You can't include '&' and '@' in a file name.
- */
-char cm_8Dot3Mapping[42] =
-{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 
- 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 
- 'V', 'W', 'X', 'Y', 'Z', '_', '-', '$', '#', '!', '+', '='
-};
-int cm_8Dot3MapSize = sizeof(cm_8Dot3Mapping);
 
-void cm_Gen8Dot3NameInt(const char * longname, cm_dirFid_t * pfid,
-                        char *shortName, char **shortNameEndp)
-{
-    char number[12];
-    int i, nsize = 0;
-    int vnode = ntohl(pfid->vnode);
-    char *lastDot;
-    int validExtension = 0;
-    char tc, *temp;
-    const char *name;
-
-    /* Unparse the file's vnode number to get a "uniquifier" */
-    do {
-        number[nsize] = cm_8Dot3Mapping[vnode % cm_8Dot3MapSize];
-        nsize++;
-        vnode /= cm_8Dot3MapSize;
-    } while (vnode);
-
-    /*
-     * Look for valid extension.  There has to be a dot, and
-     * at least one of the characters following has to be legal.
-     */
-    lastDot = strrchr(longname, '.');
-    if (lastDot) {
-        temp = lastDot; temp++;
-        while (tc = *temp++)
-            if (cm_LegalChars[tc])
-                break;
-        if (tc)
-            validExtension = 1;
-    }
-
-    /* Copy name characters */
-    for (i = 0, name = longname;
-          i < (7 - nsize) && name != lastDot; ) {
-        tc = *name++;
-
-        if (tc == 0)
-            break;
-        if (!cm_LegalChars[tc])
-            continue;
-        i++;
-        *shortName++ = toupper(tc);
-    }
-
-    /* tilde */
-    *shortName++ = '~';
-
-    /* Copy uniquifier characters */
-    memcpy(shortName, number, nsize);
-    shortName += nsize;
-
-    if (validExtension) {
-        /* Copy extension characters */
-        *shortName++ = *lastDot++;     /* copy dot */
-        for (i = 0, tc = *lastDot++;
-              i < 3 && tc;
-              tc = *lastDot++) {
-            if (cm_LegalChars[tc]) {
-                i++;
-                *shortName++ = toupper(tc);
-            }
-        }
-    }
-
-    /* Trailing null */
-    *shortName = 0;
-
-    if (shortNameEndp)
-        *shortNameEndp = shortName;
-}       
 
 /* return success if we can open this file in this mode */
 long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc, cm_user_t *userp,
@@ -576,8 +429,8 @@ long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp, cm_user_t *userp,
  * cm_lookupSearch_t object.  
  */
 long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
-                  osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp,
-                  cm_scache_t **retscp)
+                 osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp,
+                 cm_scache_t **retscp)
 {
     char *tp;
     long code;
@@ -647,7 +500,7 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
                 if (code == 0) {
 
 #ifdef USE_BPLUS
-                    code = cm_BPlusDirLookup(&dirop, sp->searchNamep, &sp->fid);
+                    code = cm_BPlusDirLookup(&dirop, sp->nsearchNamep, &sp->fid);
                     if (code != EINVAL)
                         usedBplus = 1;
                     else 
@@ -847,18 +700,18 @@ long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
     return code;
 }
 
-int cm_NoneUpper(char *s)
+int cm_NoneUpper(normchar_t *s)
 {
-    char c;
+    normchar_t c;
     while (c = *s++)
         if (c >= 'A' && c <= 'Z')
             return 0;
     return 1;
 }
 
-int cm_NoneLower(char *s)
+int cm_NoneLower(normchar_t *s)
 {
-    char c;
+    normchar_t c;
     while (c = *s++)
         if (c >= 'a' && c <= 'z')
             return 0;
@@ -866,30 +719,30 @@ int cm_NoneLower(char *s)
 }
 
 long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
-                          osi_hyper_t *offp)
+                         osi_hyper_t *offp)
 {
     cm_lookupSearch_t *sp;
     int match;
-    char matchName[MAX_PATH];
+    normchar_t matchName[MAX_PATH];
     int looking_for_short_name = FALSE;
 
     sp = (cm_lookupSearch_t *) rockp;
 
-    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
+    cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
     if (sp->caseFold)
-        match = cm_stricmp_utf8(matchName, sp->searchNamep);
+        match = cm_NormStrCmpI(matchName, sp->nsearchNamep);
     else
-        match = strcmp(matchName, sp->searchNamep);
+        match = cm_NormStrCmp(matchName, sp->nsearchNamep);
 
     if (match != 0
-         && sp->hasTilde
-         && !cm_Is8Dot3(dep->name)) {
+        && sp->hasTilde
+        && !cm_Is8Dot3(matchName)) {
 
-        cm_Gen8Dot3Name(dep, matchName, NULL);
+        cm_Gen8Dot3NameInt(dep->name, &dep->fid, matchName, NULL);
         if (sp->caseFold)
-            match = cm_stricmp_utf8(matchName, sp->searchNamep);
+            match = cm_NormStrCmpI(matchName, sp->nsearchNamep);
         else
-            match = strcmp(matchName, sp->searchNamep);
+            match = cm_NormStrCmp(matchName, sp->nsearchNamep);
         looking_for_short_name = TRUE;
     }
 
@@ -913,7 +766,7 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
      */
 
     /* Exact matches are the best. */
-    match = strcmp(matchName, sp->searchNamep);
+    match = cm_NormStrCmp(matchName, sp->nsearchNamep);
     if (match == 0) {
         sp->ExactFound = 1;
         cm_SetFid(&sp->fid, sp->fid.cell, sp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
@@ -1024,15 +877,15 @@ long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
 long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
                          cm_req_t *reqp, cm_scache_t **outScpp)
 {
-    char *cellNamep;
-    char *volNamep;
+    fschar_t *cellNamep = NULL;
+    fschar_t *volNamep = NULL;
     int tlen;
-    long code;
-    char *cp;
-    char *mpNamep;
+    afs_uint32 code;
+    fschar_t *cp;
+    fschar_t *mpNamep;
     cm_volume_t *volp = NULL;
     cm_cell_t *cellp;
-    char mtType;
+    fschar_t mtType;
     cm_fid_t tfid;
     size_t vnLength;
     int targetType;
@@ -1049,25 +902,23 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
     mpNamep = scp->mountPointStringp;
     if (!mpNamep[0])
        return CM_ERROR_NOSUCHPATH;
-    tlen = (int)strlen(scp->mountPointStringp);
+    tlen = cm_FsStrLen(scp->mountPointStringp);
     mtType = *scp->mountPointStringp;
-    cellNamep = malloc(tlen);
-    volNamep = malloc(tlen);
 
-    cp = strrchr(mpNamep, ':');
+    cp = cm_FsStrChr(mpNamep, _FS(':'));
     if (cp) {
         /* cellular mount point */
-        memset(cellNamep, 0, tlen);
-        strncpy(cellNamep, mpNamep+1, cp - mpNamep - 1);
-        strcpy(volNamep, cp+1);
+        cellNamep = (fschar_t *)malloc((cp - mpNamep) * sizeof(fschar_t));
+        cm_FsStrCpyN(cellNamep, cp - mpNamep, mpNamep + 1, cp - mpNamep - 1);
+        volNamep = cm_FsStrDup(cp+1);
+
         /* now look up the cell */
         lock_ReleaseWrite(&scp->rw);
         cellp = cm_GetCell(cellNamep, CM_FLAG_CREATE);
         lock_ObtainWrite(&scp->rw);
-    }
-    else {
+    } else {
         /* normal mt pt */
-        strcpy(volNamep, mpNamep+1);
+        volNamep = cm_FsStrDup(mpNamep + 1);
 
         cellp = cm_FindCellByID(scp->fid.cell, 0);
     }
@@ -1077,11 +928,11 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
         goto done;
     }
 
-    vnLength = strlen(volNamep);
-    if (vnLength >= 8 && strcmp(volNamep + vnLength - 7, ".backup") == 0)
+    vnLength = cm_FsStrLen(volNamep);
+    if (vnLength >= 8 && cm_FsStrCmp(volNamep + vnLength - 7, ".backup") == 0)
         targetType = BACKVOL;
     else if (vnLength >= 10
-              && strcmp(volNamep + vnLength - 9, ".readonly") == 0)
+             && cm_FsStrCmp(volNamep + vnLength - 9, ".readonly") == 0)
         targetType = ROVOL;
     else
         targetType = RWVOL;
@@ -1153,12 +1004,14 @@ long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
   done:
     if (volp)
        cm_PutVolume(volp);
-    free(cellNamep);
-    free(volNamep);
+    if (cellNamep)
+        free(cellNamep);
+    if (volNamep)
+        free(volNamep);
     return code;
 }       
 
-long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
+long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_user_t *userp,
                        cm_req_t *reqp, cm_scache_t **outpScpp)
 {
     long code;
@@ -1167,20 +1020,25 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
     cm_scache_t *mountedScp;
     cm_lookupSearch_t rock;
     int getroot;
+    normchar_t *nnamep = NULL;
+    fschar_t *fnamep = NULL;
 
     memset(&rock, 0, sizeof(rock));
 
     if (dscp->fid.vnode == 1 && dscp->fid.unique == 1
-         && strcmp(namep, "..") == 0) {
+        && cm_ClientStrCmp(cnamep, _C("..")) == 0) {
         if (dscp->dotdotFid.volume == 0)
             return CM_ERROR_NOSUCHVOLUME;
         rock.fid = dscp->dotdotFid;
         goto haveFid;
-    } else if (strcmp(namep, ".") == 0) {
+    } else if (cm_ClientStrCmp(cnamep, _C(".")) == 0) {
        rock.fid = dscp->fid;
        goto haveFid;
     }
 
+    nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
+    fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+
     if (flags & CM_FLAG_NOMOUNTCHASE) {
         /* In this case, we should go and call cm_Dir* functions
            directly since the following cm_ApplyDir() function will
@@ -1194,12 +1052,12 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
         code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
         if (code == 0) {
 #ifdef USE_BPLUS
-            code = cm_BPlusDirLookup(&dirop, namep, &rock.fid);
+            code = cm_BPlusDirLookup(&dirop, nnamep, &rock.fid);
             if (code != EINVAL)
                 usedBplus = 1;
             else
 #endif
-                code = cm_DirLookup(&dirop, namep, &rock.fid);
+                code = cm_DirLookup(&dirop, fnamep, &rock.fid);
 
             cm_EndDirOp(&dirop);
         }
@@ -1225,13 +1083,14 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
 
     rock.fid.cell = dscp->fid.cell;
     rock.fid.volume = dscp->fid.volume;
-    rock.searchNamep = namep;
+    rock.searchNamep = fnamep;
+    rock.nsearchNamep = nnamep;
     rock.caseFold = (flags & CM_FLAG_CASEFOLD);
-    rock.hasTilde = ((strchr(namep, '~') != NULL) ? 1 : 0);
+    rock.hasTilde = ((cm_ClientStrChr(cnamep, '~') != NULL) ? 1 : 0);
 
     /* If NOMOUNTCHASE, bypass DNLC by passing NULL scp pointer */
     code = cm_ApplyDir(dscp, cm_LookupSearchProc, &rock, NULL, userp, reqp,
-                        (flags & CM_FLAG_NOMOUNTCHASE) ? NULL : &tscp);
+                       (flags & CM_FLAG_NOMOUNTCHASE) ? NULL : &tscp);
 
     /* code == 0 means we fell off the end of the dir, while stopnow means
      * that we stopped early, probably because we found the entry we're
@@ -1244,31 +1103,34 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
          */
         if (code == CM_ERROR_NOTDIR) {
             if (flags & CM_FLAG_CHECKPATH)
-                return CM_ERROR_NOSUCHPATH;
+                code = CM_ERROR_NOSUCHPATH;
             else
-                return CM_ERROR_NOSUCHFILE;
+                code = CM_ERROR_NOSUCHFILE;
         }
-        return code;
+        goto done;
     }
 
     getroot = (dscp==cm_data.rootSCachep) ;
     if (!rock.found) {
         if (!cm_freelanceEnabled || !getroot) {
             if (flags & CM_FLAG_CHECKPATH)
-                return CM_ERROR_NOSUCHPATH;
+                code = CM_ERROR_NOSUCHPATH;
             else
-                return CM_ERROR_NOSUCHFILE;
+                code = CM_ERROR_NOSUCHFILE;
+            goto done;
         }
-        else if (!strchr(namep, '#') && !strchr(namep, '%') &&
-                 strcmp(namep, "srvsvc") && strcmp(namep, "wkssvc") &&
-                 strcmp(namep, "ipc$")) 
+        else if (!cm_ClientStrChr(cnamep, '#') &&
+                 !cm_ClientStrChr(cnamep, '%') &&
+                 cm_ClientStrCmpI(cnamep, _C("srvsvc")) &&
+                 cm_ClientStrCmpI(cnamep, _C("wkssvc")) &&
+                 cm_ClientStrCmpI(cnamep, _C("ipc$"))) 
         {
             /* nonexistent dir on freelance root, so add it */
-            char fullname[200] = ".";
+            fschar_t fullname[200] = ".";
             int  found = 0;
 
-            osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %s", 
-                      osi_LogSaveString(afsd_logp,namep));
+            osi_Log1(afsd_logp,"cm_Lookup adding mount for non-existent directory: %S", 
+                     osi_LogSaveClientString(afsd_logp,cnamep));
 
             /* 
              * There is an ugly behavior where a share name "foo" will be searched
@@ -1278,39 +1140,42 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
              */
 
             code = -1;
-            if (namep[0] == '.') {
-                if (cm_GetCell_Gen(&namep[1], &fullname[1], CM_FLAG_CREATE)) {
+            if (cnamep[0] == '.') {
+                if (cm_GetCell_Gen(&fnamep[1], &fullname[1], CM_FLAG_CREATE)) {
                     found = 1;
                     if (!cm_FreelanceMountPointExists(fullname, 0))
-                        code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.", 1, &rock.fid);
-                    if ( cm_stricmp_utf8(&namep[1], &fullname[1]) && 
-                                               !cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
-                                               !cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
-                        code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
+                        code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.",
+                                                    1, &rock.fid);
+                    if ( cm_FsStrCmpI(&fnamep[1], &fullname[1]) && 
+                         !cm_FreelanceMountPointExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
+                         !cm_FreelanceSymlinkExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
+                        code = cm_FreelanceAddSymlink(fnamep, fullname, &rock.fid);
                 }
             } else {
-                if (cm_GetCell_Gen(namep, fullname, CM_FLAG_CREATE)) {
+                if (cm_GetCell_Gen(fnamep, fullname, CM_FLAG_CREATE)) {
                     found = 1;
                     if (!cm_FreelanceMountPointExists(fullname, 0))
                         code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
-                    if ( cm_stricmp_utf8(namep, fullname) && 
-                                               !cm_FreelanceMountPointExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
-                                               !cm_FreelanceSymlinkExists(namep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
-                        code = cm_FreelanceAddSymlink(namep, fullname, &rock.fid);
+                    if ( cm_FsStrCmpI(fnamep, fullname) && 
+                         !cm_FreelanceMountPointExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0) &&
+                         !cm_FreelanceSymlinkExists(fnamep, flags & CM_FLAG_DFS_REFERRAL ? 1 : 0))
+                        code = cm_FreelanceAddSymlink(fnamep, fullname, &rock.fid);
                 }
             }
             if (!found || code < 0) {   /* add mount point failed, so give up */
                 if (flags & CM_FLAG_CHECKPATH)
-                    return CM_ERROR_NOSUCHPATH;
+                    code = CM_ERROR_NOSUCHPATH;
                 else
-                    return CM_ERROR_NOSUCHFILE;
+                    code = CM_ERROR_NOSUCHFILE;
+                goto done;
             }
             tscp = NULL;   /* to force call of cm_GetSCache */
         } else {
             if (flags & CM_FLAG_CHECKPATH)
-                return CM_ERROR_NOSUCHPATH;
+                code = CM_ERROR_NOSUCHPATH;
             else
-                return CM_ERROR_NOSUCHFILE;
+                code = CM_ERROR_NOSUCHFILE;
+            goto done;
         }
     }
 
@@ -1320,8 +1185,8 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
         dnlcHit = 0; 
         code = cm_GetSCache(&rock.fid, &tscp, userp, reqp);
         if (code) 
-            return code;
-    }       
+            goto done;
+    }
     /* tscp is now held */
 
     lock_ObtainWrite(&tscp->rw);
@@ -1330,7 +1195,7 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
     if (code) { 
         lock_ReleaseWrite(&tscp->rw);
         cm_ReleaseSCache(tscp);
-        return code;
+        goto done;
     }
     cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
     /* tscp is now locked */
@@ -1343,12 +1208,12 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
         code = cm_ReadMountPoint(tscp, userp, reqp);
         if (code == 0)
             code = cm_FollowMountPoint(tscp, dscp, userp, reqp,
-                                        &mountedScp);
+                                       &mountedScp);
         lock_ReleaseWrite(&tscp->rw);
         cm_ReleaseSCache(tscp);
-        if (code) {
-            return code;
-        }
+        if (code)
+            goto done;
+
         tscp = mountedScp;
     }
     else {
@@ -1363,26 +1228,39 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
         /* lock the directory entry to prevent racing callback revokes */
         lock_ObtainRead(&dscp->rw);
         if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 ) {
-            /* Note: namep is a normalized name */
-            cm_dnlcEnter(dscp, namep, tscp);
+            /* TODO: reuse nnamep from above */
+            if (nnamep) 
+                free(nnamep);
+            nnamep = cm_ClientStringToNormStringAlloc(cnamep, -1, NULL);
+            cm_dnlcEnter(dscp, nnamep, tscp);
         }
         lock_ReleaseRead(&dscp->rw);
     }
 
     /* and return */
-    return 0;
+  done:
+    if (fnamep) {
+        free (fnamep);
+        fnamep = NULL;
+    }
+    if (nnamep) {
+        free (nnamep);
+        nnamep = NULL;
+    }
+
+    return code;
 }
 
-int cm_ExpandSysName(char *inp, char *outp, long outSize, unsigned int index)
+int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch, unsigned int index)
 {
-    char *tp;
+    clientchar_t *tp;
     int prefixCount;
 
-    tp = strrchr(inp, '@');
+    tp = cm_ClientStrRChr(inp, '@');
     if (tp == NULL) 
         return 0;              /* no @sys */
 
-    if (strcmp(tp, "@sys") != 0) 
+    if (cm_ClientStrCmp(tp, _C("@sys")) != 0) 
         return 0;      /* no @sys */
 
     /* caller just wants to know if this is a valid @sys type of name */
@@ -1395,21 +1273,22 @@ int cm_ExpandSysName(char *inp, char *outp, long outSize, unsigned int index)
     /* otherwise generate the properly expanded @sys name */
     prefixCount = (int)(tp - inp);
 
-    strncpy(outp, inp, prefixCount);   /* copy out "a." from "a.@sys" */
+    cm_ClientStrCpyN(outp, outSizeCch, inp, prefixCount);      /* copy out "a." from "a.@sys" */
     outp[prefixCount] = 0;             /* null terminate the "a." */
-    strcat(outp, cm_sysNameList[index]);/* append i386_nt40 */
+    cm_ClientStrCat(outp, outSizeCch, cm_sysNameList[index]);/* append i386_nt40 */
     return 1;
 }   
 
-long cm_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
+long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * userp,
                                 cm_req_t *reqp, cm_scache_t ** outpScpp)
 {
-    long          code = 0;
-    char          cellName[CELL_MAXNAMELEN];
-    char          volumeName[VL_MAXNAMELEN];
+    afs_uint32    code = 0;
+    fschar_t      cellName[CELL_MAXNAMELEN];
+    fschar_t      volumeName[VL_MAXNAMELEN];
     size_t        len;
-    char *        cp;
-    char *        tp;
+    fschar_t *        cp;
+    fschar_t *        tp;
+    fschar_t *        fnamep = NULL;
 
     cm_cell_t *   cellp = NULL;
     cm_volume_t * volp = NULL;
@@ -1418,10 +1297,10 @@ long cm_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
     int           volType;
     int           mountType = RWVOL;
 
-    osi_Log1(afsd_logp, "cm_EvaluateVolumeReference for string [%s]",
-             osi_LogSaveString(afsd_logp, namep));
+    osi_Log1(afsd_logp, "cm_EvaluateVolumeReference for string [%S]",
+             osi_LogSaveClientString(afsd_logp, namep));
 
-    if (strnicmp(namep, CM_PREFIX_VOL, CM_PREFIX_VOL_CCH) != 0) {
+    if (cm_ClientStrCmpNI(namep, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH) != 0) {
         goto _exit_invalid_path;
     }
 
@@ -1433,39 +1312,38 @@ long cm_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
 
      */
 
-    cp = namep + CM_PREFIX_VOL_CCH; /* cp points to cell name, hopefully */
-    tp = strchr(cp, '%');
+    fnamep = cm_ClientStringToFsStringAlloc(namep, cm_ClientStrLen(namep), NULL);
+    cp = fnamep + CM_PREFIX_VOL_CCH; /* cp points to cell name, hopefully */
+    tp = cm_FsStrChr(cp, '%');
     if (tp == NULL)
-        tp = strchr(cp, '#');
+        tp = cm_FsStrChr(cp, '#');
     if (tp == NULL ||
         (len = tp - cp) == 0 ||
         len > CELL_MAXNAMELEN)
         goto _exit_invalid_path;
-    strncpy(cellName, cp, len);
-    cellName[len] = '\0';
+    cm_FsStrCpyN(cellName, lengthof(cellName), cp, len);
 
     if (*tp == '#')
         mountType = ROVOL;
 
     cp = tp+1;                  /* cp now points to volume, supposedly */
-    strncpy(volumeName, cp, VL_MAXNAMELEN-1);
-    volumeName[VL_MAXNAMELEN - 1] = 0;
+    cm_FsStrCpy(volumeName, lengthof(volumeName), cp);
 
     /* OK, now we have the cell and the volume */
     osi_Log2(afsd_logp, "   Found cell [%s] and volume [%s]",
-             osi_LogSaveString(afsd_logp, cellName),
-             osi_LogSaveString(afsd_logp, volumeName));
+             osi_LogSaveFsString(afsd_logp, cellName),
+             osi_LogSaveFsString(afsd_logp, volumeName));
 
     cellp = cm_GetCell(cellName, CM_FLAG_CREATE);
     if (cellp == NULL) {
         goto _exit_invalid_path;
     }
 
-    len = strlen(volumeName);
-    if (len >= 8 && strcmp(volumeName + len - 7, ".backup") == 0)
+    len = cm_FsStrLen(volumeName);
+    if (len >= 8 && cm_FsStrCmp(volumeName + len - 7, ".backup") == 0)
         volType = BACKVOL;
     else if (len >= 10 &&
-             strcmp(volumeName + len - 9, ".readonly") == 0)
+             cm_FsStrCmp(volumeName + len - 9, ".readonly") == 0)
         volType = ROVOL;
     else
         volType = RWVOL;
@@ -1493,7 +1371,10 @@ long cm_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
 
     code = cm_GetSCache(&fid, outpScpp, userp, reqp);
 
- _exit_cleanup:
+  _exit_cleanup:
+    if (fnamep)
+        free(fnamep);
+
     if (volp)
         cm_PutVolume(volp);
 
@@ -1508,15 +1389,15 @@ long cm_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
 }
 
 #ifdef DEBUG_REFCOUNT
-long cm_LookupDbg(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
+long cm_LookupDbg(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
                cm_req_t *reqp, cm_scache_t **outpScpp, char * file, long line)
 #else
-long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
+long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags, cm_user_t *userp,
                cm_req_t *reqp, cm_scache_t **outpScpp)
 #endif
 {
     long code;
-    char tname[AFSPATHMAX];
+    clientchar_t tname[AFSPATHMAX];
     int sysNameIndex = 0;
     cm_scache_t *scp = NULL;
 
@@ -1525,7 +1406,7 @@ long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
     osi_Log2(afsd_logp, "cm_Lookup dscp 0x%p ref %d", dscp, dscp->refCount);
 #endif
 
-    if ( cm_stricmp_utf8N(namep,SMB_IOCTL_FILENAME_NOSLASH) == 0 ) {
+    if ( cm_ClientStrCmpI(namep,_C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ) {
         if (flags & CM_FLAG_CHECKPATH)
             return CM_ERROR_NOSUCHPATH;
         else
@@ -1533,13 +1414,13 @@ long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
     }
 
     if (dscp == cm_data.rootSCachep &&
-        strnicmp(namep, CM_PREFIX_VOL, CM_PREFIX_VOL_CCH) == 0) {
+        cm_ClientStrCmpNI(namep, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH) == 0) {
         return cm_EvaluateVolumeReference(namep, flags, userp, reqp, outpScpp);
     }
 
     if (cm_ExpandSysName(namep, NULL, 0, 0) > 0) {
         for ( sysNameIndex = 0; sysNameIndex < MAXNUMSYSNAMES; sysNameIndex++) {
-            code = cm_ExpandSysName(namep, tname, sizeof(tname), sysNameIndex);
+            code = cm_ExpandSysName(namep, tname, lengthof(tname), sysNameIndex);
             if (code > 0) {
                 code = cm_LookupInternal(dscp, tname, flags, userp, reqp, &scp);
 #ifdef DEBUG_REFCOUNT
@@ -1589,18 +1470,20 @@ long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
   \param[in] dscp cm_scache_t pointing at the directory containing the
       name to be unlinked.
 
-  \param[in] namep Non-normalized name to be unlinked.  This is the
+  \param[in] fnamep Original name to be unlinked.  This is the
       name that will be passed into the RXAFS_RemoveFile() call.
+      This parameter is optional.  If not provided, the value will
+      be looked up.
 
-  \param[in] normalizedName Normalized name to be unlinked.  This name
-      will be used to update the local directory caches.
+  \param[in] came Client name to be unlinked.  This name will be used
+      to update the local directory caches.
 
   \param[in] userp cm_user_t for the request.
 
   \param[in] reqp Request tracker.
  
  */
-long cm_Unlink(cm_scache_t *dscp, char *namep, char * normalizedName,
+long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t * cnamep,
                cm_user_t *userp, cm_req_t *reqp)
 {
     long code;
@@ -1612,16 +1495,32 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, char * normalizedName,
     struct rx_connection * callp;
     cm_dirOp_t dirop;
     cm_scache_t *scp = NULL;
+    int free_fnamep = FALSE;
+
+    if (fnamep == NULL) {
+        code = -1;
+#ifdef USE_BPLUS
+        code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+        if (code == 0) {
+            code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
+            if (code == 0)
+                free_fnamep = TRUE;
+            cm_EndDirOp(&dirop);
+        }
+#endif
+        if (code)
+            goto done;
+    }
 
 #ifdef AFS_FREELANCE_CLIENT
     if (cm_freelanceEnabled && dscp == cm_data.rootSCachep) {
         /* deleting a mount point from the root dir. */
-        code = cm_FreelanceRemoveMount(namep);
-        return code;
+        code = cm_FreelanceRemoveMount(fnamep);
+        goto done;
     }
 #endif  
 
-    code = cm_Lookup(dscp, namep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    code = cm_Lookup(dscp, cnamep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
 
     /* make sure we don't screw up the dir status during the merge */
     code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
@@ -1632,7 +1531,7 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, char * normalizedName,
     lock_ReleaseWrite(&dscp->rw);
     if (code) {
         cm_EndDirOp(&dirop);
-        return code;
+        goto done;
     }
 
     /* make the RPC */
@@ -1643,12 +1542,12 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, char * normalizedName,
     osi_Log1(afsd_logp, "CALL RemoveFile scp 0x%p", dscp);
     do {
         code = cm_ConnFromFID(&dscp->fid, userp, reqp, &connp);
-        if (code) 
+        if (code)
             continue;
 
         callp = cm_GetRxConn(connp);
-        code = RXAFS_RemoveFile(callp, &afsFid, namep,
-                                 &newDirStatus, &volSync);
+        code = RXAFS_RemoveFile(callp, &afsFid, fnamep,
+                                &newDirStatus, &volSync);
         rx_PutConnection(callp);
 
     } while (cm_Analyze(connp, userp, reqp, &dscp->fid, &volSync, NULL, NULL, code));
@@ -1664,7 +1563,7 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, char * normalizedName,
         dirop.lockType = CM_DIRLOCK_WRITE;
     }
     lock_ObtainWrite(&dscp->rw);
-    cm_dnlcRemove(dscp, normalizedName);
+    cm_dnlcRemove(dscp, cnamep);
     cm_SyncOpDone(dscp, NULL, sflags);
     if (code == 0) {
         cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
@@ -1677,10 +1576,10 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, char * normalizedName,
     }
     lock_ReleaseWrite(&dscp->rw);
 
-    if (code == 0 && cm_CheckDirOpForSingleChange(&dirop) && normalizedName) {
-        cm_DirDeleteEntry(&dirop, namep);
+    if (code == 0 && cm_CheckDirOpForSingleChange(&dirop) && cnamep) {
+        cm_DirDeleteEntry(&dirop, fnamep);
 #ifdef USE_BPLUS
-        cm_BPlusDirDeleteEntry(&dirop, normalizedName);
+        cm_BPlusDirDeleteEntry(&dirop, cnamep);
 #endif
     }
     cm_EndDirOp(&dirop);
@@ -1694,6 +1593,10 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, char * normalizedName,
         }
     }
 
+  done:
+    if (free_fnamep)
+        free(fnamep);
+
     return code;
 }
 
@@ -1765,13 +1668,13 @@ long cm_HandleLink(cm_scache_t *linkScp, cm_user_t *userp, cm_req_t *reqp)
  * other than the directory containing the symbolic link, then the new root is
  * returned in *newRootScpp, otherwise a null is returned there.
  */
-long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
-                      cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
-                      cm_user_t *userp, cm_req_t *reqp)
+long cm_AssembleLink(cm_scache_t *linkScp, fschar_t *pathSuffixp,
+                     cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
+                     cm_user_t *userp, cm_req_t *reqp)
 {
     long code = 0;
     long len;
-    char *linkp;
+    fschar_t *linkp;
     cm_space_t *tsp;
 
     *newRootScpp = NULL;
@@ -1786,17 +1689,17 @@ long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
      * bigger than max path length, so we don't really have to worry about
      * being a little conservative here.
      */
-    if (strlen(linkScp->mountPointStringp) + strlen(pathSuffixp) + 2
-               >= CM_UTILS_SPACESIZE) {
+    if (cm_FsStrLen(linkScp->mountPointStringp) + cm_FsStrLen(pathSuffixp) + 2
+        >= CM_UTILS_SPACESIZE) {
         code = CM_ERROR_TOOBIG;
-               goto done;
-       }
+        goto done;
+    }
 
     tsp = cm_GetSpace();
     linkp = linkScp->mountPointStringp;
     if (strncmp(linkp, cm_mountRoot, cm_mountRootLen) == 0) {
         if (strlen(linkp) > cm_mountRootLen)
-            strcpy(tsp->data, linkp+cm_mountRootLen+1);
+            StringCbCopyA((char *) tsp->data, sizeof(tsp->data), linkp+cm_mountRootLen+1);
         else
             tsp->data[0] = 0;
         *newRootScpp = cm_data.rootSCachep;
@@ -1808,7 +1711,7 @@ long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
             if (strnicmp(p, "all", 3) == 0)
                 p += 4;
 
-            strcpy(tsp->data, p);
+            StringCbCopyA(tsp->data, sizeof(tsp->data), p);
             for (p = tsp->data; *p; p++) {
                 if (*p == '\\')
                     *p = '/';
@@ -1817,20 +1720,20 @@ long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
             cm_HoldSCache(cm_data.rootSCachep);
         } else {
             linkScp->fileType = CM_SCACHETYPE_DFSLINK;
-            strcpy(tsp->data, linkp);
+            StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
             code = CM_ERROR_PATH_NOT_COVERED;
         }
     } else if ( linkScp->fileType == CM_SCACHETYPE_DFSLINK ||
                 !strnicmp(linkp, "msdfs:", (len = (long)strlen("msdfs:"))) ) {
         linkScp->fileType = CM_SCACHETYPE_DFSLINK;
-        strcpy(tsp->data, linkp);
+        StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
         code = CM_ERROR_PATH_NOT_COVERED;
     } else if (*linkp == '\\' || *linkp == '/') {
 #if 0   
         /* formerly, this was considered to be from the AFS root,
          * but this seems to create problems.  instead, we will just
          * reject the link */
-        strcpy(tsp->data, linkp+1);
+        StringCchCopyA(tsp->data,lengthof(tsp->data), linkp+1);
         *newRootScpp = cm_data.rootSCachep;
         cm_HoldSCache(cm_data.rootSCachep);
 #else
@@ -1838,45 +1741,51 @@ long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
          * the user can see what the link points to
          */
         linkScp->fileType = CM_SCACHETYPE_INVALID;
-        strcpy(tsp->data, linkp);
+        StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
         code = CM_ERROR_NOSUCHPATH;
 #endif  
     } else {
         /* a relative link */
-        strcpy(tsp->data, linkp);
+        StringCchCopyA(tsp->data,lengthof(tsp->data), linkp);
     }
     if (pathSuffixp[0] != 0) { /* if suffix string is non-null */
-        strcat(tsp->data, "\\");
-        strcat(tsp->data, pathSuffixp);
+        StringCchCatA(tsp->data,lengthof(tsp->data), "\\");
+        StringCchCatA(tsp->data,lengthof(tsp->data), pathSuffixp);
     }
-    if (code == 0)
+    if (code == 0) {
+        clientchar_t * cpath = cm_FsStringToClientStringAlloc(tsp->data, -1, NULL);
+        cm_ClientStrCpy(tsp->wdata, lengthof(tsp->wdata), cpath);
+        free(cpath);
         *newSpaceBufferp = tsp;
-    else {
+    } else {
         cm_FreeSpace(tsp);
 
-        if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp)
+        if (code == CM_ERROR_PATH_NOT_COVERED && reqp->tidPathp && reqp->relPathp) {
             cm_VolStatus_Notify_DFS_Mapping(linkScp, reqp->tidPathp, reqp->relPathp);
+        }
     }
 
-  done:
+ done:
     lock_ReleaseWrite(&linkScp->rw);
     return code;
 }
 #ifdef DEBUG_REFCOUNT
-long cm_NameIDbg(cm_scache_t *rootSCachep, char *pathp, long flags,
-               cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp, 
-              char * file, long line)
+long cm_NameIDbg(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
+                 cm_user_t *userp, clientchar_t *tidPathp, cm_req_t *reqp,
+                 cm_scache_t **outScpp, 
+                 char * file, long line)
 #else
-long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
-               cm_user_t *userp, char *tidPathp, cm_req_t *reqp, cm_scache_t **outScpp)
+long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
+              cm_user_t *userp, clientchar_t *tidPathp,
+              cm_req_t *reqp, cm_scache_t **outScpp)
 #endif
 {
     long code;
-    char *tp;                  /* ptr moving through input buffer */
-    char tc;                   /* temp char */
+    clientchar_t *tp;                  /* ptr moving through input buffer */
+    clientchar_t tc;                   /* temp char */
     int haveComponent;         /* has new component started? */
-    char component[AFSPATHMAX];        /* this is the new component */
-    char *cp;                  /* component name being assembled */
+    clientchar_t component[AFSPATHMAX];        /* this is the new component */
+    clientchar_t *cp;                  /* component name being assembled */
     cm_scache_t *tscp;         /* current location in the hierarchy */
     cm_scache_t *nscp;         /* next dude down */
     cm_scache_t *dirScp;       /* last dir we searched */
@@ -1885,7 +1794,7 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
     cm_space_t *psp;           /* space for current path, if we've hit
     * any symlinks */
     cm_space_t *tempsp;                /* temp vbl */
-    char *restp;               /* rest of the pathname to interpret */
+    clientchar_t *restp;               /* rest of the pathname to interpret */
     int symlinkCount;          /* count of # of symlinks traversed */
     int extraFlag;             /* avoid chasing mt pts for dir cmd */
     int phase = 1;             /* 1 = tidPathp, 2 = pathp */
@@ -1896,9 +1805,9 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
 
 #ifdef DEBUG_REFCOUNT
     afsi_log("%s:%d cm_NameI rootscp 0x%p ref %d", file, line, rootSCachep, rootSCachep->refCount);
-    osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %s tidpath %s flags 0x%x",
-             rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>", 
-             flags);
+    osi_Log4(afsd_logp,"cm_NameI rootscp 0x%p path %S tidpath %S flags 0x%x",
+             rootSCachep, pathp ? pathp : "<NULL>", tidPathp ? tidPathp : "<NULL>", 
+             flags);
 #endif
 
     tp = tidPathp;
@@ -1907,7 +1816,7 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
         phase = 2;
     }
     if (tp == NULL) {
-        tp = "";
+        tp = _C("");
     }
     haveComponent = 0;
     psp = NULL;
@@ -1954,16 +1863,18 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                if ((flags & CM_FLAG_DIRSEARCH) && tc == 0)
                    extraFlag = CM_FLAG_NOMOUNTCHASE;
                code = cm_Lookup(tscp, component,
-                                 flags | extraFlag,
-                                 userp, reqp, &nscp);
+                                 flags | extraFlag,
+                                 userp, reqp, &nscp);
 
                 if (code == 0) {
-                    if (!strcmp(component,"..") || !strcmp(component,".")) {
+                    if (!cm_ClientStrCmp(component,_C("..")) ||
+                        !cm_ClientStrCmp(component,_C("."))) {
                         /* 
-                         * roll back the fid list until we find the fid 
-                         * that matches where we are now.  Its not necessarily
-                         * one or two fids because they might have been 
-                         * symlinks or mount points or both that were crossed.  
+                         * roll back the fid list until we find the
+                         * fid that matches where we are now.  Its not
+                         * necessarily one or two fids because they
+                         * might have been symlinks or mount points or
+                         * both that were crossed.
                          */
                         for ( i=fid_count-1; i>=0; i--) {
                             if (!cm_FidCmp(&nscp->fid, &fids[i]))
@@ -1993,8 +1904,7 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                    if (psp) 
                        cm_FreeSpace(psp);
                    if ((code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) && 
-                         tscp->fileType == CM_SCACHETYPE_SYMLINK) 
-                    {
+                        tscp->fileType == CM_SCACHETYPE_SYMLINK) {
                        osi_Log0(afsd_logp,"cm_NameI code CM_ERROR_NOSUCHPATH");
                        return CM_ERROR_NOSUCHPATH;
                    } else {
@@ -2018,8 +1928,8 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                     break;
                 }
 
-                /* now, if tscp is a symlink, we should follow
-                 * it and assemble the path again.
+                /* now, if tscp is a symlink, we should follow it and
+                 * assemble the path again.
                  */
                 lock_ObtainWrite(&tscp->rw);
                 code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
@@ -2053,10 +1963,18 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                         return CM_ERROR_TOO_MANY_SYMLINKS;
                     }
                     if (tc == 0) 
-                        restp = "";
+                        restp = _C("");
                     else 
                         restp = tp;
-                    code = cm_AssembleLink(tscp, restp, &linkScp, &tempsp, userp, reqp);
+
+                    {
+                        fschar_t * frestp;
+
+                        /* TODO: make this better */
+                        frestp = cm_ClientStringToFsStringAlloc(restp, -1, NULL);
+                        code = cm_AssembleLink(tscp, frestp, &linkScp, &tempsp, userp, reqp);
+                        free(frestp);
+                    }
 
                     if (code == 0 && linkScp != NULL) {
                         if (linkScp == cm_data.rootSCachep) 
@@ -2098,7 +2016,7 @@ long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
                     if (psp) 
                         cm_FreeSpace(psp);
                     psp = tempsp;
-                    tp = psp->data;
+                    tp = psp->wdata;
                     cm_ReleaseSCache(tscp);
                     tscp = linkScp;
                     linkScp = NULL;
@@ -2196,9 +2114,9 @@ long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
         cm_HoldSCache(dscp);
     }
 
-    code = cm_NameI(newRootScp, spacep->data,
-                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
-                     userp, NULL, reqp, outScpp);
+    code = cm_NameI(newRootScp, spacep->wdata,
+                    CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW | CM_FLAG_DIRSEARCH,
+                    userp, NULL, reqp, outScpp);
 
     if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
         code = CM_ERROR_NOSUCHPATH;
@@ -2674,7 +2592,7 @@ long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
     return code;
 }       
 
-long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
+long cm_Create(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *attrp,
                cm_scache_t **scpp, cm_user_t *userp, cm_req_t *reqp)
 {       
     cm_conn_t *connp;
@@ -2692,11 +2610,12 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
     AFSVolSync volSync;
     struct rx_connection * callp;
     cm_dirOp_t dirop;
+    fschar_t * fnamep = NULL;
 
     /* can't create names with @sys in them; must expand it manually first.
      * return "invalid request" if they try.
      */
-    if (cm_ExpandSysName(namep, NULL, 0, 0)) {
+    if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
         return CM_ERROR_ATSYS;
     }
 
@@ -2728,6 +2647,8 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
     }
     didEnd = 0;
 
+    fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+
     cm_StatusFromAttr(&inStatus, NULL, attrp);
 
     /* try the RPC now */
@@ -2742,7 +2663,7 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
         dirAFSFid.Unique = dscp->fid.unique;
 
         callp = cm_GetRxConn(connp);
-        code = RXAFS_CreateFile(connp->callp, &dirAFSFid, namep,
+        code = RXAFS_CreateFile(connp->callp, &dirAFSFid, fnamep,
                                  &inStatus, &newAFSFid, &newFileStatus,
                                  &updatedDirStatus, &newFileCallback,
                                  &volSync);
@@ -2781,9 +2702,9 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
            scp->creator = userp;               /* remember who created it */
             if (!cm_HaveCallback(scp)) {
                 cm_MergeStatus(dscp, scp, &newFileStatus, &volSync,
-                                userp, 0);
+                               userp, 0);
                 cm_EndCallbackGrantingCall(scp, &cbReq,
-                                            &newFileCallback, 0);
+                                           &newFileCallback, 0);
                 didEnd = 1;     
             }       
             lock_ReleaseWrite(&scp->rw);
@@ -2796,13 +2717,16 @@ long cm_Create(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
         cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
 
     if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
-        cm_DirCreateEntry(&dirop, namep, &newFid);
+        cm_DirCreateEntry(&dirop, fnamep, &newFid);
 #ifdef USE_BPLUS
-        cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
+        cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
 #endif
     }
     cm_EndDirOp(&dirop);
 
+    if (fnamep)
+        free(fnamep);
+
     return code;
 }       
 
@@ -2829,7 +2753,7 @@ long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
     return code;
 }
 
-long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
+long cm_MakeDir(cm_scache_t *dscp, clientchar_t *cnamep, long flags, cm_attr_t *attrp,
                  cm_user_t *userp, cm_req_t *reqp)
 {
     cm_conn_t *connp;
@@ -2847,11 +2771,12 @@ long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
     AFSVolSync volSync;
     struct rx_connection * callp;
     cm_dirOp_t dirop;
+    fschar_t * fnamep = NULL;
 
     /* can't create names with @sys in them; must expand it manually first.
      * return "invalid request" if they try.
      */
-    if (cm_ExpandSysName(namep, NULL, 0, 0)) {
+    if (cm_ExpandSysName(cnamep, NULL, 0, 0)) {
         return CM_ERROR_ATSYS;
     }
 
@@ -2883,6 +2808,7 @@ long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
     }
     didEnd = 0;
 
+    fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
     cm_StatusFromAttr(&inStatus, NULL, attrp);
 
     /* try the RPC now */
@@ -2897,14 +2823,14 @@ long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
         dirAFSFid.Unique = dscp->fid.unique;
 
         callp = cm_GetRxConn(connp);
-        code = RXAFS_MakeDir(connp->callp, &dirAFSFid, namep,
+        code = RXAFS_MakeDir(connp->callp, &dirAFSFid, fnamep,
                               &inStatus, &newAFSFid, &newDirStatus,
                               &updatedDirStatus, &newDirCallback,
                               &volSync);
         rx_PutConnection(callp);
 
     } while (cm_Analyze(connp, userp, reqp,
-                         &dscp->fid, &volSync, NULL, &cbReq, code));
+                        &dscp->fid, &volSync, NULL, &cbReq, code));
     code = cm_MapRPCError(code, reqp);
         
     if (code)
@@ -2950,18 +2876,20 @@ long cm_MakeDir(cm_scache_t *dscp, char *namep, long flags, cm_attr_t *attrp,
         cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
 
     if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
-        cm_DirCreateEntry(&dirop, namep, &newFid);
+        cm_DirCreateEntry(&dirop, fnamep, &newFid);
 #ifdef USE_BPLUS
-        cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
+        cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
 #endif
     }
     cm_EndDirOp(&dirop);
 
+    free(fnamep);
+
     /* and return error code */
     return code;
 }       
 
-long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
+long cm_Link(cm_scache_t *dscp, clientchar_t *cnamep, cm_scache_t *sscp, long flags,
              cm_user_t *userp, cm_req_t *reqp)
 {
     cm_conn_t *connp;
@@ -2973,6 +2901,7 @@ long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
     AFSVolSync volSync;
     struct rx_connection * callp;
     cm_dirOp_t dirop;
+    fschar_t * fnamep = NULL;
 
     if (dscp->fid.cell != sscp->fid.cell ||
         dscp->fid.volume != sscp->fid.volume) {
@@ -2989,6 +2918,8 @@ long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
     if (code)
         return code;
 
+    fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+
     /* try the RPC now */
     osi_Log1(afsd_logp, "CALL Link scp 0x%p", dscp);
     do {
@@ -3004,7 +2935,7 @@ long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
         existingAFSFid.Unique = sscp->fid.unique;
 
         callp = cm_GetRxConn(connp);
-        code = RXAFS_Link(callp, &dirAFSFid, namep, &existingAFSFid,
+        code = RXAFS_Link(callp, &dirAFSFid, fnamep, &existingAFSFid,
             &newLinkStatus, &updatedDirStatus, &volSync);
         rx_PutConnection(callp);
         osi_Log1(afsd_logp,"  RXAFS_Link returns 0x%x", code);
@@ -3032,18 +2963,20 @@ long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp, long flags,
 
     if (code == 0) {
         if (cm_CheckDirOpForSingleChange(&dirop)) {
-            cm_DirCreateEntry(&dirop, namep, &sscp->fid);
+            cm_DirCreateEntry(&dirop, fnamep, &sscp->fid);
 #ifdef USE_BPLUS
-            cm_BPlusDirCreateEntry(&dirop, namep, &sscp->fid);
+            cm_BPlusDirCreateEntry(&dirop, cnamep, &sscp->fid);
 #endif
         }
     }
     cm_EndDirOp(&dirop);
 
+    free(fnamep);
+
     return code;
 }
 
-long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
+long cm_SymLink(cm_scache_t *dscp, clientchar_t *cnamep, fschar_t *contentsp, long flags,
                 cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp)
 {
     cm_conn_t *connp;
@@ -3058,6 +2991,7 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
     AFSVolSync volSync;
     struct rx_connection * callp;
     cm_dirOp_t dirop;
+    fschar_t *fnamep = NULL;
 
     /* before starting the RPC, mark that we're changing the directory data,
      * so that someone who does a chmod on the dir will wait until our
@@ -3073,6 +3007,8 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
         return code;
     }
 
+    fnamep = cm_ClientStringToFsStringAlloc(cnamep, -1, NULL);
+
     cm_StatusFromAttr(&inStatus, NULL, attrp);
 
     /* try the RPC now */
@@ -3087,7 +3023,7 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
         dirAFSFid.Unique = dscp->fid.unique;
 
         callp = cm_GetRxConn(connp);
-        code = RXAFS_Symlink(callp, &dirAFSFid, namep, contentsp,
+        code = RXAFS_Symlink(callp, &dirAFSFid, fnamep, contentsp,
                               &inStatus, &newAFSFid, &newLinkStatus,
                               &updatedDirStatus, &volSync);
         rx_PutConnection(callp);
@@ -3116,9 +3052,9 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
         if (cm_CheckDirOpForSingleChange(&dirop)) {
             cm_SetFid(&newFid, dscp->fid.cell, dscp->fid.volume, newAFSFid.Vnode, newAFSFid.Unique);
 
-            cm_DirCreateEntry(&dirop, namep, &newFid);
+            cm_DirCreateEntry(&dirop, fnamep, &newFid);
 #ifdef USE_BPLUS
-            cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
+            cm_BPlusDirCreateEntry(&dirop, cnamep, &newFid);
 #endif
         }
     }
@@ -3142,6 +3078,8 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
             cm_ReleaseSCache(scp);
         }
     }
+
+    free(fnamep);
        
     /* and return error code */
     return code;
@@ -3154,19 +3092,19 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
   \param[in] dscp cm_scache_t for the directory containing the
       directory to be removed.
 
-  \param[in] namep Non-normalized name of the directory to be
-      removed. This will be the name that is passed in to
-      RXAFS_RemoveDir().
+  \param[in] fnamep This will be the original name of the directory
+      as known to the file server.   It will be passed in to RXAFS_RemoveDir().
+      This parameter is optional.  If it is not provided the value
+      will be looked up.
 
-  \param[in] normalizedNamep Normalized name used to update the local
+  \param[in] cnamep Normalized name used to update the local
       directory caches.
 
   \param[in] userp cm_user_t for the request.
 
   \param[in] reqp Request tracker.
 */
-long cm_RemoveDir(cm_scache_t *dscp, char *namep, char *normalizedNamep,
-                  cm_user_t *userp, cm_req_t *reqp)
+long cm_RemoveDir(cm_scache_t *dscp, fschar_t *fnamep, clientchar_t *cnamep, cm_user_t *userp, cm_req_t *reqp)
 {
     cm_conn_t *connp;
     long code;
@@ -3177,8 +3115,26 @@ long cm_RemoveDir(cm_scache_t *dscp, char *namep, char *normalizedNamep,
     struct rx_connection * callp;
     cm_dirOp_t dirop;
     cm_scache_t *scp = NULL;
+    int free_fnamep = FALSE;
 
-    code = cm_Lookup(dscp, namep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    if (fnamep == NULL) {
+        code = -1;
+#ifdef USE_BPLUS
+        code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
+        if (code == 0) {
+            code = cm_BPlusDirLookupOriginalName(&dirop, cnamep, &fnamep);
+            if (code == 0)
+                free_fnamep = TRUE;
+            cm_EndDirOp(&dirop);
+        }
+#endif
+        if (code)
+            goto done;
+    }
+
+    code = cm_Lookup(dscp, cnamep, CM_FLAG_NOMOUNTCHASE, userp, reqp, &scp);
+    if (code)
+        goto done;
 
     /* before starting the RPC, mark that we're changing the directory data,
      * so that someone who does a chmod on the dir will wait until our
@@ -3190,7 +3146,7 @@ long cm_RemoveDir(cm_scache_t *dscp, char *namep, char *normalizedNamep,
     lock_ReleaseWrite(&dscp->rw);
     if (code) {
         cm_EndDirOp(&dirop);
-        return code;
+        goto done;
     }
     didEnd = 0;
 
@@ -3206,12 +3162,12 @@ long cm_RemoveDir(cm_scache_t *dscp, char *namep, char *normalizedNamep,
         dirAFSFid.Unique = dscp->fid.unique;
 
         callp = cm_GetRxConn(connp);
-        code = RXAFS_RemoveDir(callp, &dirAFSFid, namep,
-                                &updatedDirStatus, &volSync);
+        code = RXAFS_RemoveDir(callp, &dirAFSFid, fnamep,
+                               &updatedDirStatus, &volSync);
         rx_PutConnection(callp);
 
     } while (cm_Analyze(connp, userp, reqp,
-                         &dscp->fid, &volSync, NULL, NULL, code));
+                        &dscp->fid, &volSync, NULL, NULL, code));
     code = cm_MapRPCErrorRmdir(code, reqp);
 
     if (code)
@@ -3226,16 +3182,16 @@ long cm_RemoveDir(cm_scache_t *dscp, char *namep, char *normalizedNamep,
     lock_ObtainWrite(&dscp->rw);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_dnlcRemove(dscp, normalizedNamep); 
+        cm_dnlcRemove(dscp, cnamep); 
         cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseWrite(&dscp->rw);
 
     if (code == 0) {
-        if (cm_CheckDirOpForSingleChange(&dirop) && normalizedNamep != NULL) {
-            cm_DirDeleteEntry(&dirop, namep);
+        if (cm_CheckDirOpForSingleChange(&dirop) && cnamep != NULL) {
+            cm_DirDeleteEntry(&dirop, fnamep);
 #ifdef USE_BPLUS
-            cm_BPlusDirDeleteEntry(&dirop, normalizedNamep);
+            cm_BPlusDirDeleteEntry(&dirop, cnamep);
 #endif
         }
     }
@@ -3250,6 +3206,10 @@ long cm_RemoveDir(cm_scache_t *dscp, char *namep, char *normalizedNamep,
         }
     }
 
+  done:
+    if (free_fnamep)
+        free(fnamep);
+
     /* and return error code */
     return code;
 }
@@ -3279,8 +3239,9 @@ long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp)
   \param[in] oldDscp cm_scache_t for the directory containing the old
       name.
 
-  \param[in] oldNamep Non-normalized old name.  This is the name that
-  will be passed into the RXAFS_Rename().
+  \param[in] oldNamep The original old name known to the file server.
+      This is the name that will be passed into the RXAFS_Rename().
+      If it is not provided, it will be looked up.
 
   \param[in] normalizedOldNamep Normalized old name.  This is used for
   updating local directory caches.
@@ -3295,8 +3256,8 @@ long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp)
   \param[in,out] reqp Request tracker.
 
 */
-long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
-               cm_scache_t *newDscp, char *newNamep, cm_user_t *userp,
+long cm_Rename(cm_scache_t *oldDscp, fschar_t *oldNamep, clientchar_t *cOldNamep,
+               cm_scache_t *newDscp, clientchar_t *cNewNamep, cm_user_t *userp,
                cm_req_t *reqp)
 {
     cm_conn_t *connp;
@@ -3313,6 +3274,24 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
     cm_fid_t   fileFid;
     int        diropCode = -1;
     cm_dirOp_t newDirOp;
+    fschar_t * newNamep = NULL;
+    int free_oldNamep = FALSE;
+
+    if (oldNamep == NULL) {
+        code = -1;
+#ifdef USE_BPLUS
+        code = cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_READ, &oldDirOp);
+        if (code == 0) {
+            code = cm_BPlusDirLookupOriginalName(&oldDirOp, cOldNamep, &oldNamep);
+            if (code == 0)
+                free_oldNamep = TRUE;
+            cm_EndDirOp(&oldDirOp);
+        }
+#endif
+        if (code)
+            goto done;
+    }
+
 
     /* before starting the RPC, mark that we're changing the directory data,
      * so that someone who does a chmod on the dir will wait until our call
@@ -3321,14 +3300,16 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
      */
     if (oldDscp == newDscp) {
         /* check for identical names */
-        if (strcmp(oldNamep, newNamep) == 0)
-            return CM_ERROR_RENAME_IDENTICAL;
+        if (cm_ClientStrCmp(cOldNamep, cNewNamep) == 0) {
+            code = CM_ERROR_RENAME_IDENTICAL;
+            goto done;
+        }
 
         oneDir = 1;
         cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
         lock_ObtainWrite(&oldDscp->rw);
-        cm_dnlcRemove(oldDscp, normalizedOldNamep);
-        cm_dnlcRemove(oldDscp, newNamep);
+        cm_dnlcRemove(oldDscp, cOldNamep);
+        cm_dnlcRemove(oldDscp, cNewNamep);
         code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
                           CM_SCACHESYNC_STOREDATA);
         lock_ReleaseWrite(&oldDscp->rw);
@@ -3340,31 +3321,35 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
         /* two distinct dir vnodes */
         oneDir = 0;
         if (oldDscp->fid.cell != newDscp->fid.cell ||
-             oldDscp->fid.volume != newDscp->fid.volume)
-            return CM_ERROR_CROSSDEVLINK;
+             oldDscp->fid.volume != newDscp->fid.volume) {
+            code = CM_ERROR_CROSSDEVLINK;
+            goto done;
+        }
 
         /* shouldn't happen that we have distinct vnodes for two
          * different files, but could due to deliberate attack, or
          * stale info.  Avoid deadlocks and quit now.
          */
-        if (oldDscp->fid.vnode == newDscp->fid.vnode)
-            return CM_ERROR_CROSSDEVLINK;
+        if (oldDscp->fid.vnode == newDscp->fid.vnode) {
+            code = CM_ERROR_CROSSDEVLINK;
+            goto done;
+        }
 
         if (oldDscp->fid.vnode < newDscp->fid.vnode) {
             cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
             lock_ObtainWrite(&oldDscp->rw);
-            cm_dnlcRemove(oldDscp, normalizedOldNamep);
+            cm_dnlcRemove(oldDscp, cOldNamep);
             code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
-                              CM_SCACHESYNC_STOREDATA);
+                             CM_SCACHESYNC_STOREDATA);
             lock_ReleaseWrite(&oldDscp->rw);
             if (code != 0)
                 cm_EndDirOp(&oldDirOp);
             if (code == 0) {
                 cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
                 lock_ObtainWrite(&newDscp->rw);
-                cm_dnlcRemove(newDscp, newNamep);
+                cm_dnlcRemove(newDscp, cNewNamep);
                 code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
-                                  CM_SCACHESYNC_STOREDATA);
+                                 CM_SCACHESYNC_STOREDATA);
                 lock_ReleaseWrite(&newDscp->rw);
                 if (code) {
                     cm_EndDirOp(&newDirOp);
@@ -3382,7 +3367,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
             /* lock the new vnode entry first */
             cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
             lock_ObtainWrite(&newDscp->rw);
-            cm_dnlcRemove(newDscp, newNamep);
+            cm_dnlcRemove(newDscp, cNewNamep);
             code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
                               CM_SCACHESYNC_STOREDATA);
             lock_ReleaseWrite(&newDscp->rw);
@@ -3391,7 +3376,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
             if (code == 0) {
                 cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
                 lock_ObtainWrite(&oldDscp->rw);
-                cm_dnlcRemove(oldDscp, normalizedOldNamep);
+                cm_dnlcRemove(oldDscp, cOldNamep);
                 code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
                                   CM_SCACHESYNC_STOREDATA);
                 lock_ReleaseWrite(&oldDscp->rw);
@@ -3409,11 +3394,13 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
         }
     }  /* two distinct vnodes */
 
-    if (code) {
-        return code;
-    }
+    if (code) 
+        goto done;
+
     didEnd = 0;
 
+    newNamep = cm_ClientStringToFsStringAlloc(cNewNamep, -1, NULL);
+
     /* try the RPC now */
     osi_Log2(afsd_logp, "CALL Rename old scp 0x%p new scp 0x%p", 
               oldDscp, newDscp);
@@ -3431,9 +3418,9 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
 
         callp = cm_GetRxConn(connp);
         code = RXAFS_Rename(callp, &oldDirAFSFid, oldNamep,
-                             &newDirAFSFid, newNamep,
-                             &updatedOldDirStatus, &updatedNewDirStatus,
-                             &volSync);
+                            &newDirAFSFid, newNamep,
+                            &updatedOldDirStatus, &updatedNewDirStatus,
+                            &volSync);
         rx_PutConnection(callp);
 
     } while (cm_Analyze(connp, userp, reqp, &oldDscp->fid,
@@ -3455,14 +3442,14 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
 
     if (code == 0)
         cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
-                        userp, CM_MERGEFLAG_DIROP);
+                       userp, CM_MERGEFLAG_DIROP);
     lock_ReleaseWrite(&oldDscp->rw);
 
     if (code == 0) {
         if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
 
 #ifdef USE_BPLUS
-            diropCode = cm_BPlusDirLookup(&oldDirOp, normalizedOldNamep, &fileFid);
+            diropCode = cm_BPlusDirLookup(&oldDirOp, cOldNamep, &fileFid);
             if (diropCode == CM_ERROR_INEXACT_MATCH)
                 diropCode = 0;
             else if (diropCode == EINVAL)
@@ -3473,14 +3460,14 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
                 if (oneDir) {
                     diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
 #ifdef USE_BPLUS
-                    cm_BPlusDirCreateEntry(&oldDirOp, newNamep, &fileFid);
+                    cm_BPlusDirCreateEntry(&oldDirOp, cNewNamep, &fileFid);
 #endif
                 }
-
+                
                 if (diropCode == 0) { 
                     diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
 #ifdef USE_BPLUS
-                    cm_BPlusDirDeleteEntry(&oldDirOp, normalizedOldNamep);
+                    cm_BPlusDirDeleteEntry(&oldDirOp, cOldNamep);
 #endif
                 }
             }
@@ -3508,13 +3495,19 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, char *normalizedOldNamep,
             if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) {
                 cm_DirCreateEntry(&newDirOp, newNamep, &fileFid);
 #ifdef USE_BPLUS
-                cm_BPlusDirCreateEntry(&newDirOp, newNamep, &fileFid);
+                cm_BPlusDirCreateEntry(&newDirOp, cNewNamep, &fileFid);
 #endif
             }
         }
         cm_EndDirOp(&newDirOp);
     }
 
+  done:
+    if (free_oldNamep)
+        free(oldNamep);
+
+    free(newNamep);
+
     /* and return error code */
     return code;
 }
index a72c0b1..280a885 100644 (file)
@@ -18,12 +18,12 @@ extern int cm_followBackupPath;
 
 /* parms for attribute setting call */
 typedef struct cm_attr {
-       int mask;
-       time_t clientModTime;
-        osi_hyper_t length;
-       int unixModeBits;
-        long owner;
-        long group;
+    int         mask;
+    time_t      clientModTime;
+    osi_hyper_t length;
+    int         unixModeBits;
+    long        owner;
+    long        group;
 } cm_attr_t;
 
 #define CM_ATTRMASK_CLIENTMODTIME      1       /* set if field is valid */
@@ -34,18 +34,19 @@ typedef struct cm_attr {
 
 /* type of rock for lookup's searches */
 typedef struct cm_lookupSearch {
-        cm_fid_t fid;
-        char *searchNamep;
-        int found;
-        int LCfound, UCfound, NCfound, ExactFound;
-        int caseFold;
-        int hasTilde;
+    cm_fid_t      fid;
+    fschar_t     *searchNamep;
+    normchar_t   *nsearchNamep;
+    int           found;
+    int           LCfound, UCfound, NCfound, ExactFound;
+    int           caseFold;
+    int           hasTilde;
 } cm_lookupSearch_t;
 
 #include "cm_dir.h"
 
 typedef int (*cm_DirFuncp_t)(struct cm_scache *, struct cm_dirEntry *, void *,
-       osi_hyper_t *entryOffsetp);
+                             osi_hyper_t *entryOffsetp);
 
 /* Special path syntax for direct references to volumes
 
@@ -60,107 +61,99 @@ typedef int (*cm_DirFuncp_t)(struct cm_scache *, struct cm_dirEntry *, void *,
 
 /* arrays */
 
-extern unsigned char cm_foldUpper[];
+extern fschar_t cm_foldUpper[];
 
 /* functions */
 
-extern int cm_NoneLower(char *s);
+extern int cm_NoneLower(normchar_t *s);
 
-extern int cm_NoneUpper(char *s);
-
-extern int cm_Is8Dot3(char *namep);
+extern int cm_NoneUpper(normchar_t *s);
 
 extern int cm_stricmp(const char *, const char *);
 
-extern void cm_Gen8Dot3Name(struct cm_dirEntry *dep, char *shortName,
-       char **shortNameEndp);
-
-#define cm_Gen8Dot3Name(dep,shortName,shortNameEndp) \
-cm_Gen8Dot3NameInt((dep)->name, &(dep)->fid, shortName, shortNameEndp)
-
-extern void cm_Gen8Dot3NameInt(const char * longname, cm_dirFid_t * pfid,
-                               char *shortName, char **shortNameEndp);
-
 extern long cm_ReadMountPoint(cm_scache_t *scp, cm_user_t *userp,
                               cm_req_t *reqp);
 
-extern long cm_EvaluateVolumeReference(char * namep, long flags, cm_user_t * userp,
+extern long cm_EvaluateVolumeReference(clientchar_t * namep, long flags, cm_user_t * userp,
                                        cm_req_t *reqp, cm_scache_t ** outpScpp);
 
 #ifdef DEBUG_REFCOUNT
-extern long cm_NameIDbg(cm_scache_t *rootSCachep, char *pathp, long flags,
-       cm_user_t *userp, char *tidPathp, cm_req_t *reqp,
-       cm_scache_t **outScpp, char *, long);
+extern long cm_NameIDbg(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
+                        cm_user_t *userp, clientchar_t *tidPathp, cm_req_t *reqp,
+                        cm_scache_t **outScpp, char *, long);
 
-extern long cm_LookupDbg(cm_scache_t *dscp, char *namep, long flags,
-       cm_user_t *userp, cm_req_t *reqp, cm_scache_t **outpScpp, char *, long);
+extern long cm_LookupDbg(cm_scache_t *dscp, clientchar_t *namep, long flags,
+                         cm_user_t *userp, cm_req_t *reqp, cm_scache_t **outpScpp,
+                         char *, long);
 
 #define cm_Lookup(a,b,c,d,e,f)  cm_LookupDbg(a,b,c,d,e,f,__FILE__,__LINE__)
 #define cm_NameI(a,b,c,d,e,f,g) cm_NameIDbg(a,b,c,d,e,f,g,__FILE__,__LINE__)
 #else
-extern long cm_NameI(cm_scache_t *rootSCachep, char *pathp, long flags,
-       cm_user_t *userp, char *tidPathp, cm_req_t *reqp,
-       cm_scache_t **outScpp);
-extern long cm_Lookup(cm_scache_t *dscp, char *namep, long flags,
-       cm_user_t *userp, cm_req_t *reqp, cm_scache_t **outpScpp);
+extern long cm_NameI(cm_scache_t *rootSCachep, clientchar_t *pathp, long flags,
+                     cm_user_t *userp, clientchar_t *tidPathp, cm_req_t *reqp,
+                     cm_scache_t **outScpp);
+extern long cm_Lookup(cm_scache_t *dscp, clientchar_t *namep, long flags,
+                      cm_user_t *userp, cm_req_t *reqp, cm_scache_t **outpScpp);
 #endif
 
-extern long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags,
+extern long cm_LookupInternal(cm_scache_t *dscp, clientchar_t *namep, long flags,
                               cm_user_t *userp, cm_req_t *reqp, 
                               cm_scache_t **outpScpp);
 
 extern afs_int32 cm_TryBulkStat(cm_scache_t *dscp, osi_hyper_t *offsetp,
-       cm_user_t *userp, cm_req_t *reqp);
+                                cm_user_t *userp, cm_req_t *reqp);
 
 extern long cm_SetAttr(cm_scache_t *scp, cm_attr_t *attrp, cm_user_t *userp,
-       cm_req_t *reqp);
+                       cm_req_t *reqp);
 
-extern long cm_Create(cm_scache_t *scp, char *namep, long flags,
-       cm_attr_t *attrp, cm_scache_t **scpp, cm_user_t *userp, cm_req_t *reqp);
+extern long cm_Create(cm_scache_t *scp, clientchar_t *namep, long flags,
+                      cm_attr_t *attrp, cm_scache_t **scpp,
+                      cm_user_t *userp, cm_req_t *reqp);
 
 extern long cm_FSync(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp);
 
 extern void cm_StatusFromAttr(struct AFSStoreStatus *statusp,
-       struct cm_scache *scp, struct cm_attr *attrp);
+                              struct cm_scache *scp, struct cm_attr *attrp);
 
-extern long cm_Unlink(cm_scache_t *dscp, char *namep, char * normalizedName,
+extern long cm_Unlink(cm_scache_t *dscp, fschar_t *fnamep,
+                      clientchar_t *cnamep,
                       cm_user_t *userp, cm_req_t *reqp);
 
 extern long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
-       osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp, 
-       cm_scache_t **retscp);
+                        osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp, 
+                        cm_scache_t **retscp);
 
-extern long cm_MakeDir(cm_scache_t *dscp, char *lastNamep, long flags,
-       cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp);
+extern long cm_MakeDir(cm_scache_t *dscp, clientchar_t *lastNamep, long flags,
+                       cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp);
 
-extern long cm_RemoveDir(cm_scache_t *dscp, char *lastNamep, char *originalNamep,
+extern long cm_RemoveDir(cm_scache_t *dscp, fschar_t *lastNamep, clientchar_t *originalNamep,
                          cm_user_t *userp, cm_req_t *reqp);
 
 extern long cm_Rename(cm_scache_t *oldDscp,
-                      char *oldLastNamep, char *normalizedOldNamep,
-                      cm_scache_t *newDscp, char *newLastNamep,
+                      fschar_t *oldLastNamep, clientchar_t *normalizedOldNamep,
+                      cm_scache_t *newDscp, clientchar_t *newLastNamep,
                       cm_user_t *userp, cm_req_t *reqp);
 
 extern long cm_HandleLink(cm_scache_t *linkScp, struct cm_user *userp,
-       cm_req_t *reqp);
+                          cm_req_t *reqp);
 
-extern long cm_Link(cm_scache_t *dscp, char *namep, cm_scache_t *sscp,
-    long flags, cm_user_t *userp, cm_req_t *reqp);
+extern long cm_Link(cm_scache_t *dscp, clientchar_t *namep, cm_scache_t *sscp,
+                    long flags, cm_user_t *userp, cm_req_t *reqp);
 
-extern long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp,
-       long flags, cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp);
+extern long cm_SymLink(cm_scache_t *dscp, clientchar_t *namep, fschar_t *contentsp,
+                       long flags, cm_attr_t *attrp, cm_user_t *userp, cm_req_t *reqp);
 
-extern long cm_AssembleLink(cm_scache_t *linkScp, char *pathSuffixp,
+extern long cm_AssembleLink(cm_scache_t *linkScp, fschar_t *pathSuffixp,
                             cm_scache_t **newRootScpp, cm_space_t **newSpaceBufferp,
                             cm_user_t *userp, cm_req_t *reqp);
 
-extern int cm_ExpandSysName(char *inp, char *outp, long outSize,
+extern int cm_ExpandSysName(clientchar_t *inp, clientchar_t *outp, long outSizeCch,
                             unsigned int sysNameIndex);
 
 extern long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp);
 
 extern long cm_CheckOpen(cm_scache_t *scp, int openMode, int trunc,
-       cm_user_t *userp, cm_req_t *reqp);
+                         cm_user_t *userp, cm_req_t *reqp);
 
 /*
  * Combinations of file opening access bits for AFS.
@@ -180,47 +173,49 @@ typedef struct cm_lock_data {
 } cm_lock_data_t;
 
 extern long cm_CheckNTOpen(cm_scache_t *scp, unsigned int desiredAccess,
-       unsigned int createDisp, cm_user_t *userp, cm_req_t *reqp, cm_lock_data_t ** ldpp);
+                           unsigned int createDisp, cm_user_t *userp,
+                           cm_req_t *reqp, cm_lock_data_t ** ldpp);
 
 extern long cm_CheckNTOpenDone(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp, 
                               cm_lock_data_t ** ldpp);
 
 extern long cm_CheckNTDelete(cm_scache_t *dscp, cm_scache_t *scp,
-       cm_user_t *userp, cm_req_t *reqp);
+                             cm_user_t *userp, cm_req_t *reqp);
 
 extern long cm_EvaluateSymLink(cm_scache_t *dscp, cm_scache_t *linkScp,
-       cm_scache_t **outScpp, cm_user_t *userp, cm_req_t *reqp);
+                               cm_scache_t **outScpp, cm_user_t *userp,
+                               cm_req_t *reqp);
 
 extern long cm_FollowMountPoint(cm_scache_t *scp, cm_scache_t *dscp, cm_user_t *userp,
                                 cm_req_t *reqp, cm_scache_t **outScpp);
 
 
 extern long cm_Lock(cm_scache_t *scp, unsigned char sLockType,
-        LARGE_INTEGER LOffset, LARGE_INTEGER LLength, cm_key_t key,
-       int allowWait, cm_user_t *userp, cm_req_t *reqp,
-       cm_file_lock_t **lockpp);
+                    LARGE_INTEGER LOffset, LARGE_INTEGER LLength, cm_key_t key,
+                    int allowWait, cm_user_t *userp, cm_req_t *reqp,
+                    cm_file_lock_t **lockpp);
 
 #define CM_UNLOCK_BY_FID       0x0001
 
 extern long cm_UnlockByKey(cm_scache_t * scp,
-        cm_key_t key,
-        int flags,
-        cm_user_t * userp,
-        cm_req_t * reqp);
+                           cm_key_t key,
+                           int flags,
+                           cm_user_t * userp,
+                           cm_req_t * reqp);
 
 extern long cm_Unlock(cm_scache_t *scp, unsigned char sLockType,
-        LARGE_INTEGER LOffset, LARGE_INTEGER LLength, cm_key_t key,
-       cm_user_t *userp, cm_req_t *reqp);
+                      LARGE_INTEGER LOffset, LARGE_INTEGER LLength, cm_key_t key,
+                      cm_user_t *userp, cm_req_t *reqp);
 
 extern long cm_LockCheckRead(cm_scache_t *scp, 
-        LARGE_INTEGER LOffset, 
-        LARGE_INTEGER LLength, 
-        cm_key_t key);
+                             LARGE_INTEGER LOffset, 
+                             LARGE_INTEGER LLength, 
+                             cm_key_t key);
 
 extern long cm_LockCheckWrite(cm_scache_t *scp,
-        LARGE_INTEGER LOffset,
-        LARGE_INTEGER LLength,
-        cm_key_t key);
+                              LARGE_INTEGER LOffset,
+                              LARGE_INTEGER LLength,
+                              cm_key_t key);
 
 extern void cm_CheckLocks(void);
 
index e90183a..3f1a2f6 100644 (file)
@@ -40,6 +40,7 @@
 #include <string.h>
 #include <malloc.h>
 #include "afsd.h"
+#include "smb.h"
 #include <WINNT/afsreg.h>
 
 HMODULE hVolStatus = NULL;
@@ -171,7 +172,7 @@ long
 #ifdef _WIN64
 cm_VolStatus_Network_Started(const char * netbios32, const char * netbios64)
 #else /* _WIN64 */
-cm_VolStatus_Network_Started(const char * netbios)
+cm_VolStatus_Network_Started(const char * netbios32)
 #endif /* _WIN64 */
 {
     long code = 0;
@@ -182,7 +183,7 @@ cm_VolStatus_Network_Started(const char * netbios)
 #ifdef _WIN64
     code = dll_funcs.dll_VolStatus_Network_Started(netbios32, netbios64);
 #else
-    code = dll_funcs.dll_VolStatus_Network_Started(netbios, netbios);
+    code = dll_funcs.dll_VolStatus_Network_Started(netbios32, netbios32);
 #endif
 
     return code;
@@ -196,7 +197,7 @@ long
 #ifdef _WIN64
 cm_VolStatus_Network_Stopped(const char * netbios32, const char * netbios64)
 #else /* _WIN64 */
-cm_VolStatus_Network_Stopped(const char * netbios)
+cm_VolStatus_Network_Stopped(const char * netbios32)
 #endif /* _WIN64 */
 {
     long code = 0;
@@ -207,7 +208,7 @@ cm_VolStatus_Network_Stopped(const char * netbios)
 #ifdef _WIN64
     code = dll_funcs.dll_VolStatus_Network_Stopped(netbios32, netbios64);
 #else
-    code = dll_funcs.dll_VolStatus_Network_Stopped(netbios, netbios);
+    code = dll_funcs.dll_VolStatus_Network_Stopped(netbios32, netbios32);
 #endif
 
     return code;
@@ -250,15 +251,21 @@ cm_VolStatus_Change_Notification(afs_uint32 cellID, afs_uint32 volID, enum volst
 
 
 long
-cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp, char *tidPathp, char *pathp)
+cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp, const clientchar_t *ctidPathp,
+                                const clientchar_t *cpathp)
 {
     long code = 0;
     char src[1024], *p;
     size_t len;
+    char * tidPathp = NULL;
+    char * pathp = NULL;
 
     if (hVolStatus == NULL || dll_funcs.version < 2)
         return 0;
 
+    tidPathp = cm_ClientStringToUtf8Alloc(ctidPathp, -1, NULL);
+    pathp = cm_ClientStringToUtf8Alloc(cpathp, -1, NULL);
+
     snprintf(src,sizeof(src), "\\\\%s%s", volstat_NetbiosName, tidPathp);
     len = strlen(src);
     if ((src[len-1] == '\\' || src[len-1] == '/') &&
@@ -275,6 +282,11 @@ cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp, char *tidPathp, char *pathp)
     code = dll_funcs.dll_VolStatus_Notify_DFS_Mapping(scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
                                                       src, scp->mountPointStringp);
 
+    if (tidPathp)
+        free(tidPathp);
+    if (pathp)
+        free(pathp);
+
     return code;
 }
 
@@ -299,6 +311,8 @@ cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cell
     cm_req_t    req;
     cm_scache_t *scp;
     cm_volume_t *volp;
+    clientchar_t * cpath = NULL;
+    clientchar_t * cshare = NULL;
 
     if (cellID == NULL || volID == NULL)
         return CM_ERROR_INVAL;
@@ -308,7 +322,12 @@ cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cell
 
     cm_InitReq(&req);
 
-    code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, cm_rootUserp, (char *)share, &req, &scp);
+    cpath = cm_FsStringToClientStringAlloc(path, -1, NULL);
+    cshare = cm_FsStringToClientStringAlloc(share, -1, NULL);
+
+    code = cm_NameI(cm_data.rootSCachep, cpath,
+                    CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
+                    cm_rootUserp, cshare, &req, &scp);
     if (code)
         goto done;
 
@@ -336,6 +355,11 @@ cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cell
     cm_ReleaseSCache(scp);
 
   done:
+    if (cpath)
+        free(cpath);
+    if (cshare)
+        free(cshare);
+
     osi_Log1(afsd_logp,"cm_VolStatus_Path_To_ID code 0x%x",code); 
     return code;
 }
@@ -347,6 +371,8 @@ cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *
     cm_req_t    req;
     cm_scache_t *scp;
     size_t      len;
+    clientchar_t *cpath = NULL;
+    clientchar_t *cshare = NULL;
 
     if (pBufSize == NULL || (pBuffer == NULL && *pBufSize != 0))
         return CM_ERROR_INVAL;
@@ -356,8 +382,11 @@ cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *
 
     cm_InitReq(&req);
 
-    code = cm_NameI(cm_data.rootSCachep, (char *)path, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, 
-                    cm_rootUserp, (char *)share, &req, &scp);
+    cpath = cm_FsStringToClientStringAlloc(path, -1, NULL);
+    cshare = cm_FsStringToClientStringAlloc(share, -1, NULL);
+
+    code = cm_NameI(cm_data.rootSCachep, cpath, CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW, 
+                    cm_rootUserp, cshare, &req, &scp);
     if (code)
         goto done;
 
@@ -392,6 +421,11 @@ cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *
     cm_ReleaseSCache(scp);
 
   done:
+    if (cpath)
+        free(cpath);
+    if (cshare)
+        free(cshare);
+
     osi_Log1(afsd_logp,"cm_VolStatus_Path_To_DFSlink code 0x%x",code); 
     return code;
 }
index 84016aa..a9d0118 100644 (file)
@@ -42,9 +42,11 @@ extern long cm_VolStatus_Service_Started(void);
 extern long cm_VolStatus_Service_Stopped(void);
 
 #ifdef _WIN64
-extern long cm_VolStatus_Network_Started(const char * netbios32, const char * netbios64);
+extern long cm_VolStatus_Network_Started(const char * netbios32,
+                                         const char * netbios64);
 
-extern long cm_VolStatus_Network_Stopped(const char * netbios32, const char * netbios64);
+extern long cm_VolStatus_Network_Stopped(const char * netbios32,
+                                         const char * netbios64);
 #else /* _WIN64 */
 extern long cm_VolStatus_Network_Started(const char * netbios);
 
@@ -55,11 +57,19 @@ extern long cm_VolStatus_Network_Addr_Change(void);
 
 extern long cm_VolStatus_Change_Notification(afs_uint32 cellID, afs_uint32 volID, enum volstatus status);
 
-extern long __fastcall cm_VolStatus_Path_To_ID(const char * share, const char * path, afs_uint32 * cellID, afs_uint32 * volID, enum volstatus *pstatus);
+extern long __fastcall cm_VolStatus_Path_To_ID(const char * share,
+                                               const char * path,
+                                               afs_uint32 * cellID, afs_uint32 * volID,
+                                               enum volstatus *pstatus);
 
-extern long __fastcall cm_VolStatus_Path_To_DFSlink(const char * share, const char * path, afs_uint32 *pBufSize, char *pBuffer);
+extern long __fastcall cm_VolStatus_Path_To_DFSlink(const char * share,
+                                                    const char * path,
+                                                    afs_uint32 *pBufSize,
+                                                    char *pBuffer);
 
-extern long cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp, char *tidPathp, char *pathp);
+extern long cm_VolStatus_Notify_DFS_Mapping(cm_scache_t *scp,
+                                            const clientchar_t *tidPathp,
+                                            const clientchar_t *pathp);
 
 extern long cm_VolStatus_Invalidate_DFS_Mapping(cm_scache_t *scp);
 
index 91fff17..f073b81 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,13 +179,13 @@ 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 }};
@@ -493,8 +494,9 @@ unsigned int smb_Attributes(cm_scache_t *scp)
 /* Check if the named file/dir is a dotfile/dotdir */
 /* String pointed to by lastComp can have leading slashes, but otherwise should have
    no other patch components */
-unsigned int smb_IsDotFile(char *lastComp) {
-    char *s;
+unsigned int smb_IsDotFile(clientchar_t *lastComp) {
+    clientchar_t *s;
+
     if(lastComp) {
         /* skip over slashes */
         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
@@ -503,12 +505,12 @@ unsigned int smb_IsDotFile(char *lastComp) {
         return 0;
 
     /* nulls, curdir and parent dir doesn't count */
-    if (!*s) 
+    if (!*s)
         return 0;
-    if (*s == '.') {
+    if (*s == _C('.')) {
         if (!*(s + 1)) 
             return 0;
-        if(*(s+1) == '.' && !*(s + 2)) 
+        if(*(s+1) == _C('.') && !*(s + 2)) 
             return 0;
         return 1;
     }
@@ -895,16 +897,16 @@ smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
     return vcp;
 }
 
-int smb_IsStarMask(char *maskp)
+int smb_IsStarMask(clientchar_t *maskp)
 {
     int i;
-    char tc;
+    clientchar_t tc;
         
     for(i=0; i<11; i++) {
         tc = *maskp++;
-        if (tc == '?' || tc == '*' || tc == '>')
+        if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
            return 1;
-    }  
+    }
     return 0;
 }
 
@@ -1087,7 +1089,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));
@@ -1102,7 +1104,7 @@ smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
     }
     lock_ReleaseWrite(&smb_rctLock);
     return tidp;
-}              
+}
 
 void smb_HoldTIDNoLock(smb_tid_t *tidp)
 {
@@ -1147,9 +1149,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;
         }
     }
@@ -1163,22 +1165,23 @@ smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
         vcp->usersp = uidp;
         lock_InitializeMutex(&uidp->mx, "user_t mutex");
         uidp->userID = uid;
-        osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
-                vcp, uidp->userID, 
-                osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
+        osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
+                vcp, uidp->userID,
+                ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
     }
     lock_ReleaseWrite(&smb_rctLock);
     return uidp;
 }              
 
-smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
+smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
+                                   afs_uint32 flags)
 {
     smb_username_t *unp= NULL;
 
     lock_ObtainWrite(&smb_rctLock);
     for(unp = usernamesp; unp; unp = unp->nextp) {
-        if (cm_stricmp_utf8(unp->name, usern) == 0 &&
-            cm_stricmp_utf8(unp->machine, machine) == 0) {
+        if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
+            cm_ClientStrCmpI(unp->machine, machine) == 0) {
             unp->refCount++;
             break;
         }
@@ -1188,8 +1191,8 @@ smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
         memset(unp, 0, sizeof(*unp));
         unp->refCount = 1;
         unp->nextp = usernamesp;
-        unp->name = strdup(usern);
-        unp->machine = strdup(machine);
+        unp->name = cm_ClientStrDup(usern);
+        unp->machine = cm_ClientStrDup(machine);
         usernamesp = unp;
         lock_InitializeMutex(&unp->mx, "username_t mutex");
        if (flags & SMB_FLAG_AFSLOGON)
@@ -1200,7 +1203,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 +1211,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 (cm_stricmp_utf8(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 +1247,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);
@@ -1329,7 +1332,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;
@@ -1539,12 +1542,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 (cm_stricmp_utf8(cursor, str2) == 0)
+        if (cm_ClientStrCmpI(cursor, str2) == 0)
             return cursor;
 
     return NULL;
@@ -1555,25 +1558,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,17 +1587,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;
-    char normName[MAX_PATH];
+    normchar_t normName[MAX_PATH];
 
-    cm_NormalizeUtf8String(dep->name, -1, normName, sizeof(normName)/sizeof(char));
+    cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
 
-    if (!strnicmp(normName, vrock->shareName, 12)) {
-        if(!cm_stricmp_utf8(normName, vrock->shareName))
+    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(normName);
+        vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
         vrock->matchType = matchType;
 
         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
@@ -1606,15 +1608,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;
@@ -1625,18 +1629,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 && cm_stricmp_utf8N(shareName, "all") == 0) {
+    if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
         *pathNamep = NULL;
         return 1;
     }
@@ -1644,17 +1648,17 @@ 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 (cm_stricmp_utf8N(shareName, "ioctl$") == 0) {
-        *pathNamep = strdup("/.__ioctl__");
+    if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
+        *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
         return 1;
     }
 
-    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
-         ) {
+    if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
+        cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
+        ) {
         *pathNamep = NULL;
         return 0;
     }
@@ -1663,25 +1667,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 {
@@ -1690,64 +1693,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 -= (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
@@ -1756,7 +1770,8 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
         cm_req_t req;
         smb_findShare_rock_t vrock;
         osi_hyper_t thyper;
-        char * p = shareName; 
+        fschar_t ftemp[1024];
+        clientchar_t * p = shareName; 
         int rw = 0;
 
         /*  attempt to locate a partial match in root.afs.  This is because
@@ -1766,18 +1781,21 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
         thyper.HighPart = 0;
         thyper.LowPart = 0;
 
-        vrock.shareName = shareName;
+        vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
         vrock.match = NULL;
         vrock.matchType = 0;
 
         cm_HoldSCache(cm_data.rootSCachep);
         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
-            (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
+                           (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
         cm_ReleaseSCache(cm_data.rootSCachep);
 
+        free(vrock.shareName);
+        vrock.shareName = NULL;
+
         if (vrock.matchType) {
-            sprintf(pathName,"/%s/",vrock.match);
-            *pathNamep = strdup(strlwr(pathName));
+            cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
+            *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
             free(vrock.match);
             return 1;
         }
@@ -1789,17 +1807,25 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
             rw = 1;
         }
         /* Get the full name for this cell */
-        code = cm_SearchCellFile(p, temp, 0, 0);
+        cellname = cm_ClientStringToFsStringAlloc(p, cm_ClientStrLen(p), NULL);
+        code = cm_SearchCellFile(cellname, ftemp, 0, 0);
 #ifdef AFS_AFSDB_ENV
         if (code && cm_dnsEnabled) {
             int ttl;
-            code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
+            code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
         }
 #endif
+        if (cellname)
+            free(cellname);
+
         /* construct the path */
-        if (code == 0) {     
-            sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
-            *pathNamep = strdup(strlwr(pathName));
+        if (code == 0) {
+            clientchar_t temp[1024];
+
+            cm_FsStringToClientString(ftemp, cm_FsStrLen(ftemp), temp, 1024);
+            cm_ClientStrPrintfN(pathName, lengthof(pathName),
+                                rw ? _C("/.%S/") : _C("/%S/"), temp);
+            *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
             return 1;
         }
     }
@@ -1814,10 +1840,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;
@@ -1833,19 +1859,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 = cm_stricmp_utf8N("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
+        retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
     }
-    else if (cm_stricmp_utf8N(policy, "documents") == 0)
+    else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
     {
         retval = CSC_POLICY_DOCUMENTS;
     }
-    else if (cm_stricmp_utf8N(policy, "programs") == 0)
+    else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
     {
         retval = CSC_POLICY_PROGRAMS;
     }
-    else if (cm_stricmp_utf8N(policy, "disable") == 0)
+    else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
     {
         retval = CSC_POLICY_DISABLE;
     }
@@ -2312,7 +2338,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) 
@@ -2325,7 +2351,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) 
@@ -2340,7 +2366,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 */
@@ -2354,7 +2380,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) {
@@ -2371,11 +2397,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) {
@@ -2391,8 +2418,8 @@ 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;
 
@@ -2414,8 +2441,8 @@ unsigned char *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
     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;
 
@@ -2434,8 +2461,8 @@ unsigned char *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
     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)
+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))
@@ -2445,8 +2472,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;
 
@@ -2460,15 +2487,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 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;
 
@@ -2499,85 +2526,62 @@ 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, *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_IGNORENULL))
+                *plen += sizeof(wchar_t);
 
             return (unsigned char *) 1; /* return TRUE if we are using unicode */
         }
@@ -2585,17 +2589,31 @@ unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
 #endif
         {
             /* Storing ANSI */
-            size_t len;
 
-            len = strlen(str);
+            int cch_str;
+            int cch_dest;
+
+            cch_str = cm_ClientStrLen(str);
+            cch_dest = cm_ClientStringToUtf8(str, cch_str, NULL, 0);
+
             if (plen)
-                *plen = ((flags & SMB_STRF_IGNORENULL)? len: len+1);
+                *plen = ((flags & SMB_STRF_IGNORENULL)? 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);
         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
@@ -2612,7 +2630,7 @@ 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;
@@ -2623,29 +2641,10 @@ unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
             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,