$(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 \
afsrpc.h $(OUT)\afsrpc_c.obj
CONFOBJS=$(OUT)\cm_config.obj \
- $(OUT)\cm_dns.obj
+ $(OUT)\cm_dns.obj \
+ $(OUT)\cm_nls.obj
$(CONFOBJS):
$(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 \
$(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
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 \
############################################################################
# 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
$(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 \
#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"
{
// 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;
(pName - pHostNames < dwSize) && *pName ;
pName += strlen(pName) + 1)
{
- if ( !stricmp(pName, cm_NetbiosName) ) {
+ if ( !cm_stricmp_utf8(pName, cm_NetbiosName) ) {
bNameFound = TRUE;
break;
}
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;
}
}
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);
{
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;
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)
{
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:
cm_SetFid(&data.fid, cfid->cell, cfid->volume, cfid->vnode, cfid->unique);
data.longname = NULL;
+ data.origname = NULL;
QueryPerformanceCounter(&start);
bplus_create_entry++;
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)
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;
}
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);
}
typedef struct dirdata {
cm_fid_t fid;
char * longname;
+ char * origname;
} dataT;
typedef struct entry {
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);
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;
}
* 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;
}
*/
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;
}
}
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;
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);
return rc;
}
+
/* Look up a file name in directory.
On entry:
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;
#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)
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 */
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;
}
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;
}
memcpy(shortname, line, cp-line);
shortname[cp-line]=0;
- if (!stricmp(shortname, filename)) {
+ if (!cm_stricmp_utf8(shortname, filename)) {
found = 1;
break;
}
memcpy(shortname, line, cp-line);
shortname[cp-line]=0;
- if (!stricmp(shortname, filename)) {
+ if (!cm_stricmp_utf8(shortname, filename)) {
found = 1;
break;
}
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;
}
#include <winioctl.h>
#include <rx\rx.h>
+#include "cm_btree.h"
+
#ifdef _DEBUG
#include <crtdbg.h>
#endif
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)))
cm_scache_t *dscp;
cm_scache_t *scp;
char *cp;
+ char *originalName = NULL;
cm_req_t req;
+ cm_dirOp_t dirop;
cm_InitReq(&req);
/* 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);
cm_scache_t *dscp;
cm_scache_t *scp;
char *cp;
+ char * originalName = NULL;
cm_req_t req;
+ cm_dirOp_t dirop;
cm_InitReq(&req);
/* 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,
| 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);
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);
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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
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;
-}
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__ */
{
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)
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;
}
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);
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);
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);
}
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
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;
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);
}
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);
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;
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
}
}
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;
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);
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);
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);
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)
if (diropCode == 0) {
diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
#ifdef USE_BPLUS
- cm_BPlusDirDeleteEntry(&oldDirOp, oldNamep);
+ cm_BPlusDirDeleteEntry(&oldDirOp, normalizedOldNamep);
#endif
}
}
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,
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);
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];
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 */
}
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;
}
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));
char *cursor;
for (cursor = str1; *cursor; cursor++)
- if (stricmp(cursor, str2) == 0)
+ if (cm_stricmp_utf8(cursor, str2) == 0)
return cursor;
return NULL;
{
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)
RegCloseKey (parmKey);
}
- if (allSubmount && _stricmp(shareName, "all") == 0) {
+ if (allSubmount && cm_stricmp_utf8N(shareName, "all") == 0) {
*pathNamep = NULL;
return 1;
}
/* 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;
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;
}
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);
smb_unlinkRock_t *rockp;
int caseFold;
int match;
- char shortName[13];
- char *matchName;
+ char matchName[MAX_PATH];
rockp = vrockp;
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);
}
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);
}
}
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;
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;
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 */
/* 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);
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
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,
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) {
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);
}
}
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,
}
if (fidp->flags & SMB_FID_DELONCLOSE) {
- char *fullPathp;
+ char *fullPathp = NULL;
+ char *originalNamep = NULL;
lock_ReleaseMutex(&fidp->mx);
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)
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)
dscp, fullPathp, NULL, TRUE);
}
}
+
+ if (fullPathp)
free(fullPathp);
+ if (originalNamep)
+ free(originalNamep);
+
lock_ObtainMutex(&fidp->mx);
fidp->flags &= ~SMB_FID_DELONCLOSE;
}
#include <WINNT\afsreg.h>
#include "smb.h"
+#include <strsafe.h>
extern osi_hyper_t hzero;
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;
}
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 '..' */
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 */
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) {
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) {
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).
*/
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;
}
#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
#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
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;
}
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 */
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 &&
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 */
}
/* 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,
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:
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;
} /* 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;
}
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).
*/
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).
*/
void Die();
+#if 0
foldcmp (a, b)
register char *a;
register char *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)
$(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)
$(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
$(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)
$(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)
$(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)
+
# Copyright 2000, International Business Machines Corporation and others.
# All Rights Reserved.
#
$(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
$(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
$(WINNTAFSDOBJS) \
$(AUDITBJS) \
$(DESTDIR)\lib\cm_dns.obj \
+ $(DESTDIR)\lib\cm_nls.obj \
$(OUT)\afsauthent.res
$(RXOBJS): $(RX)\$$(@B).c
$(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
$(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
$(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 \
$(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
$(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
############################################################################