mirror of
https://github.com/fadden/nulib2.git
synced 2024-05-28 08:41:29 +00:00
Upped version number to v2.0.0.
Fixed filename conversion issues. Specifically: - Correctly handle '%' when preservation is OFF. - Accept 4-character extensions in '-ee' without risk of buffer overflow. - Fixed broken assert when converting long %xx names. - Store "AUX" as "%00AUX" when preserving names under Win32 (vs. "_AUX"). - Always store files with ':' as path separator. - Recognize that some Win32 variants (Win2K and later at the least) will accept both '/' and '\' as pathname separators. - Correctly convert ".//foo" to "foo" instead of "/foo". Corrected definition of F_OK under Win32.
This commit is contained in:
parent
861eb84b4d
commit
0d053dca09
|
@ -20,7 +20,7 @@
|
||||||
#define kFilenameExtDelim '.' /* separates extension from filename */
|
#define kFilenameExtDelim '.' /* separates extension from filename */
|
||||||
#define kResourceFlag 'r'
|
#define kResourceFlag 'r'
|
||||||
#define kDiskImageFlag 'i'
|
#define kDiskImageFlag 'i'
|
||||||
#define kMaxExtLen 4 /* ".123" */
|
#define kMaxExtLen 5 /* ".1234" */
|
||||||
#define kResourceStr "_rsrc_"
|
#define kResourceStr "_rsrc_"
|
||||||
|
|
||||||
/* must be longer then strlen(kResourceStr)... no problem there */
|
/* must be longer then strlen(kResourceStr)... no problem there */
|
||||||
|
@ -182,7 +182,7 @@ AddPreservationString(NulibState* pState,
|
||||||
pExt = nil;
|
pExt = nil;
|
||||||
else
|
else
|
||||||
pExt = FindExtension(pState, pathBuf);
|
pExt = FindExtension(pState, pathBuf);
|
||||||
if (pExt != nil && strlen(pExt+1) <= kMaxExtLen) {
|
if (pExt != nil && strlen(pExt+1) < kMaxExtLen) {
|
||||||
pExt++; /* skip past the '.' */
|
pExt++; /* skip past the '.' */
|
||||||
|
|
||||||
/* if it's strictly decimal-numeric, don't use it (.1, .2, etc) */
|
/* if it's strictly decimal-numeric, don't use it (.1, .2, etc) */
|
||||||
|
@ -250,6 +250,7 @@ NormalizePath(NulibState* pState, NuPathnameProposal* pPathProposal)
|
||||||
const char* endp;
|
const char* endp;
|
||||||
char* dstp;
|
char* dstp;
|
||||||
char localFssep;
|
char localFssep;
|
||||||
|
int newBufLen;
|
||||||
|
|
||||||
Assert(pState != nil);
|
Assert(pState != nil);
|
||||||
Assert(pPathProposal != nil);
|
Assert(pPathProposal != nil);
|
||||||
|
@ -262,8 +263,8 @@ NormalizePath(NulibState* pState, NuPathnameProposal* pPathProposal)
|
||||||
* requires converting all chars to '%' codes and adding the longest
|
* requires converting all chars to '%' codes and adding the longest
|
||||||
* possible preservation string.
|
* possible preservation string.
|
||||||
*/
|
*/
|
||||||
NState_SetTempPathnameLen(pState,
|
newBufLen = strlen(pPathProposal->pathname)*3 + kMaxPathGrowth +1;
|
||||||
strlen(pPathProposal->pathname)*3 + kMaxPathGrowth +1);
|
NState_SetTempPathnameLen(pState, newBufLen);
|
||||||
pathBuf = NState_GetTempPathnameBuf(pState);
|
pathBuf = NState_GetTempPathnameBuf(pState);
|
||||||
Assert(pathBuf != nil);
|
Assert(pathBuf != nil);
|
||||||
if (pathBuf == nil)
|
if (pathBuf == nil)
|
||||||
|
@ -316,8 +317,7 @@ NormalizePath(NulibState* pState, NuPathnameProposal* pPathProposal)
|
||||||
pPathProposal->newFilenameSeparator = localFssep;
|
pPathProposal->newFilenameSeparator = localFssep;
|
||||||
|
|
||||||
/* check for overflow */
|
/* check for overflow */
|
||||||
Assert(dstp - pathBuf <=
|
Assert(dstp - pathBuf <= newBufLen);
|
||||||
(int)(strlen(pPathProposal->pathname) + kMaxPathGrowth));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If "junk paths" is set, drop everything but the last component.
|
* If "junk paths" is set, drop everything but the last component.
|
||||||
|
@ -543,7 +543,8 @@ DenormalizePath(NulibState* pState, char* pathBuf)
|
||||||
if (isxdigit((int)*srcp)) {
|
if (isxdigit((int)*srcp)) {
|
||||||
/* valid, output char */
|
/* valid, output char */
|
||||||
ch += HexDigit(*srcp);
|
ch += HexDigit(*srcp);
|
||||||
*dstp++ = ch;
|
if (ch != '\0') /* used by Win32 converter */
|
||||||
|
*dstp++ = ch;
|
||||||
srcp++;
|
srcp++;
|
||||||
} else {
|
} else {
|
||||||
/* bogus '%' with trailing hex digit found! */
|
/* bogus '%' with trailing hex digit found! */
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
/* replace unsupported chars with '%xx' */
|
/* replace unsupported chars with '%xx' */
|
||||||
#define kForeignIndic '%'
|
#define kForeignIndic '%'
|
||||||
|
|
||||||
|
/* use this to separate path components in stored filenames */
|
||||||
|
#define kStorageFssep ':'
|
||||||
|
|
||||||
/* make our one-line comments this big */
|
/* make our one-line comments this big */
|
||||||
#define kDefaultCommentLen 200
|
#define kDefaultCommentLen 200
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "Nulib2.h"
|
#include "Nulib2.h"
|
||||||
|
|
||||||
|
|
||||||
static const char* gProgramVersion = "1.1.0";
|
static const char* gProgramVersion = "2.0.0";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -28,6 +28,11 @@ NState_Init(NulibState** ppState)
|
||||||
* Initialize the contents to default values.
|
* Initialize the contents to default values.
|
||||||
*/
|
*/
|
||||||
(*ppState)->systemPathSeparator = PATH_SEP;
|
(*ppState)->systemPathSeparator = PATH_SEP;
|
||||||
|
#ifdef PATH_SEP2
|
||||||
|
(*ppState)->altSystemPathSeparator = PATH_SEP2;
|
||||||
|
#else
|
||||||
|
(*ppState)->altSystemPathSeparator = '\0';
|
||||||
|
#endif
|
||||||
(*ppState)->programVersion = gProgramVersion;
|
(*ppState)->programVersion = gProgramVersion;
|
||||||
|
|
||||||
return kNuErrNone;
|
return kNuErrNone;
|
||||||
|
@ -108,6 +113,9 @@ NState_DebugDump(const NulibState* pState)
|
||||||
printf("NState:\n");
|
printf("NState:\n");
|
||||||
printf(" programVersion: '%s'\n", pState->programVersion);
|
printf(" programVersion: '%s'\n", pState->programVersion);
|
||||||
printf(" systemPathSeparator: '%c'\n", pState->systemPathSeparator);
|
printf(" systemPathSeparator: '%c'\n", pState->systemPathSeparator);
|
||||||
|
if (pState->altSystemPathSeparator != '\0')
|
||||||
|
printf(" altSystemPathSeparator: '%c'\n",
|
||||||
|
pState->altSystemPathSeparator);
|
||||||
printf(" archiveFilename: '%s'\n", pState->archiveFilename);
|
printf(" archiveFilename: '%s'\n", pState->archiveFilename);
|
||||||
printf(" filespec: %ld (%s ...)\n", pState->filespecCount,
|
printf(" filespec: %ld (%s ...)\n", pState->filespecCount,
|
||||||
!pState->filespecCount ? "<none>" : *pState->filespecPointer);
|
!pState->filespecCount ? "<none>" : *pState->filespecPointer);
|
||||||
|
@ -160,6 +168,12 @@ NState_GetSystemPathSeparator(const NulibState* pState)
|
||||||
return pState->systemPathSeparator;
|
return pState->systemPathSeparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char
|
||||||
|
NState_GetAltSystemPathSeparator(const NulibState* pState)
|
||||||
|
{
|
||||||
|
return pState->altSystemPathSeparator;
|
||||||
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
NState_GetProgramVersion(const NulibState* pState)
|
NState_GetProgramVersion(const NulibState* pState)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,6 +38,7 @@ typedef struct NulibState {
|
||||||
|
|
||||||
/* system-specific values */
|
/* system-specific values */
|
||||||
char systemPathSeparator;
|
char systemPathSeparator;
|
||||||
|
char altSystemPathSeparator;
|
||||||
|
|
||||||
/* pointer to archive we're working with */
|
/* pointer to archive we're working with */
|
||||||
NuArchive* pArchive;
|
NuArchive* pArchive;
|
||||||
|
@ -88,6 +89,7 @@ void NState_DebugDump(const NulibState* pState);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char NState_GetSystemPathSeparator(const NulibState* pState);
|
char NState_GetSystemPathSeparator(const NulibState* pState);
|
||||||
|
char NState_GetAltSystemPathSeparator(const NulibState* pState);
|
||||||
const char* NState_GetProgramVersion(const NulibState* pState);
|
const char* NState_GetProgramVersion(const NulibState* pState);
|
||||||
NuArchive* NState_GetNuArchive(const NulibState* pState);
|
NuArchive* NState_GetNuArchive(const NulibState* pState);
|
||||||
void NState_SetNuArchive(NulibState* pState, NuArchive* pArchive);
|
void NState_SetNuArchive(NulibState* pState, NuArchive* pArchive);
|
||||||
|
|
|
@ -94,7 +94,7 @@
|
||||||
|
|
||||||
#if defined(WINDOWS_LIKE)
|
#if defined(WINDOWS_LIKE)
|
||||||
# ifndef F_OK
|
# ifndef F_OK
|
||||||
# define F_OK 02
|
# define F_OK 00
|
||||||
# endif
|
# endif
|
||||||
# ifndef R_OK
|
# ifndef R_OK
|
||||||
# define R_OK 04
|
# define R_OK 04
|
||||||
|
|
|
@ -80,9 +80,10 @@ UNIXNormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
|
||||||
while (srcLen--) { /* don't go until null found! */
|
while (srcLen--) { /* don't go until null found! */
|
||||||
Assert(*srcp != '\0');
|
Assert(*srcp != '\0');
|
||||||
|
|
||||||
if (*srcp == '%') {
|
if (*srcp == kForeignIndic) {
|
||||||
/* change '%' to "%%" */
|
/* change '%' to "%%" */
|
||||||
*dstp++ = *srcp;
|
if (NState_GetModPreserveType(pState))
|
||||||
|
*dstp++ = *srcp;
|
||||||
*dstp++ = *srcp++;
|
*dstp++ = *srcp++;
|
||||||
} else if (*srcp == '/') {
|
} else if (*srcp == '/') {
|
||||||
/* change '/' to "%2f" */
|
/* change '/' to "%2f" */
|
||||||
|
@ -110,7 +111,9 @@ UNIXNormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
|
||||||
#elif defined(WINDOWS_LIKE)
|
#elif defined(WINDOWS_LIKE)
|
||||||
/*
|
/*
|
||||||
* You can't create files or directories with these names on a FAT filesystem,
|
* You can't create files or directories with these names on a FAT filesystem,
|
||||||
* because they're MS-DOS "device special files".
|
* because they're MS-DOS "device special files". So, we either prepend
|
||||||
|
* a '_' (if we're not preserving filenames) or "%00" (if we are). The
|
||||||
|
* "%00" sequence gets stripped off during denormalization.
|
||||||
*
|
*
|
||||||
* The list comes from the Linux kernel's fs/msdos/namei.c.
|
* The list comes from the Linux kernel's fs/msdos/namei.c.
|
||||||
*/
|
*/
|
||||||
|
@ -139,7 +142,12 @@ Win32NormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
|
||||||
for (ppcch = fatReservedNames3; *ppcch != nil; ppcch++) {
|
for (ppcch = fatReservedNames3; *ppcch != nil; ppcch++) {
|
||||||
if (strncasecmp(srcp, *ppcch, srcLen) == 0) {
|
if (strncasecmp(srcp, *ppcch, srcLen) == 0) {
|
||||||
DBUG(("--- fixing '%s'\n", *ppcch));
|
DBUG(("--- fixing '%s'\n", *ppcch));
|
||||||
*dstp++ = '_';
|
if (NState_GetModPreserveType(pState)) {
|
||||||
|
*dstp++ = kForeignIndic;
|
||||||
|
*dstp++ = '0';
|
||||||
|
*dstp++ = '0';
|
||||||
|
} else
|
||||||
|
*dstp++ = '_';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +157,12 @@ Win32NormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
|
||||||
for (ppcch = fatReservedNames4; *ppcch != nil; ppcch++) {
|
for (ppcch = fatReservedNames4; *ppcch != nil; ppcch++) {
|
||||||
if (strncasecmp(srcp, *ppcch, srcLen) == 0) {
|
if (strncasecmp(srcp, *ppcch, srcLen) == 0) {
|
||||||
DBUG(("--- fixing '%s'\n", *ppcch));
|
DBUG(("--- fixing '%s'\n", *ppcch));
|
||||||
*dstp++ = '_';
|
if (NState_GetModPreserveType(pState)) {
|
||||||
|
*dstp++ = kForeignIndic;
|
||||||
|
*dstp++ = '0';
|
||||||
|
*dstp++ = '0';
|
||||||
|
} else
|
||||||
|
*dstp++ = '_';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,9 +172,10 @@ Win32NormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
|
||||||
while (srcLen--) { /* don't go until null found! */
|
while (srcLen--) { /* don't go until null found! */
|
||||||
Assert(*srcp != '\0');
|
Assert(*srcp != '\0');
|
||||||
|
|
||||||
if (*srcp == '%') {
|
if (*srcp == kForeignIndic) {
|
||||||
/* change '%' to "%%" */
|
/* change '%' to "%%" */
|
||||||
*dstp++ = *srcp;
|
if (NState_GetModPreserveType(pState))
|
||||||
|
*dstp++ = *srcp;
|
||||||
*dstp++ = *srcp++;
|
*dstp++ = *srcp++;
|
||||||
} else if (strchr(kInvalid, *srcp) != nil) {
|
} else if (strchr(kInvalid, *srcp) != nil) {
|
||||||
/* change invalid char to "%2f" or '_' */
|
/* change invalid char to "%2f" or '_' */
|
||||||
|
@ -397,6 +411,22 @@ UNIXTimeToDateTime(const time_t* pWhen, NuDateTime *pDateTime)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(UNIX_LIKE) || defined(WINDOWS_LIKE)
|
#if defined(UNIX_LIKE) || defined(WINDOWS_LIKE)
|
||||||
|
/*
|
||||||
|
* Replace "oldc" with "newc". If we find an instance of "newc" already
|
||||||
|
* in the string, replace it with "newSubst".
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ReplaceFssep(char* str, char oldc, char newc, char newSubst)
|
||||||
|
{
|
||||||
|
while (*str != '\0') {
|
||||||
|
if (*str == oldc)
|
||||||
|
*str = newc;
|
||||||
|
else if (*str == newc)
|
||||||
|
*str = newSubst;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the contents of a NuFileDetails structure, based on the pathname
|
* Set the contents of a NuFileDetails structure, based on the pathname
|
||||||
* and characteristics of the file.
|
* and characteristics of the file.
|
||||||
|
@ -407,6 +437,7 @@ SetFileDetails(NulibState* pState, const char* pathname, struct stat* psb,
|
||||||
{
|
{
|
||||||
Boolean wasPreserved;
|
Boolean wasPreserved;
|
||||||
Boolean doJunk = false;
|
Boolean doJunk = false;
|
||||||
|
Boolean adjusted;
|
||||||
char* livePathStr;
|
char* livePathStr;
|
||||||
char slashDotDotSlash[5] = "_.._";
|
char slashDotDotSlash[5] = "_.._";
|
||||||
time_t now;
|
time_t now;
|
||||||
|
@ -421,12 +452,20 @@ SetFileDetails(NulibState* pState, const char* pathname, struct stat* psb,
|
||||||
Assert(livePathStr != nil);
|
Assert(livePathStr != nil);
|
||||||
strcpy(livePathStr, pathname);
|
strcpy(livePathStr, pathname);
|
||||||
|
|
||||||
|
/* under Win32, both '/' and '\' work... we want to settle on one */
|
||||||
|
if (NState_GetAltSystemPathSeparator(pState) != '\0') {
|
||||||
|
ReplaceFssep(livePathStr,
|
||||||
|
NState_GetAltSystemPathSeparator(pState),
|
||||||
|
NState_GetSystemPathSeparator(pState),
|
||||||
|
NState_GetSystemPathSeparator(pState));
|
||||||
|
}
|
||||||
|
|
||||||
/* init to defaults */
|
/* init to defaults */
|
||||||
memset(pDetails, 0, sizeof(*pDetails));
|
memset(pDetails, 0, sizeof(*pDetails));
|
||||||
pDetails->threadID = kNuThreadIDDataFork;
|
pDetails->threadID = kNuThreadIDDataFork;
|
||||||
pDetails->storageName = livePathStr; /* point at temp buffer */
|
pDetails->storageName = livePathStr; /* point at temp buffer */
|
||||||
pDetails->fileSysID = kNuFileSysUnknown;
|
pDetails->fileSysID = kNuFileSysUnknown;
|
||||||
pDetails->fileSysInfo = NState_GetSystemPathSeparator(pState);
|
pDetails->fileSysInfo = kStorageFssep;
|
||||||
pDetails->fileType = 0;
|
pDetails->fileType = 0;
|
||||||
pDetails->extraType = 0;
|
pDetails->extraType = 0;
|
||||||
pDetails->storageType = kNuStorageUnknown; /* let NufxLib worry about it */
|
pDetails->storageType = kNuStorageUnknown; /* let NufxLib worry about it */
|
||||||
|
@ -483,23 +522,40 @@ SetFileDetails(NulibState* pState, const char* pathname, struct stat* psb,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for other unpleasantness, such as a leading fssep.
|
* Strip bad chars off the front of the pathname. Every time we
|
||||||
|
* remove one thing we potentially expose another, so we have to
|
||||||
|
* loop until it's sanitized.
|
||||||
|
*
|
||||||
|
* The outer loop isn't really necessary under Win32, because you'd
|
||||||
|
* need to do something like ".\\foo", which isn't allowed. UNIX
|
||||||
|
* silently allows ".//foo", so this is a problem there. (We could
|
||||||
|
* probably do away with the inner loops, but those were already
|
||||||
|
* written when I saw the larger problem.)
|
||||||
*/
|
*/
|
||||||
Assert(NState_GetSystemPathSeparator(pState) != '\0');
|
do {
|
||||||
while (livePathStr[0] == NState_GetSystemPathSeparator(pState)) {
|
adjusted = false;
|
||||||
/* slide it down, len is strlen +1 (for null) -1 (dropping first char)*/
|
|
||||||
memmove(livePathStr, livePathStr+1, strlen(livePathStr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove leading "./".
|
* Check for other unpleasantness, such as a leading fssep.
|
||||||
*/
|
*/
|
||||||
while (livePathStr[0] == '.' &&
|
Assert(NState_GetSystemPathSeparator(pState) != '\0');
|
||||||
livePathStr[1] == NState_GetSystemPathSeparator(pState))
|
while (livePathStr[0] == NState_GetSystemPathSeparator(pState)) {
|
||||||
{
|
/* slide it down, len is (strlen +1), -1 (dropping first char)*/
|
||||||
/* slide it down, len is strlen +1 (for null) -2 (dropping two chars) */
|
memmove(livePathStr, livePathStr+1, strlen(livePathStr));
|
||||||
memmove(livePathStr, livePathStr+2, strlen(livePathStr)-1);
|
adjusted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove leading "./".
|
||||||
|
*/
|
||||||
|
while (livePathStr[0] == '.' &&
|
||||||
|
livePathStr[1] == NState_GetSystemPathSeparator(pState))
|
||||||
|
{
|
||||||
|
/* slide it down, len is (strlen +1) -2 (dropping two chars) */
|
||||||
|
memmove(livePathStr, livePathStr+2, strlen(livePathStr)-1);
|
||||||
|
adjusted = true;
|
||||||
|
}
|
||||||
|
} while (adjusted);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's a "/../" present anywhere in the name, junk everything
|
* If there's a "/../" present anywhere in the name, junk everything
|
||||||
|
@ -517,6 +573,13 @@ SetFileDetails(NulibState* pState, const char* pathname, struct stat* psb,
|
||||||
doJunk = true;
|
doJunk = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scan for and remove "/./" and trailing "/.". They're filesystem
|
||||||
|
* no-ops that work just fine under Win32 and UNIX but could confuse
|
||||||
|
* a IIgs. (Of course, the user could just omit them from the pathname.)
|
||||||
|
*/
|
||||||
|
/* TO DO 20030208 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If "junk paths" is set, drop everything before the last fssep char.
|
* If "junk paths" is set, drop everything before the last fssep char.
|
||||||
*/
|
*/
|
||||||
|
@ -529,6 +592,16 @@ SetFileDetails(NulibState* pState, const char* pathname, struct stat* psb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finally, substitute our generally-accepted path separator in place of
|
||||||
|
* the local one, stomping on anything with a ':' in it as we do. The
|
||||||
|
* goal is to avoid having "subdir:foo/bar" turn into "subdir/foo/bar".
|
||||||
|
* Were we a general-purpose archiver, this might be a mistake, but
|
||||||
|
* we're not. NuFX doesn't really give us a choice.
|
||||||
|
*/
|
||||||
|
ReplaceFssep(livePathStr, NState_GetSystemPathSeparator(pState),
|
||||||
|
kStorageFssep, 'X');
|
||||||
|
|
||||||
/*bail:*/
|
/*bail:*/
|
||||||
return kNuErrNone;
|
return kNuErrNone;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user