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:
Andy McFadden 2003-02-08 22:35:31 +00:00
parent 861eb84b4d
commit 0d053dca09
6 changed files with 125 additions and 32 deletions

View File

@ -20,7 +20,7 @@
#define kFilenameExtDelim '.' /* separates extension from filename */
#define kResourceFlag 'r'
#define kDiskImageFlag 'i'
#define kMaxExtLen 4 /* ".123" */
#define kMaxExtLen 5 /* ".1234" */
#define kResourceStr "_rsrc_"
/* must be longer then strlen(kResourceStr)... no problem there */
@ -182,7 +182,7 @@ AddPreservationString(NulibState* pState,
pExt = nil;
else
pExt = FindExtension(pState, pathBuf);
if (pExt != nil && strlen(pExt+1) <= kMaxExtLen) {
if (pExt != nil && strlen(pExt+1) < kMaxExtLen) {
pExt++; /* skip past the '.' */
/* 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;
char* dstp;
char localFssep;
int newBufLen;
Assert(pState != nil);
Assert(pPathProposal != nil);
@ -262,8 +263,8 @@ NormalizePath(NulibState* pState, NuPathnameProposal* pPathProposal)
* requires converting all chars to '%' codes and adding the longest
* possible preservation string.
*/
NState_SetTempPathnameLen(pState,
strlen(pPathProposal->pathname)*3 + kMaxPathGrowth +1);
newBufLen = strlen(pPathProposal->pathname)*3 + kMaxPathGrowth +1;
NState_SetTempPathnameLen(pState, newBufLen);
pathBuf = NState_GetTempPathnameBuf(pState);
Assert(pathBuf != nil);
if (pathBuf == nil)
@ -316,8 +317,7 @@ NormalizePath(NulibState* pState, NuPathnameProposal* pPathProposal)
pPathProposal->newFilenameSeparator = localFssep;
/* check for overflow */
Assert(dstp - pathBuf <=
(int)(strlen(pPathProposal->pathname) + kMaxPathGrowth));
Assert(dstp - pathBuf <= newBufLen);
/*
* If "junk paths" is set, drop everything but the last component.
@ -543,7 +543,8 @@ DenormalizePath(NulibState* pState, char* pathBuf)
if (isxdigit((int)*srcp)) {
/* valid, output char */
ch += HexDigit(*srcp);
*dstp++ = ch;
if (ch != '\0') /* used by Win32 converter */
*dstp++ = ch;
srcp++;
} else {
/* bogus '%' with trailing hex digit found! */

View File

@ -20,6 +20,9 @@
/* replace unsupported chars with '%xx' */
#define kForeignIndic '%'
/* use this to separate path components in stored filenames */
#define kStorageFssep ':'
/* make our one-line comments this big */
#define kDefaultCommentLen 200

View File

@ -9,7 +9,7 @@
#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.
*/
(*ppState)->systemPathSeparator = PATH_SEP;
#ifdef PATH_SEP2
(*ppState)->altSystemPathSeparator = PATH_SEP2;
#else
(*ppState)->altSystemPathSeparator = '\0';
#endif
(*ppState)->programVersion = gProgramVersion;
return kNuErrNone;
@ -108,6 +113,9 @@ NState_DebugDump(const NulibState* pState)
printf("NState:\n");
printf(" programVersion: '%s'\n", pState->programVersion);
printf(" systemPathSeparator: '%c'\n", pState->systemPathSeparator);
if (pState->altSystemPathSeparator != '\0')
printf(" altSystemPathSeparator: '%c'\n",
pState->altSystemPathSeparator);
printf(" archiveFilename: '%s'\n", pState->archiveFilename);
printf(" filespec: %ld (%s ...)\n", pState->filespecCount,
!pState->filespecCount ? "<none>" : *pState->filespecPointer);
@ -160,6 +168,12 @@ NState_GetSystemPathSeparator(const NulibState* pState)
return pState->systemPathSeparator;
}
char
NState_GetAltSystemPathSeparator(const NulibState* pState)
{
return pState->altSystemPathSeparator;
}
const char*
NState_GetProgramVersion(const NulibState* pState)
{

View File

@ -38,6 +38,7 @@ typedef struct NulibState {
/* system-specific values */
char systemPathSeparator;
char altSystemPathSeparator;
/* pointer to archive we're working with */
NuArchive* pArchive;
@ -88,6 +89,7 @@ void NState_DebugDump(const NulibState* pState);
#endif
char NState_GetSystemPathSeparator(const NulibState* pState);
char NState_GetAltSystemPathSeparator(const NulibState* pState);
const char* NState_GetProgramVersion(const NulibState* pState);
NuArchive* NState_GetNuArchive(const NulibState* pState);
void NState_SetNuArchive(NulibState* pState, NuArchive* pArchive);

View File

@ -94,7 +94,7 @@
#if defined(WINDOWS_LIKE)
# ifndef F_OK
# define F_OK 02
# define F_OK 00
# endif
# ifndef R_OK
# define R_OK 04

View File

@ -80,9 +80,10 @@ UNIXNormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
while (srcLen--) { /* don't go until null found! */
Assert(*srcp != '\0');
if (*srcp == '%') {
if (*srcp == kForeignIndic) {
/* change '%' to "%%" */
*dstp++ = *srcp;
if (NState_GetModPreserveType(pState))
*dstp++ = *srcp;
*dstp++ = *srcp++;
} else if (*srcp == '/') {
/* change '/' to "%2f" */
@ -110,7 +111,9 @@ UNIXNormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
#elif defined(WINDOWS_LIKE)
/*
* 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.
*/
@ -139,7 +142,12 @@ Win32NormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
for (ppcch = fatReservedNames3; *ppcch != nil; ppcch++) {
if (strncasecmp(srcp, *ppcch, srcLen) == 0) {
DBUG(("--- fixing '%s'\n", *ppcch));
*dstp++ = '_';
if (NState_GetModPreserveType(pState)) {
*dstp++ = kForeignIndic;
*dstp++ = '0';
*dstp++ = '0';
} else
*dstp++ = '_';
break;
}
}
@ -149,7 +157,12 @@ Win32NormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
for (ppcch = fatReservedNames4; *ppcch != nil; ppcch++) {
if (strncasecmp(srcp, *ppcch, srcLen) == 0) {
DBUG(("--- fixing '%s'\n", *ppcch));
*dstp++ = '_';
if (NState_GetModPreserveType(pState)) {
*dstp++ = kForeignIndic;
*dstp++ = '0';
*dstp++ = '0';
} else
*dstp++ = '_';
break;
}
}
@ -159,9 +172,10 @@ Win32NormalizeFileName(NulibState* pState, const char* srcp, long srcLen,
while (srcLen--) { /* don't go until null found! */
Assert(*srcp != '\0');
if (*srcp == '%') {
if (*srcp == kForeignIndic) {
/* change '%' to "%%" */
*dstp++ = *srcp;
if (NState_GetModPreserveType(pState))
*dstp++ = *srcp;
*dstp++ = *srcp++;
} else if (strchr(kInvalid, *srcp) != nil) {
/* change invalid char to "%2f" or '_' */
@ -397,6 +411,22 @@ UNIXTimeToDateTime(const time_t* pWhen, NuDateTime *pDateTime)
#endif
#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
* and characteristics of the file.
@ -407,6 +437,7 @@ SetFileDetails(NulibState* pState, const char* pathname, struct stat* psb,
{
Boolean wasPreserved;
Boolean doJunk = false;
Boolean adjusted;
char* livePathStr;
char slashDotDotSlash[5] = "_.._";
time_t now;
@ -421,12 +452,20 @@ SetFileDetails(NulibState* pState, const char* pathname, struct stat* psb,
Assert(livePathStr != nil);
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 */
memset(pDetails, 0, sizeof(*pDetails));
pDetails->threadID = kNuThreadIDDataFork;
pDetails->storageName = livePathStr; /* point at temp buffer */
pDetails->fileSysID = kNuFileSysUnknown;
pDetails->fileSysInfo = NState_GetSystemPathSeparator(pState);
pDetails->fileSysInfo = kStorageFssep;
pDetails->fileType = 0;
pDetails->extraType = 0;
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');
while (livePathStr[0] == NState_GetSystemPathSeparator(pState)) {
/* slide it down, len is strlen +1 (for null) -1 (dropping first char)*/
memmove(livePathStr, livePathStr+1, strlen(livePathStr));
}
do {
adjusted = false;
/*
* Remove leading "./".
*/
while (livePathStr[0] == '.' &&
livePathStr[1] == NState_GetSystemPathSeparator(pState))
{
/* slide it down, len is strlen +1 (for null) -2 (dropping two chars) */
memmove(livePathStr, livePathStr+2, strlen(livePathStr)-1);
}
/*
* Check for other unpleasantness, such as a leading fssep.
*/
Assert(NState_GetSystemPathSeparator(pState) != '\0');
while (livePathStr[0] == NState_GetSystemPathSeparator(pState)) {
/* slide it down, len is (strlen +1), -1 (dropping first char)*/
memmove(livePathStr, livePathStr+1, strlen(livePathStr));
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
@ -517,6 +573,13 @@ SetFileDetails(NulibState* pState, const char* pathname, struct stat* psb,
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.
*/
@ -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:*/
return kNuErrNone;
}