windows-unicode-20080527
authorAsanka Herath <asanka@secure-endpoints.com>
Tue, 27 May 2008 21:33:14 +0000 (21:33 +0000)
committerJeffrey Altman <jaltman@secure-endpoints.com>
Tue, 27 May 2008 21:33:14 +0000 (21:33 +0000)
LICENSE MIT

An incremental commit.  This patch adds support for normalization of Unicode
but we have concluded that the normalization rules are incorrect.  Normalized
strings should not be written to the file server or returned to the application.

36 files changed:
src/WINNT/afsd/NTMakefile
src/WINNT/afsd/afsd.h
src/WINNT/afsd/afsd_flushvol.c
src/WINNT/afsd/afsd_init.c
src/WINNT/afsd/afslogon.c
src/WINNT/afsd/cm_btree.c
src/WINNT/afsd/cm_btree.h
src/WINNT/afsd/cm_cell.c
src/WINNT/afsd/cm_config.c
src/WINNT/afsd/cm_dir.c
src/WINNT/afsd/cm_dnlc.c
src/WINNT/afsd/cm_dns.c
src/WINNT/afsd/cm_freelance.c
src/WINNT/afsd/cm_ioctl.c
src/WINNT/afsd/cm_nls.c [new file with mode: 0644]
src/WINNT/afsd/cm_nls.h [new file with mode: 0644]
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_volume.c
src/WINNT/afsd/fs.c
src/WINNT/afsd/smb.c
src/WINNT/afsd/smb3.c
src/WINNT/afsd/symlink.c
src/auth/NTMakefile
src/bozo/NTMakefile
src/bucoord/NTMakefile
src/budb/NTMakefile
src/butc/NTMakefile
src/kauth/NTMakefile
src/libafsauthent/NTMakefile
src/ptserver/NTMakefile
src/tbutc/NTMakefile
src/vlserver/NTMakefile
src/volser/NTMakefile

index 4dadd5e..446407b 100644 (file)
@@ -64,6 +64,7 @@ INCFILES =\
        $(INCFILEDIR)\cm_freelance.h \
         $(INCFILEDIR)\cm_memmap.h \
        $(INCFILEDIR)\cm_performance.h \
+        $(INCFILEDIR)\cm_nls.h \
         $(INCFILEDIR)\afsd_eventlog.h \
         $(INCFILEDIR)\afsd_eventmessages.h \
         $(INCFILEDIR)\afskfw.h \
@@ -73,7 +74,8 @@ IDLFILES =\
        afsrpc.h $(OUT)\afsrpc_c.obj
 
 CONFOBJS=$(OUT)\cm_config.obj \
-         $(OUT)\cm_dns.obj
+         $(OUT)\cm_dns.obj \
+         $(OUT)\cm_nls.obj
 
 $(CONFOBJS):
 
@@ -119,6 +121,7 @@ AFSDOBJS=\
        $(OUT)\cm_rpc.obj \
         $(OUT)\cm_memmap.obj \
         $(OUT)\cm_performance.obj \
+        $(OUT)\cm_nls.obj \
        $(OUT)\afsrpc_s.obj \
 !IFDEF OSICRASH
        $(OUT)\afsdcrash.obj \
@@ -133,7 +136,8 @@ $(AFSDOBJS):
 $(OUT)\cm_conn.obj: cm_conn.c
        $(C2OBJ) -DAFS_PTHREAD_ENV /Fo$@ $**
 
-FSOBJS=$(OUT)\fs.obj $(OUT)\fs_utils.obj
+FSOBJS=$(OUT)\fs.obj \
+       $(OUT)\fs_utils.obj
 
 CMDBGOBJS=$(OUT)\cmdebug.obj
 
@@ -224,7 +228,8 @@ LOGON_DLLFILE = $(DESTDIR)\root.client\usr\vice\etc\afslogon.dll
 LOGON_DLLOBJS =\
     $(OUT)\afslogon.obj \
     $(OUT)\logon_ad.obj \
-    $(OUT)\afslogon.res
+    $(OUT)\afslogon.res \
+    $(OUT)\cm_nls.obj
 
 LOGON_DLLLIBS =\
     $(DESTDIR)\lib\afsauthent.lib \
@@ -257,8 +262,9 @@ $(LOGON_DLLFILE): $(LOGON_DLLOBJS) $(LOGON_DLLLIBS)
 ############################################################################
 # Install target; primary makefile target
 
-install_objs: $(OUT)\cm_dns.obj $(OUT)\cm_config.obj $(LANAHELPERLIB) $(OUT)\afsicf.obj
+install_objs: $(OUT)\cm_dns.obj $(OUT)\cm_config.obj $(OUT)\cm_nls.obj $(LANAHELPERLIB) $(OUT)\afsicf.obj
      $(COPY) $(OUT)\cm_dns.obj $(DESTDIR)\lib
+     $(COPY) $(OUT)\cm_nls.obj $(DESTDIR)\lib
      $(COPY) $(OUT)\cm_config.obj $(DESTDIR)\lib
      $(COPY) $(OUT)\afsicf.obj $(DESTDIR)\lib
 
@@ -307,7 +313,8 @@ EXELIBS = \
        $(DESTDIR)\lib\afsrx.lib \
        $(DESTDIR)\lib\afslwp.lib \
        $(DESTDIR)\lib\libosi.lib \
-       $(DESTDIR)\lib\libafsconf.lib
+       $(DESTDIR)\lib\libafsconf.lib \
+        $(DESTDIR)\lib\cm_nls.obj
 
 EXELIBS2 = \
         $(DESTDIR)\lib\afsrpc.lib \
index ceeab6e..a35fad5 100644 (file)
@@ -54,6 +54,7 @@ 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"
index 02300c0..640e9ec 100644 (file)
@@ -152,7 +152,7 @@ afsd_ServicePerformFlushVolumes()
             {
                 // got one!
                 // but we don't want to flush '\\[...]afs\all'
-                if (_stricmp(lpnr->lpRemoteName, pszShareName) == 0)
+                if (cm_stricmp_utf8(lpnr->lpRemoteName, pszShareName) == 0)
                     continue;
                 ++dwTotalVols;
 
index a9e3954..cafbf01 100644 (file)
@@ -300,7 +300,7 @@ configureBackConnectionHostNames(void)
                     (pName - pHostNames < dwSize) && *pName ; 
                     pName += strlen(pName) + 1)
                {
-                   if ( !stricmp(pName, cm_NetbiosName) ) {
+                   if ( !cm_stricmp_utf8(pName, cm_NetbiosName) ) {
                        bNameFound = TRUE;
                        break;
                    }   
index 5a74a35..af03d50 100644 (file)
@@ -370,7 +370,7 @@ GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOpt
     if(domain) {
         dwSize = MAX_COMPUTERNAME_LENGTH;
         if(GetComputerName(computerName, &dwSize)) {
-            if(!stricmp(computerName, domain)) {
+            if(!cm_stricmp_utf8(computerName, domain)) {
                 effDomain = "LOCALHOST";
                 opt->flags = LOGON_FLAG_LOCAL;
             }
@@ -977,7 +977,7 @@ DWORD APIENTRY NPLogonNotify(
                             }
                            p = opt.theseCells;
                            while ( *p ) {
-                                if ( stricmp(p, cell) ) {
+                                if ( cm_stricmp_utf8(p, cell) ) {
                                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
                                     code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
                                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
index ee81843..07f23cf 100644 (file)
@@ -141,7 +141,7 @@ Tree *initBtree(unsigned int poolsz, unsigned int fanout, KeyCmp keyCmp)
 {
     Tree *B;
     keyT empty = {NULL};
-    dataT data = {0,0,0,0};
+    dataT data = {0,0,0,0,0,0,0};
 
     if (fanout > MAX_FANOUT)
         fanout = MAX_FANOUT;
@@ -1293,6 +1293,10 @@ cleanupNodePool(Tree *B)
                 free(getdatavalue(node).longname);
                 getdatavalue(node).longname = NULL;
             }
+            if ( getdatavalue(node).origname ) {
+                free(getdatavalue(node).origname);
+                getdatavalue(node).origname = NULL;
+            }
         } else { /* data node */
             for ( j=1; j<=getfanout(B); j++ ) {
                 if (getkey(node, j).name)
@@ -1555,12 +1559,91 @@ compareKeys(keyT key1, keyT key2, int flags)
 {
     int comp;
 
-    comp = stricmp(key1.name, key2.name);
+    comp = cm_stricmp_utf8(key1.name, key2.name);
     if (comp == 0 && (flags & EXACT_MATCH))
         comp = strcmp(key1.name, key2.name);
     return (comp < 0 ? -1 : (comp > 0 ? 1 : 0));
 }
 
+int
+cm_BPlusDirLookupOriginalName(cm_dirOp_t * op, char * entry,
+                              char ** originalNameRetp)
+{
+    int rc = EINVAL;
+    keyT key = {entry};
+    Nptr leafNode = NONODE;
+    LARGE_INTEGER start, end;
+    char * originalName = NULL;
+
+    if (op->scp->dirBplus == NULL || 
+        op->dataVersion != op->scp->dirDataVersion) {
+        rc = EINVAL;
+        goto done;
+    }
+
+    lock_AssertAny(&op->scp->dirlock);
+
+    QueryPerformanceCounter(&start);
+
+    leafNode = bplus_Lookup(op->scp->dirBplus, key);
+    if (leafNode != NONODE) {
+        int         slot;
+        Nptr        firstDataNode, dataNode, nextDataNode;
+        int         exact = 0;
+        int         count = 0;
+
+        /* Found a leaf that matches the key via a case-insensitive
+         * match.  There may be one or more data nodes that match.
+         * If we have an exact match, return that.
+         * If we have an ambiguous match, return an error.
+         * If we have only one inexact match, return that.
+         */
+        slot = getSlot(op->scp->dirBplus, leafNode);
+        if (slot <= BTERROR) {
+            op->scp->dirDataVersion = 0;
+            rc = (slot == BTERROR ? EINVAL : ENOENT);
+            goto done;
+        }
+        firstDataNode = getnode(leafNode, slot);
+
+        for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
+            count++;
+            if (!comparekeys(op->scp->dirBplus)(key, getdatakey(dataNode), EXACT_MATCH) ) {
+                exact = 1;
+                break;
+            }
+            nextDataNode = getdatanext(dataNode);
+        }
+
+        if (exact) {
+            originalName = getdatavalue(dataNode).origname;
+            rc = 0;
+            bplus_lookup_hits++;
+        } else if (count == 1) {
+            originalName = getdatavalue(firstDataNode).origname;
+            rc = CM_ERROR_INEXACT_MATCH;
+            bplus_lookup_hits_inexact++;
+        } else {
+            rc = CM_ERROR_AMBIGUOUS_FILENAME;
+            bplus_lookup_ambiguous++;
+        } 
+    } else {
+        rc = ENOENT;
+        bplus_lookup_misses++;
+    }
+
+    if (originalName)
+        *originalNameRetp = strdup(originalName);
+
+    QueryPerformanceCounter(&end);
+
+    bplus_lookup_time += (end.QuadPart - start.QuadPart);
+
+  done:
+    return rc;
+
+}
+
 /* Look up a file name in directory.
 
    On entry:
@@ -1669,6 +1752,7 @@ long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
 
     cm_SetFid(&data.fid, cfid->cell, cfid->volume, cfid->vnode, cfid->unique);
     data.longname = NULL;
+    data.origname = NULL;
 
     QueryPerformanceCounter(&start);
     bplus_create_entry++;
@@ -1857,6 +1941,7 @@ int cm_BPlusDirFoo(struct cm_scache *scp, struct cm_dirEntry *dep,
     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)
@@ -1864,6 +1949,8 @@ int cm_BPlusDirFoo(struct cm_scache *scp, struct cm_dirEntry *dep,
     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;
     }
@@ -1878,7 +1965,8 @@ int cm_BPlusDirFoo(struct cm_scache *scp, struct cm_dirEntry *dep,
         cm_Gen8Dot3NameInt(dep->name, &dfid, shortName, NULL);
 
         key.name = shortName;
-        data.longname = strdup(dep->name);
+        data.longname = strdup(key.name);
+        data.origname = NULL;
         insert(scp->dirBplus, key, data);
     }
 
index 695ee33..3e37191 100644 (file)
@@ -55,6 +55,7 @@ typedef struct key {
 typedef struct dirdata {
     cm_fid_t    fid;
     char * longname;
+    char * origname;
 } dataT;
 
 typedef struct entry {
@@ -136,7 +137,9 @@ void        delete(Tree *B, keyT key);
 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);
 long cm_BPlusDirBuildTree(cm_scache_t *scp, cm_user_t *userp, cm_req_t* reqp);
index bf06465..bd605e3 100644 (file)
@@ -149,7 +149,7 @@ cm_cell_t *cm_GetCell_Gen(char *namep, char *newnamep, afs_uint32 flags)
 
     lock_ObtainRead(&cm_cellLock);
     for (cp = cm_data.cellNameHashTablep[hash]; cp; cp=cp->nameNextp) {
-        if (stricmp(namep, cp->name) == 0) {
+        if (cm_stricmp_utf8(namep, cp->name) == 0) {
             strcpy(fullname, cp->name);
             break;
         }
@@ -176,7 +176,7 @@ cm_cell_t *cm_GetCell_Gen(char *namep, char *newnamep, afs_uint32 flags)
          * to the list so check again while holding the write lock 
          */
         for (cp = cm_data.cellNameHashTablep[hash]; cp; cp=cp->nameNextp) {
-            if (stricmp(namep, cp->name) == 0) {
+            if (cm_stricmp_utf8(namep, cp->name) == 0) {
                 strcpy(fullname, cp->name);
                 break;
             }
@@ -245,7 +245,7 @@ cm_cell_t *cm_GetCell_Gen(char *namep, char *newnamep, afs_uint32 flags)
          */
         hash = CM_CELL_NAME_HASH(fullname);
         for (cp2 = cm_data.cellNameHashTablep[hash]; cp2; cp2=cp2->nameNextp) {
-            if (stricmp(fullname, cp2->name) == 0) {
+            if (cm_stricmp_utf8(fullname, cp2->name) == 0) {
                 break;
             }
         }   
index 8812dab..4a885a2 100644 (file)
@@ -93,11 +93,11 @@ IsWindowsModule(const char * name)
     p = strrchr(name, '.');
     if (p) {
        if (i == 1 && 
-           (!stricmp(p,".dll") ||
-            !stricmp(p,".exe") ||
-            !stricmp(p,".ini") ||
-            !stricmp(p,".db") ||
-            !stricmp(p,".drv")))
+           (!cm_stricmp_utf8N(p,".dll") ||
+            !cm_stricmp_utf8N(p,".exe") ||
+            !cm_stricmp_utf8N(p,".ini") ||
+            !cm_stricmp_utf8N(p,".db") ||
+            !cm_stricmp_utf8N(p,".drv")))
            return 1;
     }
     return 0;
@@ -203,8 +203,7 @@ long cm_SearchCellFile(char *cellNamep, char *newCellNamep,
                         inRightCell, osi_LogSaveString(afsd_logp,lineBuffer));
 #endif
            }
-           else if (strnicmp(lineBuffer+1, cellNamep,
-                              strlen(cellNamep)) == 0) {
+           else if (cm_stricmp_utf8(lineBuffer+1, cellNamep) == 0) {
                /* partial match */
                if (partial) {  /* ambiguous */
                    fclose(tfilep);
index d1fdfbd..a49872d 100644 (file)
@@ -572,6 +572,7 @@ cm_DirMakeDir(cm_dirOp_t * op, cm_fid_t * me, cm_fid_t * parent)
     return rc;
 }
 
+
 /* Look up a file name in directory.
 
    On entry:
index 91a474c..7cb8afc 100644 (file)
@@ -230,7 +230,7 @@ cm_dnlcLookup (cm_scache_t *adp, cm_lookupSearch_t* sp)
 
            if ( sp->caseFold )         /* case insensitive */
            {
-            match = cm_stricmp(tnc->name, aname);
+            match = cm_stricmp_utf8(tnc->name, aname);
             if ( !match )      /* something matches */
             {
                 tvc = tnc->vp;
index 5cf72ad..2cd822f 100644 (file)
@@ -15,6 +15,7 @@
 #include <winsock2.h>
 #include "cm_dns_private.h"
 #include "cm_dns.h"
+#include "cm_nls.h"
 #include <lwp.h>
 #include <afs/afsint.h>
 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500)
@@ -687,7 +688,7 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
     char query[1024];
 
 #ifdef AFS_FREELANCE_CLIENT
-    if ( stricmp(cellName, "Freelance.Local.Root") == 0 )
+    if ( cm_stricmp_utf8N(cellName, "Freelance.Local.Root") == 0 )
         return -1;
 #endif /* AFS_FREELANCE_CLIENT */
 
@@ -728,7 +729,7 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
             if(pDnsIter->wType == DNS_TYPE_A)
                 /* check if its for one of the volservers */
                 for (i=0;i<*numServers;i++)
-                    if(stricmp(pDnsIter->pName, cellHostNames[i]) == 0)
+                    if(cm_stricmp_utf8(pDnsIter->pName, cellHostNames[i]) == 0)
                         cellHostAddrs[i] = pDnsIter->Data.A.IpAddress;
         }       
 
@@ -739,14 +740,14 @@ int getAFSServer(char *cellName, int *cellHostAddrs, char cellHostNames[][MAXHOS
                 if (DnsQuery_A(cellHostNames[i], DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &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 && stricmp(cellHostNames[i], pDnsVolIter->pName)==0) {
+                        if (pDnsVolIter->wType == DNS_TYPE_A && cm_stricmp_utf8(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 && stricmp(cellHostNames[i], pDnsVolIter->pName)==0) {
+                        if (pDnsVolIter->wType == DNS_TYPE_CNAME && cm_stricmp_utf8(cellHostNames[i], pDnsVolIter->pName)==0) {
                             for (pDnsCIter=pDnsVolIter; pDnsCIter; pDnsCIter=pDnsCIter->pNext) {
-                                if (pDnsCIter->wType == DNS_TYPE_A && stricmp(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
+                                if (pDnsCIter->wType == DNS_TYPE_A && cm_stricmp_utf8(pDnsVolIter->Data.CNAME.pNameHost, pDnsCIter->pName)==0) {
                                     cellHostAddrs[i] = pDnsCIter->Data.A.IpAddress;
                                     break;
                                 }
index af242f8..873c613 100644 (file)
@@ -846,7 +846,7 @@ long cm_FreelanceMountPointExists(char * filename, int prefix_ok)
             memcpy(shortname, line, cp-line);
             shortname[cp-line]=0;
 
-            if (!stricmp(shortname, filename)) {
+            if (!cm_stricmp_utf8(shortname, filename)) {
                 found = 1;
                 break;
             }
@@ -929,7 +929,7 @@ long cm_FreelanceSymlinkExists(char * filename, int prefix_ok)
             memcpy(shortname, line, cp-line);
             shortname[cp-line]=0;
 
-            if (!stricmp(shortname, filename)) {
+            if (!cm_stricmp_utf8(shortname, filename)) {
                 found = 1;
                 break;
             }
@@ -1196,11 +1196,11 @@ long cm_FreelanceAddSymlink(char *filename, char *destination, cm_fid_t *fidp)
     fullname[0] = '\0';
     if (filename[0] == '.') {
         cm_GetCell_Gen(&filename[1], fullname, CM_FLAG_CREATE);
-        if (stricmp(&filename[1],fullname) == 0)
+        if (cm_stricmp_utf8(&filename[1],fullname) == 0)
             return CM_ERROR_EXISTS;
     } else {
         cm_GetCell_Gen(filename, fullname, CM_FLAG_CREATE);
-        if (stricmp(filename,fullname) == 0)
+        if (cm_stricmp_utf8(filename,fullname) == 0)
             return CM_ERROR_EXISTS;
     }
 
index 2c8e9c0..5c95346 100644 (file)
@@ -37,6 +37,8 @@
 #include <winioctl.h>
 #include <rx\rx.h>
 
+#include "cm_btree.h"
+
 #ifdef _DEBUG
 #include <crtdbg.h>
 #endif
@@ -575,6 +577,10 @@ long cm_ParseIoctlParent(smb_ioctl_t *ioctlp, cm_user_t *userp, cm_req_t *reqp,
         free(inpathp);
     inpathp = NULL;             /* We don't need this from this point on */
 
+    if (free_path)
+        free(inpathp);
+    inpathp = NULL;             /* We don't need this from this point on */
+
     if (tbuffer[0] == tbuffer[1] &&
         tbuffer[1] == '\\' && 
         !_strnicmp(cm_NetbiosName,tbuffer+2,strlen(cm_NetbiosName))) 
@@ -1395,7 +1401,9 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_scache_t *dscp;
     cm_scache_t *scp;
     char *cp;
+    char *originalName = NULL;
     cm_req_t req;
+    cm_dirOp_t dirop;
 
     cm_InitReq(&req);
 
@@ -1425,23 +1433,49 @@ long cm_IoctlDeleteMountPoint(struct smb_ioctl *ioctlp, struct cm_user *userp)
     /* time to make the RPC, so drop the lock */
     lock_ReleaseWrite(&scp->rw);
 
+#ifdef USE_BPLUS
+    code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, &dirop);
+    if (code == 0) {
+        code = cm_BPlusDirLookupOriginalName(&dirop, cp, &originalName);
+        /* The cm_Dir* functions can't be used to lookup the
+           originalName.  Those functions only know of the original
+           name. */
+        cm_EndDirOp(&dirop);
+    }
+#endif
+
+    /* If this name doesn't have a non-normalized name associated with
+       it, we assume that what we had is what is actually present on
+       the file server. */
+
+    if (originalName == NULL) {
+        originalName = cp;
+    }
+
+    /* 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. */
         osi_Log0(afsd_logp,"IoctlDeleteMountPoint from Freelance root dir");
-        code = cm_FreelanceRemoveMount(cp);
+        code = cm_FreelanceRemoveMount(originalName);
     } else 
 #endif
     {
         /* easier to do it this way */
-        code = cm_Unlink(dscp, cp, userp, &req);
+        code = cm_Unlink(dscp, originalName, cp, userp, &req);
     }
     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;
+    }
+
     lock_ObtainWrite(&scp->rw);
   done1:
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
@@ -2289,7 +2323,9 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     cm_scache_t *dscp;
     cm_scache_t *scp;
     char *cp;
+    char * originalName = NULL;
     cm_req_t req;
+    cm_dirOp_t dirop;
 
     cm_InitReq(&req);
 
@@ -2321,17 +2357,39 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
     /* time to make the RPC, so drop the lock */
     lock_ReleaseWrite(&scp->rw);
         
+#ifdef USE_BPLUS
+    code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, &dirop);
+    if (code == 0) {
+        code = cm_BPlusDirLookupOriginalName(&dirop, cp, &originalName);
+        /* cm_Dir*() functions can't be used to lookup the original
+           name since those functions only know of the original
+           name. */
+        cm_EndDirOp(&dirop);
+    }
+#endif
+
+    /* If this name doesn't have a non-normalized name associated with
+       it, we assume that what we had is what is actually present on
+       the file server. */
+
+    if (originalName == NULL)
+        originalName = cp;
+
+    /* 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. */
         osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir");
-        code = cm_FreelanceRemoveSymlink(cp);
+        code = cm_FreelanceRemoveSymlink(originalName);
     } else 
 #endif
     {
         /* easier to do it this way */
-        code = cm_Unlink(dscp, cp, userp, &req);
+        code = cm_Unlink(dscp, originalName, cp, userp, &req);
     }
     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
         smb_NotifyChange(FILE_ACTION_REMOVED,
@@ -2339,6 +2397,11 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp)
                           | FILE_NOTIFY_CHANGE_DIR_NAME,
                           dscp, cp, NULL, TRUE);
 
+    if (originalName != NULL && originalName != cp) {
+        free(originalName);
+        originalName = NULL;
+    }
+
     lock_ObtainWrite(&scp->rw);
   done1:
     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
@@ -2410,7 +2473,7 @@ long cm_UsernameToId(char *uname, cm_ucell_t * ucellp, afs_uint32* uid)
        if (*p == '@')
            r = p;
     }
-    if (r && !stricmp(r+1,ucellp->cellp->name))
+    if (r && !cm_stricmp_utf8(r+1,ucellp->cellp->name))
        *r = '\0';
 
     code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids);
diff --git a/src/WINNT/afsd/cm_nls.c b/src/WINNT/afsd/cm_nls.c
new file mode 100644 (file)
index 0000000..cdeb9e3
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2008 Secure Endpoints Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <windows.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <strsafe.h>
+#include <errno.h>
+
+#define DEBUG_UNICODE
+
+/* This is part of the Microsoft Internationalized Domain Name
+   Mitigation APIs. */
+#include <normalization.h>
+
+int
+(WINAPI *pNormalizeString)( __in NORM_FORM NormForm,
+                            __in_ecount(cwSrcLength) LPCWSTR lpSrcString,
+                            __in int cwSrcLength,
+                            __out_ecount(cwDstLength) LPWSTR lpDstString,
+                            __in int cwDstLength ) = NULL;
+
+BOOL
+(WINAPI *pIsNormalizedString)( __in NORM_FORM NormForm,
+                               __in_ecount(cwLength) LPCWSTR lpString,
+                               __in int cwLength ) = NULL;
+
+
+#define NLSDLLNAME "Normaliz.dll"
+#define NLSMAXCCH  1024
+#define NLSERRCCH  8
+
+#define AFS_NORM_FORM NormalizationC
+
+long cm_InitNormalization(void)
+{
+    HMODULE h_Nls;
+
+    if (pNormalizeString != NULL)
+        return 0;
+
+    h_Nls = LoadLibrary(NLSDLLNAME);
+    if (h_Nls == INVALID_HANDLE_VALUE) {
+        return 1;
+    }
+
+    pNormalizeString = GetProcAddress(h_Nls, "NormalizeString");
+    pIsNormalizedString = GetProcAddress(h_Nls, "IsNormalizedString");
+
+    return (pNormalizeString && pIsNormalizedString);
+}
+
+/* \brief Normalize a UTF-16 string.
+
+   If the supplied destination buffer is insufficient or NULL, then a
+   new buffer will be allocated to hold the normalized string.
+
+   \param[in] src : Source UTF-16 string.  Length is specified in
+       cch_src.
+
+   \param[in] cch_src : The character count in cch_src is assumed to
+       be tight and include the terminating NULL character if there is
+       one.  If the NULL is absent, the resulting string will not be
+       NULL terminated.
+
+   \param[out] ext_dest : The destination buffer.  Can be NULL, in
+       which case *pcch_dest MUST be 0.
+
+   \param[in,out] pcch_dest : On entry *pcch_dest contains a count of
+       characters in the destination buffer.  On exit, it will contain
+       a count of characters that were copied to the destination
+       buffer.
+
+   Returns a pointer to the buffer containing the normalized string or
+   NULL if the call was unsuccessful.  If the returned destination
+   buffer is different from the supplied buffer and non-NULL, it
+   should be freed using free().
+*/
+static wchar_t * 
+NormalizeUtf16String(const wchar_t * src, int cch_src, wchar_t * ext_dest, int *pcch_dest)
+{
+    if ((pIsNormalizedString && (*pIsNormalizedString)(AFS_NORM_FORM, src, cch_src)) ||
+        (!pNormalizeString)) {
+
+        if (ext_dest == NULL || *pcch_dest < cch_src) {
+            ext_dest = malloc(cch_src * sizeof(wchar_t));
+            *pcch_dest = cch_src;
+        }
+
+        /* No need to or unable to normalize.  Just copy the string.
+           Note that the string is not necessarily NULL terminated. */
+
+        if (ext_dest) {
+            memcpy(ext_dest, src, cch_src * sizeof(wchar_t));
+            *pcch_dest = cch_src;
+        } else {
+            *pcch_dest = 0;
+        }
+        return ext_dest;
+
+    } else {
+
+        int rv;
+        DWORD gle;
+        int tries = 10;
+        wchar_t * dest;
+        int cch_dest = *pcch_dest;
+
+        dest = ext_dest;
+
+        while (tries-- > 0) {
+
+            rv = (*pNormalizeString)(AFS_NORM_FORM, src, cch_src, dest, cch_dest);
+
+            if (rv <= 0 && (gle = GetLastError()) != ERROR_SUCCESS) {
+                if (gle == ERROR_INSUFFICIENT_BUFFER) {
+
+                    /* The buffer wasn't big enough.  We are going to
+                       try allocating one. */
+
+                    cch_dest = (-rv) + NLSERRCCH;
+                    goto cont;
+
+                } else {
+                    /* Something else is wrong */
+                    break;
+                }
+
+            } else if (rv < 0) { /* rv < 0 && gle == ERROR_SUCCESS */
+
+                /* Technically not one of the expected outcomes */
+                break;
+
+            } else {            /* rv > 0 || (rv == 0 && gle == ERROR_SUCCESS) */
+
+                /* Possibly succeeded */
+
+                if (rv == 0) { /* Succeeded and the return string is empty */
+                    *pcch_dest = 0;
+                    return dest;
+                }
+
+                if (cch_dest == 0) {
+                    /* Nope.  We only calculated the required size of the buffer */
+
+                    cch_dest = rv + NLSERRCCH;
+                    goto cont;
+                }
+
+                *pcch_dest = rv;
+
+                /* Success! */
+                return dest;
+            }
+
+        cont:
+            if (dest != ext_dest && dest)
+                free(dest);
+            dest = malloc(cch_dest * sizeof(wchar_t));
+        }
+
+        /* Failed */
+
+        if (dest != ext_dest && dest)
+            free(dest);
+
+        *pcch_dest = 0;
+        return NULL;
+    }
+}
+
+/* \brief Normalize a UTF-16 string into a UTF-8 string.
+
+   \param[in] src : Source string.
+
+   \param[in] cch_src : Count of characters in src. If the count includes the
+       NULL terminator, then the resulting string will be NULL
+       terminated.  If it is -1, then src is assumed to be NULL
+       terminated.
+
+   \param[out] adest : Destination buffer.
+
+   \param[in] cch_adest : Number of characters in the destination buffer.
+
+   Returns the number of characters stored into cch_adest. This will
+   include the terminating NULL if cch_src included the terminating
+   NULL or was -1.  If this is 0, then the operation was unsuccessful.
+ */
+long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
+                                   char * adest, int cch_adest)
+{
+    if (cch_src < 0) {
+        size_t cch;
+
+        if (FAILED(StringCchLengthW(src, NLSMAXCCH, &cch)))
+            return E2BIG;
+
+        cch_src = cch+1;
+    }
+
+    {
+        wchar_t nbuf[NLSMAXCCH];
+        wchar_t * normalized;
+        int cch_norm = NLSMAXCCH;
+
+        normalized = NormalizeUtf16String(src, cch_src, nbuf, &cch_norm);
+        if (normalized) {
+            cch_adest = WideCharToMultiByte(CP_UTF8, 0, normalized, cch_norm,
+                                            adest, cch_adest, NULL, 0);
+
+            if (normalized != nbuf && normalized)
+                free(normalized);
+
+            return cch_adest;
+
+        } else {
+
+            return 0;
+
+        }
+    }
+}
+
+#define ESCVAL 0x1000
+#define Esc(c) (ESCVAL + (short)(c))
+#define IS_ESCAPED(c) (((c) & ESCVAL) == ESCVAL)
+
+/* \brief Character sanitization map for CP-1252
+
+   The following map indicates which characters should be escaped in
+   the CP-1252 character map.  Characters that are documented as
+   illegal characters in a file name are marked as escaped.  Escaped
+   characters are marked using the ::Esc macro defined above.  The
+   following exceptions apply:
+
+   - Path delimeters '\\' and '/' are NOT escaped because the
+     sanitization map applies to paths.  While those characters are
+     illegal in filenames, they are legal in paths.
+
+   - Wildcard characters '*' and '?' ARE escaped.  The document
+     referred below does not specify these characters as invalid.
+     Since no other escape mechanism exists, names containing
+     wildcards are indistinguishable from actual wildcards used in SMB
+     requests.
+
+   - Reserved names are not and cannot be represented in this map.
+     Reserved names are :
+
+     CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7,
+     COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9,
+     CLOCK$
+
+   - Characters 0x80, 0x81, 0x8d, 0x8e, 0x8f, 0x90, 0x9d, 0x9e, 0x9f
+     are also escaped because they are unused in CP-1252 and hence
+     cannot be convered to a Unicode string.
+
+     Reserved names with extensions are also invalid. (i.e. NUL.txt)
+
+   \note The only bit we are actually interested in from the following
+     table is the ESCVAL bit.  However, the characters themselves are
+     included for ease of maintenance.
+
+   \see "Naming a File" topic in the Windows SDK.
+ */
+static const short sanitized_escapes_1252[] = {
+    Esc(0x00),Esc(0x01),Esc(0x02),Esc(0x03),Esc(0x04),Esc(0x05),Esc(0x06),Esc(0x07),
+    Esc(0x08),Esc(0x09),Esc(0x0a),Esc(0x0b),Esc(0x0c),Esc(0x0d),Esc(0x0e),Esc(0x0f),
+    Esc(0x10),Esc(0x11),Esc(0x12),Esc(0x13),Esc(0x14),Esc(0x15),Esc(0x16),Esc(0x17),
+    Esc(0x18),Esc(0x19),Esc(0x1a),Esc(0x1b),Esc(0x1c),Esc(0x1d),Esc(0x1e),Esc(0x1f),
+    ' ','!',Esc('"'),'#','$','%','&','\'','(',')',Esc('*'),'+',',','-','.','/',
+    '0','1','2','3','4','5','6','7','8','9',Esc(':'),';',Esc('<'),'=',Esc('>'),Esc('?'),
+    '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
+    'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',
+    '`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
+    'p','q','r','s','t','u','v','w','x','y','z','{',Esc('|'),'}','~',Esc(0x7f),
+    Esc(0x80),Esc(0x81),0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,Esc(0x8d),Esc(0x8e),Esc(0x8f),
+    Esc(0x90),0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,Esc(0x9d),Esc(0x9e),0x9f,
+    0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
+    0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+    0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
+    0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+    0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
+    0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+};
+
+static int sanitize_bytestring(const char * src, int cch_src,
+                                char * odest, int cch_dest)
+{
+    char * dest = odest;
+    while (cch_src > 0 && *src && cch_dest > 0) {
+
+        unsigned short rc;
+
+        rc = sanitized_escapes_1252[*src];
+        if (IS_ESCAPED(rc)) {
+            static const char hex[] = 
+                {'0','1','2','3','4','5','6','7',
+                 '8','9','a','b','c','d','e','f'};
+
+            if (cch_dest < 3) {
+                *dest++ = '\0';
+                return 0;
+            }
+
+            *dest++ = '%';
+            *dest++ = hex[(((int)*src) >> 4) & 0x0f];
+            *dest++ = hex[(((int)*src) & 0x0f)];
+            cch_dest -= 3;
+
+        } else {
+            *dest++ = *src;
+            cch_dest--;
+        }
+
+        cch_src--;
+        src++;
+    }
+
+    if (cch_src > 0 && cch_dest > 0) {
+        *dest++ = '\0';
+    }
+
+    return (int)(dest - odest);
+}
+
+#undef Esc
+#undef IS_ESCAPED
+#undef ESCVAL
+
+/* \brief Normalize a UTF-8 string.
+
+   \param[in] src String to normalize.
+
+   \param[in] cch_src : Count of characters in src.  If this value is
+       -1, then src is assumed to be NULL terminated.  The translated
+       string will be NULL terminated only if this is -1 or the count
+       includes the terminating NULL.
+
+   \param[out] adest : Destination string.  Only considered valid if
+       \a cch_adest is non-zero.
+
+   \param[in] cch_adest : Number of characters in the destination
+       string.  If this is zero, then the return value is the number
+       of bytes required.
+
+   \return If \a cch_adest is non-zero, then the return value is the
+       number of bytes stored into adest.  If \a cch_adest is zero,
+       then the return value is the number of bytes required.  In both
+       cases, the return value is 0 if the call was unsuccessful.
+ */
+long cm_NormalizeUtf8String(const char * src, int cch_src,
+                            char * adest, int cch_adest)
+{
+    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_adest >= 1)
+            *adest = '\0';
+        return 1;
+    }
+
+    if (cch_src == -1) {
+        cch_src = strlen(src) + 1;
+    }
+
+    cch = MultiByteToWideChar(CP_UTF8, 0, 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 = 0;
+    wnorm = NormalizeUtf16String(wsrcbuf, cch, NULL, &cch_norm);
+    if (wnorm == NULL) {
+#ifdef DEBUG_UNICODE
+        DebugBreak();
+#endif
+        return 0;
+    }
+
+    cch = WideCharToMultiByte(CP_UTF8, 0, wnorm,
+                              cch_norm, adest, cch_adest * sizeof(char),
+                              NULL, FALSE);
+
+    if (wnorm)
+        free(wnorm);
+
+    return cch;
+}
+
+/*! \brief Case insensitive comparison with specific length
+
+  \param[in] str1 First string to compare.  Assumed to be encoded in UTF-8.
+
+  \param[in] str2 Second string to compare.  Assumed to be encoded in UTF-8.
+
+  \param[in] n Max byte count.
+
+ */
+int cm_strnicmp_utf8(const char * str1, const char * str2, int n)
+{
+    wchar_t wstr1[NLSMAXCCH];
+    int len1;
+    int len2;
+    wchar_t wstr2[NLSMAXCCH];
+    int rv;
+
+    /* first check for NULL pointers */
+    if (str1 == NULL) {
+        if (str2 == NULL)
+            return 0;
+        else
+            return -1;
+    } else if (str2 == NULL) {
+        return 1;
+    }
+
+    len1 = MultiByteToWideChar(CP_UTF8, 0, str1, n, wstr1, NLSMAXCCH);
+    if (len1 == 0) {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        wstr1[0] = L'\0';
+    }
+
+    len2 = MultiByteToWideChar(CP_UTF8, 0, str2, n, wstr2, NLSMAXCCH);
+    if (len2 == 0) {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        wstr2[0] = L'\0';
+    }
+
+    rv = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wstr1, len1, wstr2, len2);
+    if (rv > 0)
+        return (rv - 2);
+    else {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        return 0;
+    }
+}
+
+int cm_stricmp_utf8(const char * str1, const char * str2)
+{
+    wchar_t wstr1[NLSMAXCCH];
+    int len1;
+    int len2;
+    wchar_t wstr2[NLSMAXCCH];
+    int rv;
+
+    /* first check for NULL pointers */
+    if (str1 == NULL) {
+        if (str2 == NULL)
+            return 0;
+        else
+            return -1;
+    } else if (str2 == NULL) {
+        return 1;
+    }
+
+    len1 = MultiByteToWideChar(CP_UTF8, 0, str1, -1, wstr1, NLSMAXCCH);
+    if (len1 == 0) {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        wstr1[0] = L'\0';
+    }
+
+    len2 = MultiByteToWideChar(CP_UTF8, 0, str2, -1, wstr2, NLSMAXCCH);
+    if (len2 == 0) {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        wstr2[0] = L'\0';
+    }
+
+    rv = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wstr1, len1, wstr2, len2);
+    if (rv > 0)
+        return (rv - 2);
+    else {
+#ifdef DEBUG
+        DebugBreak();
+#endif
+        return 0;
+    }
+}
+
+wchar_t * strupr_utf16(wchar_t * wstr, size_t cbstr)
+{
+    wchar_t wstrd[NLSMAXCCH];
+    int len;
+
+    len = cbstr / sizeof(wchar_t);
+    len = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, wstr, len, wstrd, NLSMAXCCH);
+    StringCbCopyW(wstr, cbstr, wstrd);
+
+    return wstr;
+}
+
+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);
+    if (len == 0)
+        return str;
+
+    len = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, wstr, len, wstrd, NLSMAXCCH);
+
+    len = WideCharToMultiByte(CP_UTF8, 0, wstrd, -1, str, cbstr, NULL, FALSE);
+
+    return str;
+}
+
+char * char_next_utf8(const char * c)
+{
+#define CH (*((const unsigned char *)c))
+
+    if ((CH & 0x80) == 0)
+        return (char *) c+1;
+    else {
+        switch (CH & 0xf0) {
+        case 0xc0:
+        case 0xd0:
+            return (char *) c+2;
+
+        case 0xe0:
+            return (char *) c+3;
+
+        case 0xf0:
+            return (char *) c+4;
+
+        default:
+            return (char *) c+1;
+        }
+    }
+#undef CH
+}
+
+
+char * char_prev_utf8(const char * c)
+{
+#define CH (*((const unsigned char *)c))
+
+    c--;
+
+    if ((CH & 0x80) == 0)
+        return (char *) c;
+    else
+        while ((CH & 0xc0) == 0x80)
+            (char *) c--;
+    return (char *) c;
+
+#undef CH
+}
diff --git a/src/WINNT/afsd/cm_nls.h b/src/WINNT/afsd/cm_nls.h
new file mode 100644 (file)
index 0000000..ba7add3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008 Secure Endpoints Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __CM_NLS_H_ENV__
+#define __CM_NLS_H_ENV__
+
+extern long cm_InitNormalization(void);
+
+extern long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
+                                          char * adest, int cch_adest);
+
+extern long cm_NormalizeUtf8String(const char * src, int cch_src,
+                                   char * adest, int cch_adest);
+
+/* 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);
+#define cm_stricmp_utf8N cm_stricmp_utf8
+
+extern int cm_stricmp_utf8(const char * str1, 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);
+#define cm_strnicmp_utf8N cm_strnicmp_utf8
+
+extern int cm_strnicmp_utf8(const char * str1, const char * str2, int n);
+
+extern char * char_next_utf8(const char * c);
+
+extern char * char_prev_utf8(const char * c);
+
+extern char * strupr_utf8(char * str, size_t cbstr);
+
+#endif
index d9cefeb..68b03de 100644 (file)
@@ -363,275 +363,3 @@ void cm_FreeSpace(cm_space_t *tsp)
         lock_ReleaseWrite(&cm_utilsLock);
 }
 
-/* This is part of the Microsoft Internationalized Domain Name
-   Mitigation APIs. */
-#include <normalization.h>
-
-int
-(WINAPI *pNormalizeString)( __in NORM_FORM NormForm,
-                            __in_ecount(cwSrcLength) LPCWSTR lpSrcString,
-                            __in int cwSrcLength,
-                            __out_ecount(cwDstLength) LPWSTR lpDstString,
-                            __in int cwDstLength ) = NULL;
-
-BOOL
-(WINAPI *pIsNormalizedString)( __in NORM_FORM NormForm,
-                               __in_ecount(cwLength) LPCWSTR lpString,
-                               __in int cwLength ) = NULL;
-
-
-#define NLSDLLNAME "Normaliz.dll"
-#define NLSMAXCCH  1024
-#define NLSERRCCH  8
-
-#define AFS_NORM_FORM NormalizationC
-
-long cm_InitNormalization(void)
-{
-    HMODULE h_Nls;
-
-    if (pNormalizeString != NULL)
-        return 0;
-
-    h_Nls = LoadLibrary(NLSDLLNAME);
-    if (h_Nls == INVALID_HANDLE_VALUE) {
-        afsi_log("Can't load " NLSDLLNAME ": LastError=%d", GetLastError());
-        return 1;
-    }
-
-    pNormalizeString = GetProcAddress(h_Nls, "NormalizeString");
-    pIsNormalizedString = GetProcAddress(h_Nls, "IsNormalizedString");
-
-    return (pNormalizeString && pIsNormalizedString);
-}
-
-/* \brief Normalize a UTF-16 string.
-
-   If the supplied destination buffer is
-   insufficient or NULL, then a new buffer will be allocated to hold
-   the normalized string.
-
-   \param[in] src : Source UTF-16 string.  Length is specified in
-       cch_src.
-
-   \param[in] cch_src : The character count in cch_src is assumed to
-       be tight and include the terminating NULL character if there is
-       one.  If the NULL is absent, the resulting string will not be
-       NULL terminated.
-
-   \param[out] ext_dest : The destination buffer.  Can be NULL, in
-       which case *pcch_dest MUST be NULL.
-
-   \param[in,out] pcch_dest : On entry *pcch_dest contains a count of
-       characters in the destination buffer.  On exit, it will contain
-       a count of characters that were copied to the destination
-       buffer.
-
-   Returns a pointer to the buffer containing the normalized string or
-   NULL if the call was unsuccessful.  If the returned destination
-   buffer is different from the supplied buffer and non-NULL, it
-   should be freed using free().
-*/
-static wchar_t * 
-NormalizeUtf16String(const wchar_t * src, int cch_src, wchar_t * ext_dest, int *pcch_dest)
-{
-    if ((pIsNormalizedString && (*pIsNormalizedString)(AFS_NORM_FORM, src, cch_src)) ||
-        (!pNormalizeString)) {
-
-        /* No need to or unable to normalize.  Just copy the string */
-        if (SUCCEEDED(StringCchCopyNW(ext_dest, *pcch_dest, src, cch_src))) {
-            *pcch_dest = cch_src;
-            return ext_dest;
-        } else {
-            *pcch_dest = 0;
-            return NULL;
-        }
-    } else {
-
-        int rv;
-        DWORD gle;
-        int tries = 10;
-        wchar_t * dest;
-        int cch_dest = *pcch_dest;
-
-        dest = ext_dest;
-
-        while (tries-- > 0) {
-
-            rv = (*pNormalizeString)(AFS_NORM_FORM, src, cch_src, dest, cch_dest);
-
-            if (rv <= 0 && (gle = GetLastError()) != ERROR_SUCCESS) {
-#ifdef DEBUG
-                osi_Log1(afsd_logp, "NormalizeUtf16String error = %d", gle);
-#endif
-                if (gle == ERROR_INSUFFICIENT_BUFFER) {
-
-                    /* The buffer wasn't big enough.  We are going to
-                       try allocating one. */
-
-                    cch_dest = (-rv) + NLSERRCCH;
-                    goto cont;
-
-                } else {
-                    /* Something else is wrong */
-                    break;
-                }
-
-            } else if (rv < 0) { /* rv < 0 && gle == ERROR_SUCCESS */
-
-                /* Technically not one of the expected outcomes */
-                break;
-
-            } else {            /* rv > 0 || (rv == 0 && gle == ERROR_SUCCESS) */
-
-                /* Possibly succeeded */
-
-                if (rv == 0) { /* Succeeded and the return string is empty */
-                    *pcch_dest = 0;
-                    return dest;
-                }
-
-                if (cch_dest == 0) {
-                    /* Nope.  We only calculated the required size of the buffer */
-
-                    cch_dest = rv + NLSERRCCH;
-                    goto cont;
-                }
-
-                *pcch_dest = rv;
-
-                /* Success! */
-                return dest;
-            }
-
-        cont:
-            if (dest != ext_dest && dest)
-                free(dest);
-            dest = malloc(cch_dest * sizeof(wchar_t));
-        }
-
-        /* Failed */
-
-        if (dest != ext_dest && dest)
-            free(dest);
-
-        *pcch_dest = 0;
-        return NULL;
-    }
-}
-
-/* \brief Normalize a UTF-16 string into a UTF-8 string.
-
-   \param[in] src : Source string.
-
-   \param[in] cch_src : Count of characters in src. If the count includes the
-       NULL terminator, then the resulting string will be NULL
-       terminated.  If it is -1, then src is assumed to be NULL
-       terminated.
-
-   \param[out] adest : Destination buffer.
-
-   \param[in] cch_adest : Number of characters in the destination buffer.
-
-   Returns the number of characters stored into cch_adest. This will
-   include the terminating NULL if cch_src included the terminating
-   NULL or was -1.  If this is 0, then the operation was unsuccessful.
- */
-long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
-                                   char * adest, int cch_adest)
-{
-    if (cch_src < 0) {
-        size_t cch;
-
-        if (FAILED(StringCchLengthW(src, NLSMAXCCH, &cch)))
-            return CM_ERROR_TOOBIG;
-
-        cch_src = cch+1;
-    }
-
-    {
-        wchar_t nbuf[NLSMAXCCH];
-        wchar_t * normalized;
-        int cch_norm = NLSMAXCCH;
-
-        normalized = NormalizeUtf16String(src, cch_src, nbuf, &cch_norm);
-        if (normalized) {
-            cch_adest = WideCharToMultiByte(CP_UTF8, 0, normalized, cch_norm,
-                                            adest, cch_adest, NULL, 0);
-
-            if (normalized != nbuf && normalized)
-                free(normalized);
-
-            return cch_adest;
-
-        } else {
-
-            return 0;
-
-        }
-    }
-}
-
-
-/* \brief Normalize a UTF-8 string.
-
-   \param[in] src String to normalize.
-
-   \param[in] cch_src : Count of characters in src.  If this value is
-       -1, then src is assumed to be NULL terminated.  The translated
-       string will be NULL terminated only if this is -1 or the count
-       includes the terminating NULL.
-
-   \param[out] adest : Destination string.
-
-   \param[in] cch_adest : Number of characters in the destination
-       string.
-
-   Returns the number of characters stored into adest or 0 if the call
-   was unsuccessful.
- */
-long cm_NormalizeUtf8String(const char * src, int cch_src,
-                            char * adest, int cch_adest)
-{
-    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') {
-        *adest = '\0';
-        return 1;
-    }
-
-    cch = MultiByteToWideChar(CP_UTF8, 0, src, cch_src * sizeof(char),
-                             wsrcbuf, NLSMAXCCH);
-
-    if (cch == 0) {
-#ifdef DEBUG
-        DebugBreak();
-#endif
-        return 0;
-    }
-
-    cch_norm = 0;
-    wnorm = NormalizeUtf16String(wsrcbuf, cch, NULL, &cch_norm);
-    if (wnorm == NULL) {
-#ifdef DEBUG
-        DebugBreak();
-#endif
-        return 0;
-    }
-
-    cch = WideCharToMultiByte(CP_UTF8, 0, wnorm, cch_norm,
-                              adest, cch_adest * sizeof(char),
-                              NULL, FALSE);
-
-    if (wnorm)
-        free(wnorm);
-
-    return cch;
-}
index 06523bf..a157d92 100644 (file)
@@ -25,12 +25,9 @@ extern cm_space_t *cm_GetSpace(void);
 extern void cm_FreeSpace(cm_space_t *);
 
 extern long cm_MapRPCError(long error, cm_req_t *reqp);
+
 extern long cm_MapRPCErrorRmdir(long error, cm_req_t *reqp);
+
 extern long cm_MapVLRPCError(long error, cm_req_t *reqp);
 
-extern long cm_InitNormalization(void);
-extern long cm_NormalizeUtf16StringToUtf8(const wchar_t * src, int cch_src,
-                                          char * adest, int cch_adest);
-extern long cm_NormalizeUtf8String(const char * src, int cch_src,
-                                   char * adest, int cch_adest);
 #endif /*  __CM_UTILS_H_ENV__ */
index 67163b6..694e203 100644 (file)
@@ -869,26 +869,27 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 {
     cm_lookupSearch_t *sp;
     int match;
-    char shortName[13];
-    char *matchName;
+    char matchName[MAX_PATH];
+    int looking_for_short_name = FALSE;
 
     sp = (cm_lookupSearch_t *) rockp;
 
-    matchName = dep->name;
+    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
     if (sp->caseFold)
-        match = cm_stricmp(matchName, sp->searchNamep);
+        match = cm_stricmp_utf8(matchName, sp->searchNamep);
     else
         match = strcmp(matchName, sp->searchNamep);
 
     if (match != 0
          && sp->hasTilde
          && !cm_Is8Dot3(dep->name)) {
-        matchName = shortName;
-        cm_Gen8Dot3Name(dep, shortName, NULL);
+
+        cm_Gen8Dot3Name(dep, matchName, NULL);
         if (sp->caseFold)
-            match = cm_stricmp(matchName, sp->searchNamep);
+            match = cm_stricmp_utf8(matchName, sp->searchNamep);
         else
             match = strcmp(matchName, sp->searchNamep);
+        looking_for_short_name = TRUE;
     }
 
     if (match != 0)
@@ -898,7 +899,7 @@ long cm_LookupSearchProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
     if (!sp->caseFold) 
         sp->ExactFound = 1;
 
-    if (!sp->caseFold || matchName == shortName) {
+    if (!sp->caseFold || looking_for_short_name) {
         cm_SetFid(&sp->fid, sp->fid.cell, sp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
         return CM_ERROR_STOPNOW;
     }
@@ -1281,7 +1282,7 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
                     found = 1;
                     if (!cm_FreelanceMountPointExists(fullname, 0))
                         code = cm_FreelanceAddMount(fullname, &fullname[1], "root.cell.", 1, &rock.fid);
-                    if ( stricmp(&namep[1], &fullname[1]) && 
+                    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);
@@ -1291,7 +1292,7 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
                     found = 1;
                     if (!cm_FreelanceMountPointExists(fullname, 0))
                         code = cm_FreelanceAddMount(fullname, fullname, "root.cell.", 0, &rock.fid);
-                    if ( stricmp(namep, fullname) && 
+                    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);
@@ -1360,8 +1361,10 @@ long cm_LookupInternal(cm_scache_t *dscp, char *namep, long flags, cm_user_t *us
     if ( !dnlcHit && !(flags & CM_FLAG_NOMOUNTCHASE) && rock.ExactFound ) {
         /* lock the directory entry to prevent racing callback revokes */
         lock_ObtainRead(&dscp->rw);
-        if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 )
+        if ( dscp->cbServerp != NULL && dscp->cbExpires > 0 ) {
+            /* Note: namep is a normalized name */
             cm_dnlcEnter(dscp, namep, tscp);
+        }
         lock_ReleaseRead(&dscp->rw);
     }
 
@@ -1521,7 +1524,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 ( stricmp(namep,SMB_IOCTL_FILENAME_NOSLASH) == 0 ) {
+    if ( cm_stricmp_utf8N(namep,SMB_IOCTL_FILENAME_NOSLASH) == 0 ) {
         if (flags & CM_FLAG_CHECKPATH)
             return CM_ERROR_NOSUCHPATH;
         else
@@ -1578,7 +1581,26 @@ long cm_Lookup(cm_scache_t *dscp, char *namep, long flags, cm_user_t *userp,
         return CM_ERROR_NOSUCHFILE;
 }
 
-long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
+/*! \brief Unlink a file name
+
+  Encapsulates a call to RXAFS_RemoveFile().
+
+  \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
+      name that will be passed into the RXAFS_RemoveFile() call.
+
+  \param[in] normalizedName Normalized 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,
+               cm_user_t *userp, cm_req_t *reqp)
 {
     long code;
     cm_conn_t *connp;
@@ -1638,7 +1660,7 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
         dirop.lockType = CM_DIRLOCK_WRITE;
     }
     lock_ObtainWrite(&dscp->rw);
-    cm_dnlcRemove(dscp, namep);
+    cm_dnlcRemove(dscp, normalizedName);
     cm_SyncOpDone(dscp, NULL, sflags);
     if (code == 0) {
         cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
@@ -1651,10 +1673,10 @@ long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp, cm_req_t *reqp)
     }
     lock_ReleaseWrite(&dscp->rw);
 
-    if (code == 0 && cm_CheckDirOpForSingleChange(&dirop)) {
+    if (code == 0 && cm_CheckDirOpForSingleChange(&dirop) && normalizedName) {
         cm_DirDeleteEntry(&dirop, namep);
 #ifdef USE_BPLUS
-        cm_BPlusDirDeleteEntry(&dirop, namep);
+        cm_BPlusDirDeleteEntry(&dirop, normalizedName);
 #endif
     }
     cm_EndDirOp(&dirop);
@@ -3112,8 +3134,26 @@ long cm_SymLink(cm_scache_t *dscp, char *namep, char *contentsp, long flags,
     return code;
 }
 
-long cm_RemoveDir(cm_scache_t *dscp, char *namep, cm_user_t *userp,
-                   cm_req_t *reqp)
+/*! \brief Remove a directory
+
+  Encapsulates a call to RXAFS_RemoveDir().
+
+  \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] normalizedNamep 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)
 {
     cm_conn_t *connp;
     long code;
@@ -3170,16 +3210,16 @@ long cm_RemoveDir(cm_scache_t *dscp, char *namep, cm_user_t *userp,
     lock_ObtainWrite(&dscp->rw);
     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
     if (code == 0) {
-        cm_dnlcRemove(dscp, namep); 
+        cm_dnlcRemove(dscp, normalizedNamep); 
         cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, CM_MERGEFLAG_DIROP);
     }
     lock_ReleaseWrite(&dscp->rw);
 
     if (code == 0) {
-        if (cm_CheckDirOpForSingleChange(&dirop)) {
+        if (cm_CheckDirOpForSingleChange(&dirop) && normalizedNamep != NULL) {
             cm_DirDeleteEntry(&dirop, namep);
 #ifdef USE_BPLUS
-            cm_BPlusDirDeleteEntry(&dirop, namep);
+            cm_BPlusDirDeleteEntry(&dirop, normalizedNamep);
 #endif
         }
     }
@@ -3207,8 +3247,32 @@ long cm_Open(cm_scache_t *scp, int type, cm_user_t *userp)
     return 0;
 }       
 
-long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
-                char *newNamep, cm_user_t *userp, cm_req_t *reqp)
+/*! \brief Rename a file or directory
+
+  Encapsulates a RXAFS_Rename() call.
+
+  \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] normalizedOldNamep Normalized old name.  This is used for
+  updating local directory caches.
+
+  \param[in] newDscp cm_scache_t for the directory containing the new
+  name.
+
+  \param[in] newNamep New name. Normalized.
+
+  \param[in] userp cm_user_t for the request.
+
+  \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,
+               cm_req_t *reqp)
 {
     cm_conn_t *connp;
     long code;
@@ -3238,7 +3302,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
         oneDir = 1;
         cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
         lock_ObtainWrite(&oldDscp->rw);
-        cm_dnlcRemove(oldDscp, oldNamep);
+        cm_dnlcRemove(oldDscp, normalizedOldNamep);
         cm_dnlcRemove(oldDscp, newNamep);
         code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
                           CM_SCACHESYNC_STOREDATA);
@@ -3264,7 +3328,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
         if (oldDscp->fid.vnode < newDscp->fid.vnode) {
             cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
             lock_ObtainWrite(&oldDscp->rw);
-            cm_dnlcRemove(oldDscp, oldNamep);
+            cm_dnlcRemove(oldDscp, normalizedOldNamep);
             code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
                               CM_SCACHESYNC_STOREDATA);
             lock_ReleaseWrite(&oldDscp->rw);
@@ -3302,7 +3366,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
             if (code == 0) {
                 cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
                 lock_ObtainWrite(&oldDscp->rw);
-                cm_dnlcRemove(oldDscp, oldNamep);
+                cm_dnlcRemove(oldDscp, normalizedOldNamep);
                 code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
                                   CM_SCACHESYNC_STOREDATA);
                 lock_ReleaseWrite(&oldDscp->rw);
@@ -3373,7 +3437,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
         if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
 
 #ifdef USE_BPLUS
-            diropCode = cm_BPlusDirLookup(&oldDirOp, oldNamep, &fileFid);
+            diropCode = cm_BPlusDirLookup(&oldDirOp, normalizedOldNamep, &fileFid);
             if (diropCode == CM_ERROR_INEXACT_MATCH)
                 diropCode = 0;
             else if (diropCode == EINVAL)
@@ -3391,7 +3455,7 @@ long cm_Rename(cm_scache_t *oldDscp, char *oldNamep, cm_scache_t *newDscp,
                 if (diropCode == 0) { 
                     diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
 #ifdef USE_BPLUS
-                    cm_BPlusDirDeleteEntry(&oldDirOp, oldNamep);
+                    cm_BPlusDirDeleteEntry(&oldDirOp, normalizedOldNamep);
 #endif
                 }
             }
index 61105a5..a72c0b1 100644 (file)
@@ -123,8 +123,8 @@ 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);
 
-extern long cm_Unlink(cm_scache_t *dscp, char *namep, cm_user_t *userp,
-       cm_req_t *reqp);
+extern long cm_Unlink(cm_scache_t *dscp, char *namep, char * normalizedName,
+                      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, 
@@ -133,12 +133,13 @@ extern long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
 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_RemoveDir(cm_scache_t *dscp, char *lastNamep, cm_user_t *userp,
-       cm_req_t *reqp);
+extern long cm_RemoveDir(cm_scache_t *dscp, char *lastNamep, char *originalNamep,
+                         cm_user_t *userp, cm_req_t *reqp);
 
-extern long cm_Rename(cm_scache_t *oldDscp, char *oldLastNamep,
-       cm_scache_t *newDscp, char *newLastNamep, 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,
+                      cm_user_t *userp, cm_req_t *reqp);
 
 extern long cm_HandleLink(cm_scache_t *linkScp, struct cm_user *userp,
        cm_req_t *reqp);
index ffe8ef1..2ed1e3c 100644 (file)
@@ -1656,9 +1656,9 @@ cm_VolumeStateByName(cm_volume_t *volp, char *volname)
     size_t len = strlen(volname);
     cm_vol_state_t *statep;
 
-    if (stricmp(".readonly", &volname[len-9]) == 0)
+    if (cm_stricmp_utf8N(".readonly", &volname[len-9]) == 0)
         statep = &volp->vol[ROVOL];
-    else if (stricmp(".backup", &volname[len-7]) == 0)
+    else if (cm_stricmp_utf8N(".backup", &volname[len-7]) == 0)
         statep = &volp->vol[BACKVOL];
     else 
         statep = &volp->vol[RWVOL];
index aa38069..3022855 100644 (file)
@@ -271,7 +271,7 @@ IsFreelanceRoot(char *apath)
 
     code = pioctl_utf8(apath, VIOC_FILE_CELL_NAME, &blob, 1);
     if (code == 0)
-        return !stricmp("Freelance.Local.Root",space);
+        return !cm_stricmp_utf8N("Freelance.Local.Root",space);
     return 1;   /* assume it is because it is more restrictive that way */
 }
 
index 76cf54a..841991c 100644 (file)
@@ -1177,8 +1177,8 @@ smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
 
     lock_ObtainWrite(&smb_rctLock);
     for(unp = usernamesp; unp; unp = unp->nextp) {
-        if (stricmp(unp->name, usern) == 0 &&
-             stricmp(unp->machine, machine) == 0) {
+        if (cm_stricmp_utf8(unp->name, usern) == 0 &&
+            cm_stricmp_utf8(unp->machine, machine) == 0) {
             unp->refCount++;
             break;
         }
@@ -1208,7 +1208,7 @@ smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
         if (!uidp->unp) 
             continue;
-        if (stricmp(uidp->unp->name, usern) == 0) {
+        if (cm_stricmp_utf8(uidp->unp->name, usern) == 0) {
             uidp->refCount++;
             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
                     vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
@@ -1544,7 +1544,7 @@ static char *smb_stristr(char *str1, char *str2)
     char *cursor;
 
     for (cursor = str1; *cursor; cursor++)
-        if (stricmp(cursor, str2) == 0)
+        if (cm_stricmp_utf8(cursor, str2) == 0)
             return cursor;
 
     return NULL;
@@ -1585,13 +1585,17 @@ long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
 {
     int matchType = 0;
     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
-    if (!strnicmp(dep->name, vrock->shareName, 12)) {
-        if(!stricmp(dep->name, vrock->shareName))
+    char normName[MAX_PATH];
+
+    cm_NormalizeUtf8String(dep->name, -1, normName, sizeof(normName)/sizeof(char));
+
+    if (!strnicmp(normName, vrock->shareName, 12)) {
+        if(!cm_stricmp_utf8(normName, vrock->shareName))
             matchType = SMB_FINDSHARE_EXACT_MATCH;
         else
             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
         if(vrock->match) free(vrock->match);
-        vrock->match = strdup(dep->name);
+        vrock->match = strdup(normName);
         vrock->matchType = matchType;
 
         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
@@ -1632,7 +1636,7 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
         RegCloseKey (parmKey);
     }
 
-    if (allSubmount && _stricmp(shareName, "all") == 0) {
+    if (allSubmount && cm_stricmp_utf8N(shareName, "all") == 0) {
         *pathNamep = NULL;
         return 1;
     }
@@ -1640,16 +1644,16 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
     /* In case, the all share is disabled we need to still be able
      * to handle ioctl requests 
      */
-    if (_stricmp(shareName, "ioctl$") == 0) {
+    if (cm_stricmp_utf8N(shareName, "ioctl$") == 0) {
         *pathNamep = strdup("/.__ioctl__");
         return 1;
     }
 
-    if (_stricmp(shareName, "IPC$") == 0 ||
-        _stricmp(shareName, "srvsvc") == 0 ||
-        _stricmp(shareName, "wkssvc") == 0 ||
-        _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
-        _stricmp(shareName, "DESKTOP.INI") == 0
+    if (cm_stricmp_utf8N(shareName, "IPC$") == 0 ||
+        cm_stricmp_utf8N(shareName, "srvsvc") == 0 ||
+        cm_stricmp_utf8N(shareName, "wkssvc") == 0 ||
+        cm_stricmp_utf8N(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
+        cm_stricmp_utf8N(shareName, "DESKTOP.INI") == 0
          ) {
         *pathNamep = NULL;
         return 0;
@@ -1831,17 +1835,17 @@ int smb_FindShareCSCPolicy(char *shareName)
     len = sizeof(policy);
     if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
          len == 0) {
-        retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
+        retval = cm_stricmp_utf8N("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
     }
-    else if (stricmp(policy, "documents") == 0)
+    else if (cm_stricmp_utf8N(policy, "documents") == 0)
     {
         retval = CSC_POLICY_DOCUMENTS;
     }
-    else if (stricmp(policy, "programs") == 0)
+    else if (cm_stricmp_utf8N(policy, "programs") == 0)
     {
         retval = CSC_POLICY_PROGRAMS;
     }
-    else if (stricmp(policy, "disable") == 0)
+    else if (cm_stricmp_utf8N(policy, "disable") == 0)
     {
         retval = CSC_POLICY_DISABLE;
     }
@@ -4979,7 +4983,7 @@ long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_pack
     spacep = inp->spacep;
     smb_StripLastComponent(spacep->data, &lastComp, pathp);
 #ifndef SPECIAL_FOLDERS
-    if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
+    if (lastComp && cm_stricmp_utf8N(lastComp, "\\desktop.ini") == 0) {
         code = cm_NameI(rootScp, spacep->data,
                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
                         userp, tidPathp, &req, &dscp);
@@ -5267,8 +5271,7 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     smb_unlinkRock_t *rockp;
     int caseFold;
     int match;
-    char shortName[13];
-    char *matchName;
+    char matchName[MAX_PATH];
         
     rockp = vrockp;
 
@@ -5276,13 +5279,12 @@ int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
         caseFold |= CM_FLAG_8DOT3;
 
-    matchName = dep->name;
+    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
     match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
     if (!match &&
          (rockp->flags & SMB_MASKFLAG_TILDE) &&
          !cm_Is8Dot3(dep->name)) {
-        cm_Gen8Dot3Name(dep, shortName, NULL);
-        matchName = shortName;
+        cm_Gen8Dot3Name(dep, matchName, NULL);
         /* 8.3 matches are always case insensitive */
         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
     }
@@ -5404,15 +5406,22 @@ long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         cm_dirEntryList_t * entry;
 
         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
+            char normalizedName[MAX_PATH];
+
+            /* Note: entry->name is a non-normalized name */
 
             osi_Log1(smb_logp, "Unlinking %s",
                      osi_LogSaveString(smb_logp, entry->name));
-            code = cm_Unlink(dscp, entry->name, userp, &req);
+
+            cm_NormalizeUtf8String(entry->name, -1, normalizedName,
+                                   sizeof(normalizedName)/sizeof(char));
+
+            code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
 
             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                 smb_NotifyChange(FILE_ACTION_REMOVED,
                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
-                                 dscp, entry->name, NULL, TRUE);
+                                 dscp, normalizedName, NULL, TRUE);
         }
     }
 
@@ -5436,7 +5445,8 @@ typedef struct smb_renameRock {
     char *maskp;               /* pointer to star pattern of old file name */
     int flags;             /* tilde, casefold, etc */
     char *newNamep;            /* ptr to the new file's name */
-    char oldName[MAX_PATH];
+    char oldName[MAX_PATH];     /* non-normalized name */
+    char normalizedOldName[MAX_PATH]; /* normalized name */
     int any;
 } smb_renameRock_t;
 
@@ -5446,26 +5456,28 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     smb_renameRock_t *rockp;
     int caseFold;
     int match;
-    char shortName[13]="";
+    char matchName[MAX_PATH];
 
     rockp = (smb_renameRock_t *) vrockp;
 
+    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
         caseFold |= CM_FLAG_8DOT3;
 
-    match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
+    match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
     if (!match &&
         (rockp->flags & SMB_MASKFLAG_TILDE) &&
          !cm_Is8Dot3(dep->name)) {
-        cm_Gen8Dot3Name(dep, shortName, NULL);
-        match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
+        cm_Gen8Dot3Name(dep, matchName, NULL);
+        match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
     }
 
     if (match) {
        rockp->any = 1;
-        strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
-        rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
+        StringCbCopyA(rockp->oldName, sizeof(rockp->oldName), dep->name);
+        StringCbCopyA(rockp->normalizedOldName, sizeof(rockp->normalizedOldName),
+                      matchName);
             code = CM_ERROR_STOPNOW;
     } else {
        code = 0;
@@ -5577,6 +5589,7 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
     rock.newNamep = newLastNamep;
     rock.oldName[0] = '\0';
+    rock.normalizedOldName[0] = '\0';
     rock.any = 0;
 
     /* Check if the file already exists; if so return error */
@@ -5590,7 +5603,7 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
         /* Check if the old and the new names differ only in case. If so return
          * success, else return CM_ERROR_EXISTS 
          */
-        if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
+        if (!code && oldDscp == newDscp && !cm_stricmp_utf8(oldLastNamep, newLastNamep)) {
 
             /* This would be a success only if the old file is *as same as* the new file */
             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
@@ -5632,7 +5645,7 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
 
     if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
-       code = cm_Rename(rock.odscp, rock.oldName,
+       code = cm_Rename(rock.odscp, rock.oldName, rock.normalizedOldName,
                          rock.ndscp, rock.newNamep, rock.userp,
                          rock.reqp);   
         /* if the call worked, stop doing the search now, since we
@@ -5653,12 +5666,12 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
         if (oldDscp == newDscp) {
             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
-                                  filter, oldDscp, oldLastNamep,
+                                  filter, oldDscp, rock.normalizedOldName,
                                   newLastNamep, TRUE);
         } else {
             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
-                                  filter, oldDscp, oldLastNamep,
+                                  filter, oldDscp, rock.normalizedOldName,
                                   NULL, TRUE);
             if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
                 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
@@ -5871,22 +5884,20 @@ int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper
     long code = 0;
     smb_rmdirRock_t *rockp;
     int match;
-    char shortName[13];
-    char *matchName;
+    char matchName[MAX_PATH];
         
     rockp = (smb_rmdirRock_t *) vrockp;
 
-    matchName = dep->name;
+    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
-        match = (cm_stricmp(matchName, rockp->maskp) == 0);
+        match = (cm_stricmp_utf8(matchName, rockp->maskp) == 0);
     else
         match = (strcmp(matchName, rockp->maskp) == 0);
     if (!match &&
          (rockp->flags & SMB_MASKFLAG_TILDE) &&
          !cm_Is8Dot3(dep->name)) {
-        cm_Gen8Dot3Name(dep, shortName, NULL);
-        matchName = shortName;
-        match = (cm_stricmp(matchName, rockp->maskp) == 0);
+        cm_Gen8Dot3Name(dep, matchName, NULL);
+        match = (cm_stricmp_utf8(matchName, rockp->maskp) == 0);
     }       
 
     if (match) {
@@ -5980,15 +5991,20 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
         cm_dirEntryList_t * entry;
 
         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
+            char normalizedName[MAX_PATH];
+
+            cm_NormalizeUtf8String(entry->name, -1, normalizedName,
+                                   sizeof(normalizedName)/sizeof(char));
+
             osi_Log1(smb_logp, "Removing directory %s",
                      osi_LogSaveString(smb_logp, entry->name));
 
-            code = cm_RemoveDir(dscp, entry->name, userp, &req);
+            code = cm_RemoveDir(dscp, entry->name, normalizedName, userp, &req);
 
             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
                 smb_NotifyChange(FILE_ACTION_REMOVED,
                                  FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
-                                 dscp, entry->name, NULL, TRUE);
+                                 dscp, normalizedName, NULL, TRUE);
         }
     }
 
@@ -6062,47 +6078,59 @@ struct smb_FullNameRock {
     char *name;
     cm_scache_t *vnode;
     char *fullName;
+    char *originalName;
 };
 
 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
                      osi_hyper_t *offp)
 {
-    char shortName[13];
+    char matchName[MAX_PATH];
     struct smb_FullNameRock *vrockp;
 
     vrockp = (struct smb_FullNameRock *)rockp;
 
+    cm_NormalizeUtf8String(dep->name, -1, matchName, sizeof(matchName)/sizeof(char));
+
     if (!cm_Is8Dot3(dep->name)) {
+        char shortName[13];
+
         cm_Gen8Dot3Name(dep, shortName, NULL);
 
-        if (cm_stricmp(shortName, vrockp->name) == 0) {
-            vrockp->fullName = strdup(dep->name);
+        if (cm_stricmp_utf8N(shortName, vrockp->name) == 0) {
+            vrockp->fullName = strdup(matchName);
+            vrockp->originalName = strdup(dep->name);
             return CM_ERROR_STOPNOW;
         }
     }
-    if (cm_stricmp(dep->name, vrockp->name) == 0 &&
+    if (cm_stricmp_utf8(matchName, vrockp->name) == 0 &&
         ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
         ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
-        vrockp->fullName = strdup(dep->name);
+        vrockp->fullName = strdup(matchName);
+        vrockp->originalName = strdup(dep->name);
         return CM_ERROR_STOPNOW;
     }
     return 0;
 }
 
 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
-                  char **newPathp, cm_user_t *userp, cm_req_t *reqp)
+                  char **newPathp, char ** originalPathp,
+                  cm_user_t *userp, cm_req_t *reqp)
 {
     struct smb_FullNameRock rock;
     long code = 0;
 
+    memset(&rock, 0, sizeof(rock));
     rock.name = pathp;
     rock.vnode = scp;
 
     code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL); 
-    if (code == CM_ERROR_STOPNOW)
+    if (code == CM_ERROR_STOPNOW) {
         *newPathp = rock.fullName;
-    else
+        *originalPathp = rock.originalName;
+    } else {
         *newPathp = strdup(pathp);
+        *originalPathp = strdup(pathp);
+    }
 }
 
 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
@@ -6219,7 +6247,8 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     }
 
     if (fidp->flags & SMB_FID_DELONCLOSE) {
-        char *fullPathp;
+        char *fullPathp = NULL;
+        char *originalNamep = NULL;
 
        lock_ReleaseMutex(&fidp->mx);
 
@@ -6228,9 +6257,9 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
             cm_HoldSCache(scp);
             delscp = scp;
         }
-        smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
+        smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
         if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
-            code = cm_RemoveDir(dscp, fullPathp, userp, &req);
+            code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
            if (code == 0) {
                deleted = 1;
                if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
@@ -6239,7 +6268,7 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                                      dscp, fullPathp, NULL, TRUE);
            }
         } else {
-            code = cm_Unlink(dscp, fullPathp, userp, &req);
+            code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
            if (code == 0) {                            
                deleted = 1;
                if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
@@ -6248,7 +6277,12 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                                      dscp, fullPathp, NULL, TRUE);
            }
         }
+
+        if (fullPathp)
         free(fullPathp);
+        if (originalNamep)
+            free(originalNamep);
+
        lock_ObtainMutex(&fidp->mx);
        fidp->flags &= ~SMB_FID_DELONCLOSE;
     }
index 3c588a1..a1ed7f0 100644 (file)
@@ -29,6 +29,7 @@
 #include <WINNT\afsreg.h>
 
 #include "smb.h"
+#include <strsafe.h>
 
 extern osi_hyper_t hzero;
 
@@ -77,7 +78,7 @@ afs_uint32 smb_IsExecutableFileName(const char *name)
 
     for ( i=0; smb_ExecutableExtensions[i]; i++) {
         j = len - (int)strlen(smb_ExecutableExtensions[i]);
-        if (_stricmp(smb_ExecutableExtensions[i], &name[j]) == 0)
+        if (cm_stricmp_utf8N(smb_ExecutableExtensions[i], &name[j]) == 0)
             return 1;
     }
 
@@ -1532,9 +1533,9 @@ typedef struct smb_rap_share_list {
 
 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
     smb_rap_share_list_t * sp;
-    char * name;
+    char name[MAX_PATH];
 
-    name = dep->name;
+    cm_NormalizeUtf8String(dep->name, -1, name, sizeof(name)/sizeof(char));
 
     if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
         return 0; /* skip over '.' and '..' */
@@ -1690,7 +1691,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
             len = sizeof(thisShare);
             rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
             if (rv == ERROR_SUCCESS &&
-                strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
+                strlen(thisShare) && (!allSubmount || cm_stricmp_utf8N(thisShare,"all"))) {
                 strncpy(shares[cshare].shi1_netname, thisShare,
                         sizeof(shares->shi1_netname)-1);
                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
@@ -1710,7 +1711,7 @@ long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_
     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
         /* in case there are collisions with submounts, submounts have higher priority */              
         for (j=0; j < nonrootShares; j++)
-            if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
+            if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
                 break;
                
         if (j < nonrootShares) {
@@ -1796,7 +1797,7 @@ long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_pack
     else
         return CM_ERROR_INVAL;
 
-    if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
+    if(!cm_stricmp_utf8N(shareName,"all") || !strcmp(shareName,"*.")) {
         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
                           KEY_QUERY_VALUE, &hkParam);
         if (rv == ERROR_SUCCESS) {
@@ -2265,10 +2266,10 @@ long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
     if (lastNamep && 
-         (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
-           stricmp(lastNamep, "\\srvsvc") == 0 ||
-           stricmp(lastNamep, "\\wkssvc") == 0 ||
-           stricmp(lastNamep, "\\ipc$") == 0)) {
+         (cm_stricmp_utf8N(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
+           cm_stricmp_utf8N(lastNamep, "\\srvsvc") == 0 ||
+           cm_stricmp_utf8N(lastNamep, "\\wkssvc") == 0 ||
+           cm_stricmp_utf8N(lastNamep, "\\ipc$") == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
@@ -2743,19 +2744,25 @@ int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
                          osi_hyper_t *offp)
 {       
     struct smb_ShortNameRock *rockp;
+    char normName[MAX_PATH];
     char *shortNameEnd;
 
     rockp = vrockp;
+
+    cm_NormalizeUtf8String(dep->name, -1, normName, sizeof(normName)/sizeof(char));
+
     /* compare both names and vnodes, though probably just comparing vnodes
      * would be safe enough.
      */
-    if (cm_stricmp(dep->name, rockp->maskp) != 0)
+    if (cm_stricmp_utf8(normName, rockp->maskp) != 0)
         return 0;
     if (ntohl(dep->fid.vnode) != rockp->vnode)
         return 0;
+
     /* This is the entry */
     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
     rockp->shortNameLen = shortNameEnd - rockp->shortName;
+
     return CM_ERROR_STOPNOW;
 }       
 
@@ -2919,7 +2926,7 @@ long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 #ifndef SPECIAL_FOLDERS
         /* Make sure that lastComp is not NULL */
         if (lastComp) {
-            if (stricmp(lastComp, "\\desktop.ini") == 0) {
+            if (cm_stricmp_utf8N(lastComp, "\\desktop.ini") == 0) {
                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
                                  CM_FLAG_CASEFOLD
                                  | CM_FLAG_DIRSEARCH
@@ -3195,7 +3202,7 @@ long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet
 #ifndef SPECIAL_FOLDERS
         /* Make sure that lastComp is not NULL */
         if (lastComp) {
-            if (stricmp(lastComp, "\\desktop.ini") == 0) {
+            if (cm_stricmp_utf8N(lastComp, "\\desktop.ini") == 0) {
                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
                                  CM_FLAG_CASEFOLD
                                  | CM_FLAG_DIRSEARCH
@@ -4206,51 +4213,86 @@ VOID initUpperCaseTable(VOID)
     mapCaseTable[(int)'>'] = toupper('?');    
 }
 
-// Compare 'pattern' (containing metacharacters '*' and '?') with the file
-// name 'name'.
-// Note : this procedure works recursively calling itself.
-// Parameters
-// PSZ pattern    : string containing metacharacters.
-// PSZ name       : file name to be compared with 'pattern'.
-// Return value
-// BOOL : TRUE/FALSE (match/mistmatch)
+/*! \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)
+*/
 BOOL 
-szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
+szWildCardMatchFileName(char * pattern, char * name, int casefold) 
 {
-    PSZ pename;         // points to the last 'name' character
-    PSZ p;
-    pename = name + strlen(name) - 1;
+    char upattern[MAX_PATH];
+    char uname[MAX_PATH];
+
+    char * pename;         // points to the last 'name' character
+    char * p;
+    char * pattern_next;
+
+    if (casefold) {
+        StringCbCopyA(upattern, sizeof(upattern), pattern);
+        strupr_utf8(upattern, sizeof(upattern));
+        pattern = upattern;
+
+        StringCbCopyA(uname, sizeof(uname), name);
+        strupr_utf8(uname, sizeof(uname));
+        name = uname;
+
+        /* The following translations all work on single byte
+           characters */
+        for (p=pattern; *p; p++) {
+            if (*p == '"') *p = '.'; continue;
+            if (*p == '<') *p = '*'; continue;
+            if (*p == '>') *p = '?'; continue;
+        }
+
+        for (p=name; *p; p++) {
+            if (*p == '"') *p = '.'; continue;
+            if (*p == '<') *p = '*'; continue;
+            if (*p == '>') *p = '?'; continue;
+        }
+    }
+
+    pename = char_prev_utf8(name + strlen(name));
+
     while (*name) {
         switch (*pattern) {
         case '?':
-           ++pattern;
+           pattern = char_next_utf8(pattern);
             if (*name == '.')
                continue;
-            ++name;
+            name = char_next_utf8(name);
             break;
+
          case '*':
-            ++pattern;
+            pattern = char_next_utf8(pattern);
             if (*pattern == '\0')
                 return TRUE;
-            for (p = pename; p >= name; --p) {
-                if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
-                     !casefold && (*p == *pattern)) &&
-                     szWildCardMatchFileName(pattern + 1, p + 1, casefold))
+
+            pattern_next = char_next_utf8(pattern);
+
+            for (p = pename; p >= name; p = char_prev_utf8(p)) {
+                if (*p == *pattern &&
+                    szWildCardMatchFileName(pattern_next,
+                                            char_next_utf8(p), FALSE))
                     return TRUE;
             } /* endfor */
             return FALSE;
+
         default:
-            if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
-                (!casefold && *name != *pattern))
+            if (*name != *pattern)
                 return FALSE;
-            ++pattern, ++name;
+            pattern = char_next_utf8(pattern);
+            name = char_next_utf8(name);
             break;
         } /* endswitch */
     } /* endwhile */ 
 
     /* if all we have left are wildcards, then we match */
-    for (;*pattern; pattern++) {
+    for (;*pattern; pattern = char_next_utf8(pattern)) {
        if (*pattern != '*' && *pattern != '?')
            return FALSE;
     }
@@ -5102,6 +5144,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
     returnedNames = 0;
     bytesInBuffer = 0;
     while (1) {
+        char normName[MAX_PATH]; /* Normalized name */
+
         op = origOp;
         if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
             /* skip over resume key */
@@ -5274,6 +5318,8 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         if (dep->fid.vnode == 0) 
             goto nextEntry;             /* This entry is not in use */
 
+        cm_NormalizeUtf8String(dep->name, -1, normName, sizeof(normName)/sizeof(char));
+
         /* Need 8.3 name? */
         NeedShortName = 0;
         if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO && 
@@ -5284,18 +5330,18 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
                   dep->fid.vnode, dep->fid.unique, 
-                  osi_LogSaveString(smb_logp, dep->name),
+                  osi_LogSaveString(smb_logp, normName),
                   NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
 
         /* When matching, we are using doing a case fold if we have a wildcard mask.
          * If we get a non-wildcard match, it's a lookup for a specific file. 
          */
-        if (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
+        if (smb_V3MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
              (NeedShortName && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD))) 
         {
             /* Eliminate entries that don't match requested attributes */
             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
-                 smb_IsDotFile(dep->name)) {
+                 smb_IsDotFile(normName)) {
                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
                 goto nextEntry; /* no hidden files */
             }
@@ -5318,7 +5364,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
 
             /* finally check if this name will fit */
             onbytes = 0;
-            smb_UnparseString(opx, NULL, dep->name, &onbytes, SMB_STRF_ANSIPATH);
+            smb_UnparseString(opx, NULL, normName, &onbytes, SMB_STRF_ANSIPATH);
             orbytes = ohbytes + onbytes;
 
             /* now, we round up the record to a 4 byte alignment,
@@ -5346,7 +5392,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
             memset(origOp, 0, orbytes);
 
             onbytes = 0;
-            smb_UnparseString(opx, origOp + ohbytes, dep->name, &onbytes, SMB_STRF_ANSIPATH);
+            smb_UnparseString(opx, origOp + ohbytes, normName, &onbytes, SMB_STRF_ANSIPATH);
 
             switch (infoLevel) {
             case SMB_INFO_STANDARD:
@@ -5433,7 +5479,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
                 curPatchp->dptr = attrp;
 
-                if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
+                if (smb_hideDotFiles && smb_IsDotFile(normName)) {
                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
                 } else {
                     curPatchp->flags = 0;
@@ -5461,7 +5507,7 @@ long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t
         }      /* if we're including this name */
         else if (!starPattern &&
                   !foundInexact &&
-                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
+                  smb_V3MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
             /* We were looking for exact matches, but here's an inexact one*/
             foundInexact = 1;
         }
@@ -5640,10 +5686,10 @@ long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
 
     if (lastNamep && 
-         (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
-           stricmp(lastNamep, "\\srvsvc") == 0 ||
-           stricmp(lastNamep, "\\wkssvc") == 0 ||
-           stricmp(lastNamep, "ipc$") == 0)) {
+         (cm_stricmp_utf8N(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
+           cm_stricmp_utf8N(lastNamep, "\\srvsvc") == 0 ||
+           cm_stricmp_utf8N(lastNamep, "\\wkssvc") == 0 ||
+           cm_stricmp_utf8N(lastNamep, "ipc$") == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
@@ -6791,10 +6837,10 @@ long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
 
        if (lastNamep && 
-             (stricmp(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
-               stricmp(lastNamep, "\\srvsvc") == 0 ||
-               stricmp(lastNamep, "\\wkssvc") == 0 ||
-               stricmp(lastNamep, "ipc$") == 0)) {
+             (cm_stricmp_utf8N(lastNamep, SMB_IOCTL_FILENAME) == 0 ||
+               cm_stricmp_utf8N(lastNamep, "\\srvsvc") == 0 ||
+               cm_stricmp_utf8N(lastNamep, "\\wkssvc") == 0 ||
+               cm_stricmp_utf8N(lastNamep, "ipc$") == 0)) {
         /* special case magic file name for receiving IOCTL requests
          * (since IOCTL calls themselves aren't getting through).
          */
index d9de596..aff603c 100644 (file)
@@ -44,6 +44,7 @@ static int rxInitDone = 0;
 
 void Die();
 
+#if 0
 foldcmp (a, b)
     register char *a;
     register char *b; {
@@ -57,6 +58,7 @@ foldcmp (a, b)
         if (t == 0) return 0;
     }
 }
+#endif
 
 /* this function returns TRUE (1) if the file is in AFS, otherwise false (0) */
 static int InAFS(register char *apath)
index 8090fdf..833a509 100644 (file)
@@ -81,7 +81,8 @@ EXELIBS =\
        $(EXELIBDIR)\afs\afsutil.lib \
        $(EXELIBDIR)\afs\afseventlog.lib \
        $(EXELIBDIR)\afs\afsreg.lib \
-       $(EXELIBDIR)\cm_dns.obj
+       $(EXELIBDIR)\cm_dns.obj \
+        $(EXELIBDIR)\cm_nls.obj
 
 
 $(SETKEY_EXEFILE): $(SETKEY_EXEOBJS) $(EXELIBS)
index 9ac0c89..0ed4e43 100644 (file)
@@ -67,7 +67,8 @@ BOSSERVER_EXELIBS =\
        $(DESTDIR)\lib\afs\afsreg.lib \
        $(DESTDIR)\lib\afs\afseventlog.lib \
        $(DESTDIR)\lib\afs\afsprocmgmt.lib \
-       $(DESTDIR)\lib\cm_dns.obj
+       $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
 
 $(BOSSERVER_EXEFILE): $(BOSSERVER_EXEOBJS) $(BOSSERVER_EXELIBS)
        $(EXECONLINK) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib
@@ -103,7 +104,8 @@ BOS_EXELIBS =\
        $(DESTDIR)\lib\afs\afsreg.lib \
        $(DESTDIR)\lib\afs\afsprocmgmt.lib \
        $(DESTDIR)\lib\afs\afspioctl.lib \
-       $(DESTDIR)\lib\cm_dns.obj
+       $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
 
 
 $(RS_BOS_EXEFILE): $(BOS_EXEOBJS) $(BOS_EXELIBS)
index 944db3d..76708fb 100644 (file)
@@ -88,7 +88,8 @@ EXELIBS =\
        $(DESTDIR)\lib\afs\afsprocmgmt.lib \
        $(DESTDIR)\lib\afs\afspioctl.lib \
        $(DESTDIR)\lib\afs\afsreg.lib \
-     $(DESTDIR)\lib\cm_dns.obj
+        $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
        
 
 $(EXEFILE): $(EXEOBJS) $(EXERES) $(EXELIBS)
index 68d4259..d7d9f4a 100644 (file)
@@ -77,7 +77,8 @@ EXELIBS =\
        $(DESTDIR)\lib\afs\afseventlog.lib \
        $(DESTDIR)\lib\afs\afsreg.lib \
        $(DESTDIR)\lib\afs\afsprocmgmt.lib \
-       $(DESTDIR)\lib\cm_dns.obj
+       $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
 
 
 $(EXEFILE): $(EXEOBJS)  $(EXELIBS)
index 31e2dfe..478ed86 100644 (file)
@@ -1,3 +1,4 @@
+
 # Copyright 2000, International Business Machines Corporation and others.
 # All Rights Reserved.
 # 
@@ -52,7 +53,8 @@ EXELIBS =\
        $(DESTDIR)\lib\afs\afspioctl.lib \
        $(DESTDIR)\lib\afs\afseventlog.lib \
        $(DESTDIR)\lib\afs\afsreg.lib \
-       $(DESTDIR)\lib\cm_dns.obj
+       $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
 
 $(EXERES): butc.rc AFS_component_version_number.h
 
index f826b3c..e915961 100644 (file)
@@ -98,7 +98,8 @@ AFSLIBS =  \
        $(DESTDIR)\lib\afsubik.lib \
        $(DESTDIR)\lib\afs\afseventlog.lib \
        $(DESTDIR)\lib\afsrxkad.lib \
-       $(DESTDIR)\lib\cm_dns.obj
+       $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
        
 TOKENLIB = $(DESTDIR)\lib\afs\afspioctl.lib
 
index b216940..f92b1a8 100644 (file)
@@ -96,6 +96,7 @@ DLLOBJS =\
        $(WINNTAFSDOBJS) \
        $(AUDITBJS) \
        $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj \
        $(OUT)\afsauthent.res
 
 $(RXOBJS): $(RX)\$$(@B).c
index f94543d..a3f5471 100644 (file)
@@ -69,7 +69,8 @@ PTSERVER_EXELIBS =\
        $(DESTDIR)\lib\afs\afsaudit.lib \
        $(DESTDIR)\lib\afs\afseventlog.lib \
        $(DESTDIR)\lib\afs\afsreg.lib \
-       $(DESTDIR)\lib\cm_dns.obj
+       $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
 
 !IF (("$(SYS_NAME)"!="i386_win95" ) && ("$(SYS_NAME)"!="I386_WIN95" ))
 PTSERVER_EXELIBS =$(PTSERVER_EXELIBS) $(DESTDIR)\lib\afs\afsprocmgmt.lib
@@ -111,7 +112,8 @@ PTS_EXELIBS =\
        $(DESTDIR)\lib\afs\afsreg.lib \
        $(DESTDIR)\lib\afs\afseventlog.lib \
        $(DESTDIR)\lib\afs\afspioctl.lib \
-       $(DESTDIR)\lib\cm_dns.obj
+       $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
 
 $(PTS): $(PTS_EXEOBJS) $(PTS_EXELIBS) 
        $(EXECONLINK) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib
index bbac7c1..d915bcd 100644 (file)
@@ -96,7 +96,8 @@ BUTCLIBS=$(DESTDIR)\lib\afs\afsbudb.lib  \
        $(DESTDIR)\lib\afspthread.lib \
 !ENDIF
             $(DESTDIR)\lib\afsdes.lib \
-            $(DESTDIR)\lib\cm_dns.obj
+            $(DESTDIR)\lib\cm_dns.obj \
+             $(DESTDIR)\lib\cm_nls.obj
 
 
 #      $(DESTDIR)\lib\afsauthent.lib \
index 7de1cef..1844587 100644 (file)
@@ -85,7 +85,8 @@ VLSERVER_EXECLIBS = \
        $(DESTDIR)\lib\afs\afseventlog.lib \
        $(DESTDIR)\lib\afs\afsreg.lib \
        $(DESTDIR)\lib\afs\afsprocmgmt.lib \
-       $(DESTDIR)\lib\cm_dns.obj
+       $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
 
 $(VLSERVER): $(VLSERVER_EXEOBJS) $(LIBFILE) $(VLSERVER_EXECLIBS)
        $(EXECONLINK) dnsapi.lib mpr.lib iphlpapi.lib shell32.lib
index 632074c..f797aaf 100644 (file)
@@ -70,7 +70,8 @@ EXEC_LIBS = \
        $(DESTDIR)\lib\afs\afsacl.lib \
        $(DESTDIR)\lib\afs\afsreg.lib \
        $(DESTDIR)\lib\afs\afseventlog.lib \
-     $(DESTDIR)\lib\cm_dns.obj
+        $(DESTDIR)\lib\cm_dns.obj \
+        $(DESTDIR)\lib\cm_nls.obj
 
 
 ############################################################################