From 4f1a7e246bf2f9eae91453830c562cf4764c8a03 Mon Sep 17 00:00:00 2001 From: ChatGPT Date: Mon, 15 Jun 2026 17:19:20 +0000 Subject: [PATCH] 0558 nwnss: import COMN Mac short name runtime --- src/nwnss/CMakeLists.txt | 3 + src/nwnss/comn/common/comnMacShortName.c | 538 +++++++++++++++++++ src/nwnss/comn/common/zAPI.c | 33 ++ src/nwnss/library/stdlib/strtol.c | 17 + tests/nwnss/namespace/test_nwnss_namespace.c | 29 + 5 files changed, 620 insertions(+) create mode 100755 src/nwnss/comn/common/comnMacShortName.c create mode 100644 src/nwnss/comn/common/zAPI.c create mode 100644 src/nwnss/library/stdlib/strtol.c diff --git a/src/nwnss/CMakeLists.txt b/src/nwnss/CMakeLists.txt index 6304b0d..3d5f048 100644 --- a/src/nwnss/CMakeLists.txt +++ b/src/nwnss/CMakeLists.txt @@ -30,6 +30,7 @@ add_library(nwnss SHARED library/stdio/vprintf.c library/stdio/vsprintf.c library/stdlib/malloc.c + library/stdlib/strtol.c library/stdlib/zalloc.c library/stdlib/zrealloc.c library/unicode/ByteToUnicode.c @@ -96,7 +97,9 @@ add_library(nwnss SHARED library/xString.c nsslnxlib/nwlocale.c comn/common/beastHash.c + comn/common/comnMacShortName.c comn/common/comnVariableData.c + comn/common/zAPI.c comn/namespace/dosNSWild.c nss/cache/asyncio.c nss/cache/bond.c diff --git a/src/nwnss/comn/common/comnMacShortName.c b/src/nwnss/comn/common/comnMacShortName.c new file mode 100755 index 0000000..b9c7c72 --- /dev/null +++ b/src/nwnss/comn/common/comnMacShortName.c @@ -0,0 +1,538 @@ +/**************************************************************************** + | + | (C) Copyright 2004 Novell, Inc. + | All Rights Reserved. + | + | This program is free software; you can redistribute it and/or + | modify it under the terms of version 2 of the GNU General Public + | License as published by the Free Software Foundation. + | + | This program is distributed in the hope that it will be useful, + | but WITHOUT ANY WARRANTY; without even the implied warranty of + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + | GNU General Public License for more details. + | + | You should have received a copy of the GNU General Public License + | along with this program; if not, contact Novell, Inc. + | + | To contact Novell about this file by physical or electronic mail, + | you may find current contact information at www.novell.com + | + |*************************************************************************** + | + | NetWare Advance File Services (PSS) module + | + |--------------------------------------------------------------------------- + | + | $Author: vandana $ + | $Modtime: $ + | + | $Workfile: $ + | $Revision: 1177 $ + | + |--------------------------------------------------------------------------- + | This module is used to: + | Provide compatibility with AFP 2.2 by providing a short (zid-mangled) + | file name for the AFP 3.1 255 unicode char file names + +-------------------------------------------------------------------------*/ +#include + +#include // sprintf & COMN_RESOURCE +#include // isxdigit +#include // memcpy, strcpy, strlen, memset +#include // malloc/free +#include // error defines +#include "zParams.h" // zInfo at least + +#include "nameSpace.h" // necessary for macNSpace.h +#include "macNSpace.h" // MACNS_LEGACY_NAME_LIMIT + + +/**************************************************************************** +* Support routines to mangle 255 unicode char names to 31 byte-based +* names. This supports AFP 3.1 255 char names and provides back-wards +* compatibility for AFP 2.2 (31 char) names +*******************************************************************************/ + +/************************************************************************* +* Generate 31-char byte-based mangled name from 255 unicode name +**************************************************************************/ + +BOOL COMN_VerifyMangledMacName (unicode_t * mangledName, unicode_t * fileName) +{ + static unicode_t testStr[] = L"???#"; + unicode_t * baseEnd; + NINT baseLen; + + baseEnd = unirchr (mangledName, '#'); + if (!baseEnd) // no # in mangled name, return false + return FALSE; + + baseLen = baseEnd - mangledName; + + if (uninicmp (mangledName, fileName, baseLen ) == 0) + return TRUE; + + // Check to see if first char is unmappable + if (uninicmp (mangledName, testStr, 4) == 0) // first char must be unmappable + { + if (!IS_UNICODE_MAPPABLE_TO_MAC_ASCII (*fileName)) // first char is unmappable + { + return TRUE; + } + } + + // fileName does not match mangledName + return FALSE; + +} + + + +#define DOT_CHAR 0x002E + + +typedef struct parseInfo +{ + BOOL mangleBase; + BOOL mangleExt; + BOOL dropExt; + unicode_t srcName[256]; + unicode_t workingBase[32]; + unicode_t workingExt [32]; + unicode_t mangledName [32]; + unicode_t mangleStr [32]; + BYTE asciiName [32]; + int baseLen; + int extLen; +} parseInfo; + + +void dropExt (struct parseInfo * info) +{ + info->dropExt = TRUE; + info->mangleExt = FALSE; + info->workingExt[0] = 0; + info->extLen = 0; +} + +// file name (base + extension) has more than 31 characters or +// must mangle (has unmappable chars) + +unicode_t * generateMangledMacName (struct parseInfo * info, unicode_t * mangledName) +{ + + unicode_t dotChar[2]; + dotChar[0] = 0x002E; + dotChar[1] = 0; + + memset (mangledName, 0, sizeof (mangledName) ); + memset (info->mangledName, 0, sizeof (info->mangledName) ); + + if (info->mangleBase && info->mangleExt) + { + info->workingExt[0] = 0; + info->mangleExt = FALSE; + info->dropExt = TRUE; + } + + // is there room for the base name + mangled extension?? + if ( (info->dropExt == FALSE) && (info->extLen != 0) ) + { + { + if (info->mangleBase == FALSE) + { + if (unilen (info->workingBase) + unilen (info->mangleStr) + 1 <= 31) + info->mangleExt = TRUE; + } + } + } + + // Does the base name need to be shortened? + if ( info->baseLen > (MACNS_LEGACY_NAME_LIMIT - (unilen (info->mangleStr) + 1) ) ) + info->mangleBase = TRUE; + + // Do we need to shorten the extension + if (info->extLen > (unilen (info->mangleStr) + 1) ) + info->mangleExt = TRUE; + + if (info->mangleBase && info->mangleExt) + { + dropExt (info); + } + + if (info->mangleExt) + { + int minLen; + int additionalExtChars; + + minLen = info->baseLen + unilen (info->mangleStr) + 1; // for the dot + + additionalExtChars = MACNS_LEGACY_NAME_LIMIT - minLen; + + if (additionalExtChars > info->extLen) + additionalExtChars = info->extLen; + +// build ext from truncated ext + mangleString + LB_unicpy (mangledName, info->workingBase); + LB_unicat (mangledName, dotChar); + LB_unincat (mangledName, info->workingExt, additionalExtChars); + LB_unicat (mangledName, info->mangleStr); + LB_unicpy (info->mangledName, mangledName); + return (mangledName); + } + + else // mangle base name, keep full extension if not dropping + { + int minLen; + int newBaseLen; + + minLen = MACNS_LEGACY_NAME_LIMIT - (info->extLen + unilen (info->mangleStr)); + if (minLen > LB_unilen (info->workingBase) ) + newBaseLen = LB_unilen (info->workingBase); + else + newBaseLen = minLen; + + mangledName[0] = 0; + LB_unincat (mangledName, info->workingBase, newBaseLen); + LB_unicat (mangledName, info->mangleStr); + if (info->dropExt == FALSE) + { + LB_unicat (mangledName, dotChar); + LB_unicat (mangledName, info->workingExt); + } + LB_unicpy (info->mangledName, mangledName); + return (mangledName); + } +} + + + +// generate MangleString from zid +unicode_t * getMangleString (unicode_t * mangleStr, LONG zID) +{ + char buffer[256]; + unicode_t * uPtr = mangleStr; + char * chPtr; + + memset (buffer, 0, 256); + buffer[0] = '#'; + + sprintf (&buffer[1], "%x", zID); + uPtr = mangleStr; + *uPtr = 0; + + chPtr = &buffer[0]; + + /* convert ASCII hex digit string to unicode */ + while (*chPtr) + *uPtr++ = *chPtr++; + + *uPtr = 0; + + if (*mangleStr != 0) + return (mangleStr); + else + return (NULL); +} + +static STATUS parseFileName (parseInfo * info, unicode_t * srcFileName) +{ + unicode_t * lastDotPtr, *srcPtr; + char byteFileName [zMAX_COMPONENT_NAME]; +// STATUS err; + + memset (info, 0, sizeof (*info)); + memset (byteFileName, 0, sizeof (byteFileName) ); + + LB_unicpy (info->srcName, srcFileName); + +// find base & extension + +// extension - look at first dot from end of file name + + lastDotPtr = LB_unirchr (srcFileName, DOT_CHAR /* period or dot */); + + if (lastDotPtr) + info->extLen = LB_unilen (lastDotPtr); + + if (lastDotPtr == NULL) // no extension + info->dropExt = TRUE; + else + *lastDotPtr = 0; // terminate base file name for now + +// find base file name + +// copy base to workingBaseName (first 31 chars only) + memset (info->workingBase, 0, sizeof (info->workingBase) ); + // zero out, because unincpy does not always null terminate + // src is > 31 chars, no null terminator is added to string + LB_unincpy (info->workingBase, srcFileName, MACNS_LEGACY_NAME_LIMIT); + + info->baseLen = LB_unilen (srcFileName); + + if (lastDotPtr) // restore dot to filename, overwrite null terminator we added + *lastDotPtr = DOT_CHAR; + +// if (base len > 31) +// set mangleBase = true + + if (info->baseLen > MACNS_LEGACY_NAME_LIMIT) + info->mangleBase = TRUE; + + if (info->extLen > MACNS_LEGACY_NAME_LIMIT) + info->mangleExt = TRUE; + + if (info->mangleBase && info->mangleExt) + { + dropExt (info); + } + + if (info->dropExt == FALSE) // there is an extension + { +// if (extLen > 31) +// copy first 31 chars to newExt +// set mangleExt = true +// else +// copy extension to workingExt + + // unincpy does not always null terminate dest string + memset (info->workingExt, 0, sizeof (info->workingExt) ); + LB_unincpy (info->workingExt, lastDotPtr + 1, MACNS_LEGACY_NAME_LIMIT); +// if there is an unmappable char in extension +// truncate workingExtension at unmappable char +// set mangleExt = true + + srcPtr = info->workingExt; + + // terminate at first unmappable char position + while (*srcPtr != 0) + { + if (!IS_UNICODE_MAPPABLE_TO_MAC_ASCII(*srcPtr)) + { + *srcPtr = 0; + info->mangleExt = TRUE; + } + else + { + srcPtr++; + } + } + } + + +// base - check base for unmappable +// if (firstChar is unmappable) +// substitute ??? for file name in workingBaseName +// set mangleBase to true +// else +// tuncate at first unmappable in workingBaseName +// set mangleBase to true + + if (info->baseLen > 0) // filename doesn't start with dot + { + int len = 0; + + + srcPtr = info->workingBase; + + // terminate at first unmappable char position + while (*srcPtr != 0) + { + if (!IS_UNICODE_MAPPABLE_TO_MAC_ASCII(*srcPtr)) + { + *srcPtr = 0; + info->mangleBase = TRUE; + } + else + { + srcPtr++; + } + } + + len = LB_unilen (info->workingBase); + if (len == 0) // first char is unmappable + { + info->workingBase[0] = '?'; + info->workingBase[1] = '?'; + info->workingBase[2] = '?'; + info->workingBase[3] = 0; + } + } + + return (0); + +} + +STATUS COMN_MakeShortMacFileName (zInfo_s * zSrcInfo, unicode_t * uniFileName, BYTE * macByteName) +{ + unicode_t * mangleStr = NULL; + unicode_t * uPtr; + parseInfo * info = NULL; + unicode_t * mangledName = NULL; + STATUS rc = 0; + + if (uniFileName) + *uniFileName = 0; + if (macByteName) + *macByteName = 0; + + mangleStr = malloc(256); + if (mangleStr == NULL) + { +// printf ("Unable to allocate Mangle String buffer\r\n"); + rc = zERR_NO_MEMORY; + goto Cleanup; + } + + mangledName = malloc (256); + if (mangledName == NULL) + { +// printf ("Unable to allocate mangledName buffer\r\n"); + rc = zERR_NO_MEMORY; + goto Cleanup; + } + + info = malloc (sizeof (*info) ); + if (info == NULL) + { +// printf ("Unable to allocate parse info structure\r\n"); + rc = zERR_NO_MEMORY; + goto Cleanup; + } + + uPtr = zInfoGetFileName(zSrcInfo, zNSPACE_MAC); + + if (uPtr == NULL) + { + rc = zERR_NO_NAMES_IN_PATH; + goto Cleanup; + } + + rc = parseFileName (info, uPtr); + + if (rc != zOK) + goto Cleanup; + + uPtr = getMangleString (mangleStr, zSrcInfo->std.zid); + if (uPtr == NULL) + { + rc = zERR_AFP_MAKE_STRING_FROM_ZID_FAILED; + goto Cleanup; + } + LB_unicpy (info->mangleStr, mangleStr); + + if (!info->mangleBase && !info->mangleExt && + (info->baseLen + info->extLen + 1 <= MACNS_LEGACY_NAME_LIMIT) ) + { + LB_unicpy (uniFileName, info->srcName); + goto Cleanup; + } + + generateMangledMacName (info, mangledName); + + if (uniFileName) + LB_unicpy (uniFileName, info->mangledName); + + if (macByteName) + { + NINT retLen; + + rc = LB_UnicodeToMacByte(NSS_UNI_CONVERSION_RAW, + (char *)&(info->asciiName), + sizeof (info->asciiName), mangledName, &retLen); + if (rc != zOK) + { + strcpy (info->asciiName, "??"); + } + else + strcpy (macByteName, info->asciiName); + } + +Cleanup: + if (mangleStr) + free(mangleStr); + if (mangledName) + free (mangledName); + if (info) + free (info); + return rc; +} + + +/**************************************************************************** +* Determine if file name matches the #zid mangled format +* Mangled format is 31 chars or less with embedded zid like +* #zid.ext or name.ext#zid or name#zid +****************************************************************************/ + +LONG COMN_GetZidFromMangledName (unicode_t * fileName) +{ + + // make sure file name is <= 31 chars (unmappable char may generate < 31 chars) + // algorithm - check for first # from end + // check for dot in file name and replace it with a NULL terminator + // move ptr up one. + // check if all characters are valid hex numbers + // convert uni to ascii + // convert ascii hex to LONG + // If no valid zid format in name, return 0, else return zid + + unicode_t * uPtr; + utf8_t * utf8Ptr; + BYTE * bPtr, *endPtr; + LONG id; + BYTE buf [80]; + + + BYTE idStr [32]; // buffer for #nnn string, 10 bytes should be enough #nnn + null terminator + + + +// if (getMacNameLimit() > MACNS_LEGACY_NAME_LIMIT) +// return 0; // extended Mac namespace is not enabled + + if (unilen (fileName) > MACNS_LEGACY_NAME_LIMIT) // unmappable chars in file name can be < 31 + return 0; // can't be a generated mangled ID + + uPtr = unirchr (fileName, '#'); + + if (uPtr == NULL) + return 0; // no # in file name, therefore, no ID in name + + utf8Ptr = &idStr[0]; + + uni2utf (uPtr, utf8Ptr, unilen (uPtr) + 1 ); + + buf[0] = 0x2E; // DOT_CHAR + + bPtr = strchr ((char *) utf8Ptr, '.'); + + if (bPtr) // if we found a dot + *bPtr = 0x0; // null terminate at dot + + bPtr = idStr + 1; // set ptr to start of string + + if ( strlen (bPtr) > 8 ) // value will be more than a LONG + return 0; + + bPtr = idStr + 1; + + while (*bPtr) + { + if ( isxdigit (*bPtr) ) + bPtr++; + else + return 0; // not hex string digit, not an ID + } + + // if we get this far, we have something that starts with a # sign + // and contains only hex digits + + bPtr = idStr + 1; // position past # sign and convert hex string + + id = LB_strtol( bPtr, (char **)&endPtr, 16 ); // convert hex string to LONG + + return id; + +} diff --git a/src/nwnss/comn/common/zAPI.c b/src/nwnss/comn/common/zAPI.c new file mode 100644 index 0000000..8a564a0 --- /dev/null +++ b/src/nwnss/comn/common/zAPI.c @@ -0,0 +1,33 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996 Novell, Inc. + | All Rights Reserved. + | + | Source(s): public_core/comn/common/zAPI.c + | + | Minimal userspace import of the zInfo name accessor needed by the COMN + | namespace/name helper path. The function body is kept equivalent to the + | NSS source and does not perform disk or VFS IO. + +-------------------------------------------------------------------------*/ +#include +#include + +unicode_t *zInfoGetFileName(zInfo_s *info, NINT nameSpace) +{ + LONG *fileNames; + + if (info->infoVersion > zINFO_VERSION_D) { + return NULL; + } + if (nameSpace >= info->names.numEntries) { + return NULL; + } + if (info->names.fileNameArray == 0) { + return NULL; + } + fileNames = (LONG *)&((BYTE *)info)[info->names.fileNameArray]; + if (fileNames[nameSpace] == 0) { + return NULL; + } + return (unicode_t *)&(((BYTE *)info)[fileNames[nameSpace]]); +} diff --git a/src/nwnss/library/stdlib/strtol.c b/src/nwnss/library/stdlib/strtol.c new file mode 100644 index 0000000..c71f534 --- /dev/null +++ b/src/nwnss/library/stdlib/strtol.c @@ -0,0 +1,17 @@ +/**************************************************************************** + | + | (C) Copyright 1985, 1991, 1993, 1996 Novell, Inc. + | All Rights Reserved. + | + | Source(s): NSS libNSS stdlib export ABI, shared/sdk/library/xStdlib.h + | + | This userspace port preserves the NSS LB_strtol symbol and delegates the + | libc-near conversion to the host C library. + +-------------------------------------------------------------------------*/ +#include +#include + +long int LB_strtol(const char *nptr, char **endptr, int base) +{ + return strtol(nptr, endptr, base); +} diff --git a/tests/nwnss/namespace/test_nwnss_namespace.c b/tests/nwnss/namespace/test_nwnss_namespace.c index 077b35b..f9f4d4a 100644 --- a/tests/nwnss/namespace/test_nwnss_namespace.c +++ b/tests/nwnss/namespace/test_nwnss_namespace.c @@ -45,6 +45,7 @@ #include #include #include "dosNSpace.h" +#include #define CHECK(expr) do { \ if (!(expr)) { \ @@ -84,6 +85,7 @@ int main(void) CHECK(LB_isxdigit('A')); CHECK(sizeof(FullDirectoryInfo_s) >= sizeof(unicode_t)); CHECK(COMN_MakeShortMacFileName == COMN_MakeShortMacFileName); + CHECK(LB_strtol("1f", NULL, 16) == 31); CHECK(sizeof(ObjectIDCacheCtrl_s) >= sizeof(DQhead_t)); CHECK(CACHE_Startup == CACHE_Startup); CHECK(BEASTHASH_Remove == BEASTHASH_Remove); @@ -117,5 +119,32 @@ int main(void) CHECK(DOSNS_wildReplace(NULL, src_pattern, src_name, NULL, answer) == zOK); CHECK(unicode_equals_ascii(answer, "FOO.TXT")); + { + struct { + zInfo_s info; + LONG names[2]; + unicode_t mac_name[8]; + } sample; + unicode_t out_name[64]; + BYTE out_mac[64]; + + memset(&sample, 0, sizeof(sample)); + sample.info.infoVersion = zINFO_VERSION_D; + sample.info.names.numEntries = 2; + sample.info.names.fileNameArray = (LONG)((BYTE *)sample.names - (BYTE *)&sample.info); + sample.names[zNSPACE_MAC] = (LONG)((BYTE *)sample.mac_name - (BYTE *)&sample.info); + sample.mac_name[0] = 'R'; + sample.mac_name[1] = 'E'; + sample.mac_name[2] = 'A'; + sample.mac_name[3] = 'D'; + sample.mac_name[4] = 'M'; + sample.mac_name[5] = 'E'; + sample.mac_name[6] = 0; + + CHECK(zInfoGetFileName(&sample.info, zNSPACE_MAC) == sample.mac_name); + CHECK(COMN_MakeShortMacFileName(&sample.info, out_name, out_mac) == zOK); + CHECK(unicode_equals_ascii(out_name, "README")); + } + return 0; }