From 132a8338b96d3eaf67d2dfcc67f0dcc637f185b1 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Sat, 3 Jan 2015 15:15:05 -0800 Subject: [PATCH] Fix Mac OS X behavior Some fixes to the Mac OS X build: - Replace the Carbon calls that were used to set the creator and file type with xattr calls. The Carbon stuff still worked but caused deprecation warnings. Stop linking against Carbon. - Correct the way resource forks are accessed (from "/rsrc" to "/..namedfork/rsrc"). The native resource fork support is incomplete and doesn't work quite right, so it's now disabled. (Which means the corrections to the file name don't actually do anything, but you can at least play with it.) - Correct the file/aux type conversion, which appeared to do useful things but actually didn't in some circumstances (e.g. when adding files, the code for acquiring the file types needs to be in NuLib2, not NufxLib). - Set creator and file type to 'pdos' values when extracting from a Binary ][ archive. Also, drop some old purify/quantify stuff. --- nufxlib/FileIO.c | 331 ++++++++++++++++-------------------- nufxlib/SysDefs.h | 12 +- nufxlib/configure | 5 - nufxlib/configure.in | 6 - nufxlib/samples/Makefile.in | 16 +- nulib2/Binary2.c | 10 +- nulib2/Filename.c | 2 + nulib2/Makefile.in | 19 +-- nulib2/NuLib2.h | 1 + nulib2/README.txt | 4 +- nulib2/SysDefs.h | 10 ++ nulib2/SysUtils.c | 160 ++++++++++++++++- nulib2/configure | 6 - nulib2/configure.in | 7 - 14 files changed, 345 insertions(+), 244 deletions(-) diff --git a/nufxlib/FileIO.c b/nufxlib/FileIO.c index fc0a441..c4c11db 100644 --- a/nufxlib/FileIO.c +++ b/nufxlib/FileIO.c @@ -19,7 +19,7 @@ #include "NufxLibPriv.h" #ifdef MAC_LIKE -# include +# include #endif /* @@ -214,12 +214,10 @@ typedef struct NuFileInfo { Boolean isRegularFile; /* is this a regular file? */ Boolean isDirectory; /* is this a directory? */ + Boolean isForked; /* does file have a non-empty resource fork? */ uint32_t dataEof; - uint32_t rsrcEof; - uint32_t fileType; - uint32_t auxType; NuDateTime modWhen; mode_t unixMode; /* UNIX-style permissions */ } NuFileInfo; @@ -258,6 +256,98 @@ static Boolean Nu_IsForkedFile(NuArchive* pArchive, const NuRecord* pRecord) } +#if defined(MAC_LIKE) +# if defined(HAS_RESOURCE_FORKS) +/* + * String to append to the filename to access the resource fork. + * + * This appears to be the correct way to access the resource fork, since + * at least OS X 10.1. Up until 10.7 ("Lion", July 2011), you could also + * access the fork with "/rsrc". + */ +static const char kMacRsrcPath[] = "/..namedfork/rsrc"; + +/* + * Generates the resource fork pathname from the file path. + * + * The caller must free the string returned. + */ +static UNICHAR* GetResourcePath(const UNICHAR* pathnameUNI) +{ + Assert(pathnameUNI != NULL); + + // sizeof(kMacRsrcPath) includes the string and the terminating null byte + const size_t bufLen = + strlen(pathnameUNI) * sizeof(UNICHAR) + sizeof(kMacRsrcPath); + char* buf; + + buf = (char*) malloc(bufLen); + snprintf(buf, bufLen, "%s%s", pathnameUNI, kMacRsrcPath); + return buf; +} +# endif /*HAS_RESOURCE_FORKS*/ + +/* + * Due to historical reasons, the XATTR_FINDERINFO_NAME (defined to be + * ``com.apple.FinderInfo'') extended attribute must be 32 bytes; see the + * ATTR_CMN_FNDRINFO section in getattrlist(2). + * + * The FinderInfo block is the concatenation of a FileInfo structure + * and an ExtendedFileInfo (or ExtendedFolderInfo) structure -- see + * ATTR_CMN_FNDRINFO in getattrlist(2). + * + * All we're really interested in is the file type and creator code, + * which are stored big-endian in the first 8 bytes. + */ +static const int kFinderInfoSize = 32; + +/* + * Set the file type and creator type. + */ +static NuError Nu_SetFinderInfo(NuArchive* pArchive, const NuRecord* pRecord, + const UNICHAR* pathnameUNI) +{ + uint8_t fiBuf[kFinderInfoSize]; + + size_t actual = getxattr(pathnameUNI, XATTR_FINDERINFO_NAME, + fiBuf, sizeof(fiBuf), 0, 0); + if (actual == (size_t) -1 && errno == ENOATTR) { + // doesn't yet have Finder info + memset(fiBuf, 0, sizeof(fiBuf)); + } else if (actual != kFinderInfoSize) { + Nu_ReportError(NU_BLOB, errno, + "Finder info on '%s' returned %d", pathnameUNI, (int) actual); + return kNuErrFile; + } + + /* build type and creator from 8-bit type and 16-bit aux type */ + uint32_t fileType, creator; + fileType = ('p' << 24) | ((pRecord->recFileType & 0xff) << 16) | + (pRecord->recExtraType & 0xffff); + creator = 'pdos'; + + fiBuf[0] = fileType >> 24; + fiBuf[1] = fileType >> 16; + fiBuf[2] = fileType >> 8; + fiBuf[3] = fileType; + fiBuf[4] = creator >> 24; + fiBuf[5] = creator >> 16; + fiBuf[6] = creator >> 8; + fiBuf[7] = creator; + + if (setxattr(pathnameUNI, XATTR_FINDERINFO_NAME, fiBuf, sizeof(fiBuf), + 0, 0) != 0) + { + Nu_ReportError(NU_BLOB, errno, + "Unable to set Finder info on '%s'", pathnameUNI); + return kNuErrFile; + } + + return kNuErrNone; +} +#endif /*MAC_LIKE*/ + + /* * Get the file info into a NuFileInfo struct. Fields which are * inappropriate for the current system are set to default values. @@ -295,99 +385,28 @@ static NuError Nu_GetFileInfo(NuArchive* pArchive, const UNICHAR* pathnameUNI, /* BUG: should check for 32-bit overflow from 64-bit off_t */ pFileInfo->dataEof = sbuf.st_size; - pFileInfo->rsrcEof = 0; - pFileInfo->fileType = kDefaultFileType; - pFileInfo->auxType = kDefaultAuxType; -# if defined(MAC_LIKE) + pFileInfo->isForked = false; +# if defined(MAC_LIKE) && defined(HAS_RESOURCE_FORKS) if (!pFileInfo->isDirectory) { - char path[4096]; // TODO: use dynamic alloc or snprintf + /* + * Check for the presence of a resource fork. You can check + * these from a terminal with "ls -l@" -- look for the + * "com.apple.ResourceFork" attribute. + * + * We can either use getxattr() and check for the presence of + * the attribute, or get the file length with stat(). I + * don't know if xattr has always worked with resource forks, + * so we'll stick with stat for now. + */ + UNICHAR* rsrcPath = GetResourcePath(pathnameUNI); + struct stat res_sbuf; - OSErr result; - OSType fileType, creator; - FSCatalogInfo catalogInfo; - FSRef ref; - uint32_t proType, proAux; - - strcpy(path, pathnameUNI); - strcat(path, "/rsrc"); - cc = stat(path, &res_sbuf); - if (cc) { - if (!errno) { - pFileInfo->rsrcEof = res_sbuf.st_size; - } - } - - result = FSPathMakeRef(pathnameUNI, &ref, NULL); - if (!result) { - result = FSGetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catalogInfo, - NULL, NULL, NULL); - if (!result) { - fileType = ((FileInfo *) &catalogInfo.finderInfo)->fileType; - creator = ((FileInfo *) &catalogInfo.finderInfo)->fileCreator; - - /* This actually is probably more efficient than a weird table, for - so few values */ - - switch(creator) { - case 'pdos': - if (fileType == 'PSYS') { - proType = 0xFF; - proAux = 0x0000; - } else if (fileType == 'PS16') { - proType = 0xB3; - proAux = 0x0000; - } else { - if (((fileType >> 24) & 0xFF) == 'p') { - proType = (fileType >> 16) & 0xFF; - proAux = fileType & 0xFFFF; - } else { - proType = 0x00; - proAux = 0x0000; - } - } - break; - case 'dCpy': - if (fileType == 'dImg') { - proType = 0xE0; - proAux = 0x0005; - } else { - proType = 0x00; - proAux = 0x0000; - } - break; - default: - switch(fileType) { - case 'BINA': - proType = 0x06; - proAux = 0x0000; - break; - case 'TEXT': - proType = 0x04; - proAux = 0x0000; - break; - case 'MIDI': - proType = 0xD7; - proAux = 0x0000; - break; - case 'AIFF': - proType = 0xD8; - proAux = 0x0000; - break; - case 'AIFC': - proType = 0xD8; - proAux = 0x0001; - break; - default: - proType = 0x00; - proAux = 0x0000; - break; - } - break; - } - pFileInfo->fileType = proType; - pFileInfo->auxType = proAux; - } + + if (stat(rsrcPath, &res_sbuf) == 0) { + pFileInfo->isForked = (res_sbuf.st_size != 0); } + + free(rsrcPath); } # endif Nu_GMTSecondsToDateTime(&sbuf.st_mtime, &pFileInfo->modWhen); @@ -423,47 +442,14 @@ static NuError Nu_FileForkExists(NuArchive* pArchive, Assert(pExists != NULL); Assert(pFileInfo != NULL); -#if defined(MAC_LIKE) - /* - * On Mac OS X, we do much like on Unix, but we do need to look for - * a resource fork. - */ - *pExists = true; - if (!checkRsrcFork) { - /* - * Check the data fork. - */ - Assert(pArchive->lastFileCreatedUNI == NULL); - err = Nu_GetFileInfo(pArchive, pathnameUNI, pFileInfo); - if (err == kNuErrFileNotFound) { - err = kNuErrNone; - *pExists = false; - } -/* DBUG(("Data fork %s: %d (err %d)\n", pathname, *pExists, err));*/ - } else { - /* - * Check the resource fork. - */ - char path[4096]; // TODO - dynamic alloc or snprintf - strncpy(path, pathnameUNI, 4089); - strcat(path, "/rsrc"); - err = Nu_GetFileInfo(pArchive, path, pFileInfo); - if (err == kNuErrFileNotFound) { - err = kNuErrNone; - *pExists = false; - } else if (!err && !pFileInfo->rsrcEof) { - err = kNuErrNone; - *pExists = false; - } -/* DBUG(("Rsrc fork %s: %d (err %d)\n", path, *pExists, err));*/ - } - -#elif defined(UNIX_LIKE) || defined(WINDOWS_LIKE) +#if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) +# if !defined(MAC_LIKE) /* * On Unix and Windows we ignore "isForkedFile" and "checkRsrcFork". * The file must not exist at all. */ Assert(pArchive->lastFileCreatedUNI == NULL); +# endif *pExists = true; err = Nu_GetFileInfo(pArchive, pathnameUNI, pFileInfo); @@ -472,6 +458,16 @@ static NuError Nu_FileForkExists(NuArchive* pArchive, *pExists = false; } +# if defined(MAC_LIKE) + /* + * On Mac OS X, we'll use the resource fork, but we may not want to + * overwrite existing data. + */ + if (*pExists && checkRsrcFork) { + *pExists = pFileInfo->isForked; + } +# endif + #elif defined(__ORCAC__) /* * If the file doesn't exist, great. If it does, and "lastFileCreated" @@ -617,14 +613,14 @@ bail: * * Generally this just involves ensuring that the file is writable. If * this is a convenient place to truncate it, we should do that too. + * + * 20150103: we don't seem to be doing the truncation here, so prepRsrc + * is unused. */ static NuError Nu_PrepareForWriting(NuArchive* pArchive, const UNICHAR* pathnameUNI, Boolean prepRsrc, NuFileInfo* pFileInfo) { NuError err = kNuErrNone; -#if defined(MAC_LIKE) - char path[4096]; // TODO: use dynamic alloc or snprintf -#endif Assert(pArchive != NULL); Assert(pathnameUNI != NULL); @@ -638,13 +634,6 @@ static NuError Nu_PrepareForWriting(NuArchive* pArchive, return kNuErrNotRegularFile; #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) -# if defined(MAC_LIKE) - if (prepRsrc) { - strcpy(path, pathnameUNI); - strcat(path, "/rsrc"); - pathnameUNI = path; - } -# endif if (!(pFileInfo->unixMode & S_IWUSR)) { /* make it writable by owner, plus whatever it was before */ if (chmod(pathnameUNI, S_IWUSR | pFileInfo->unixMode) < 0) { @@ -770,8 +759,9 @@ static NuError Nu_CreatePathIFN(NuArchive* pArchive, const UNICHAR* pathnameUNI, Assert(fssep != '\0'); pathStart = pathnameUNI; - + #if !defined(MAC_LIKE) /* On the Mac, if it's a full path, treat it like one */ + // 20150103: not sure what use case this is for if (pathnameUNI[0] == fssep) pathStart++; #endif @@ -820,17 +810,17 @@ bail: static NuError Nu_OpenFileForWrite(NuArchive* pArchive, const UNICHAR* pathnameUNI, Boolean openRsrc, FILE** pFp) { -#if defined(MAC_LIKE) - // TODO: fix this -- use dynamic alloc or snprintf - char path[4096]; +#if defined(MAC_LIKE) && defined(HAS_RESOURCE_FORKS) if (openRsrc) { - strcpy(path, pathnameUNI); - strcat(path, "/rsrc"); - pathnameUNI = path; + UNICHAR* rsrcPath = GetResourcePath(pathnameUNI); + *pFp = fopen(rsrcPath, kNuFileOpenWriteTrunc); + free(rsrcPath); + } else { + *pFp = fopen(pathnameUNI, kNuFileOpenWriteTrunc); } -#endif - +#else *pFp = fopen(pathnameUNI, kNuFileOpenWriteTrunc); +#endif if (*pFp == NULL) return errno ? errno : -1; return kNuErrNone; @@ -1110,33 +1100,10 @@ NuError Nu_CloseOutputFile(NuArchive* pArchive, const NuRecord* pRecord, err = Nu_SetFileAccess(pArchive, pRecord, pathnameUNI); BailError(err); -#ifdef MAC_LIKE - OSErr result; - OSType fileType; - FSCatalogInfo catalogInfo; - FSRef ref; - - result = FSPathMakeRef(pathnameUNI, &ref, NULL); - BailError(result); - - result = FSGetCatalogInfo(&ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, - &catalogInfo, NULL, NULL, NULL); - if (result) { - BailError(kNuErrFileStat); - } - - /* Build the type and creator */ - - fileType = 0x70000000; - fileType |= (pRecord->recFileType & 0xFF) << 16; - fileType |= (pRecord->recExtraType & 0xFFFF); - - /* Set the type and creator */ - - ((FileInfo *) &catalogInfo.finderInfo)->fileType = fileType; - ((FileInfo *) &catalogInfo.finderInfo)->fileCreator = 'pdos'; - result = FSSetCatalogInfo(&ref, kFSCatInfoFinderInfo, &catalogInfo); - BailError(result); +#if defined(MAC_LIKE) + /* could also do this earlier and pass the fd for fsetxattr */ + err = Nu_SetFinderInfo(pArchive, pRecord, pathnameUNI); + BailError(err); #endif bail: @@ -1180,12 +1147,11 @@ NuError Nu_OpenInputFile(NuArchive* pArchive, const UNICHAR* pathnameUNI, Assert(pathnameUNI != NULL); Assert(pFp != NULL); -#if defined(MAC_LIKE) - char path[4096]; // TODO - dynamic alloc or snprintf +#if defined(MAC_LIKE) && defined(HAS_RESOURCE_FORKS) + UNICHAR* rsrcPath = NULL; if (openRsrc) { - strcpy(path, pathnameUNI); - strcat(path, "/rsrc"); - pathnameUNI = path; + rsrcPath = GetResourcePath(pathnameUNI); + pathnameUNI = rsrcPath; } #endif @@ -1253,6 +1219,9 @@ bail: pathnameUNI, openRsrc ? " (rsrc fork)" : ""); } } +#if defined(MAC_LIKE) && defined(HAS_RESOURCE_FORKS) + free(rsrcPath); +#endif return err; } diff --git a/nufxlib/SysDefs.h b/nufxlib/SysDefs.h index 86e7aad..b6ff2b1 100644 --- a/nufxlib/SysDefs.h +++ b/nufxlib/SysDefs.h @@ -119,14 +119,10 @@ # endif #endif -/* resource forks on UFS filesystem under Mac OS X are a kluge */ -/*#ifdef MAC*/ -/*# define HAS_RESOURCE_FORKS*/ -/*#endif*/ - -#if defined(__ORCAC__) || defined(MAC_LIKE) -# define HAS_RESOURCE_FORKS -#endif +/* not currently using filesystem resource forks */ +//#if defined(__ORCAC__) || defined(MAC_LIKE) +//# define HAS_RESOURCE_FORKS +//#endif /* __FUNCTION__ was missing from BeOS __MWERKS__, and might be gcc-only */ #ifdef __GNUC__ diff --git a/nufxlib/configure b/nufxlib/configure index 58a8c82..f459119 100755 --- a/nufxlib/configure +++ b/nufxlib/configure @@ -3970,11 +3970,6 @@ elif test "$host_os" = "beos"; then SHARE_FLAGS='-nostartfiles -Xlinker -soname="$@"' fi -if test "$host_vendor" = "apple" -a ${host_os:0:6} = "darwin"; then - echo "checking for Mac OS X... yes, adding -framework Carbon" - LIBS="$LIBS -framework Carbon" -fi - diff --git a/nufxlib/configure.in b/nufxlib/configure.in index d5c3afb..46df1a4 100644 --- a/nufxlib/configure.in +++ b/nufxlib/configure.in @@ -90,12 +90,6 @@ elif test "$host_os" = "beos"; then SHARE_FLAGS='-nostartfiles -Xlinker -soname="$@"' fi -dnl Mac OS X (powerpc-apple-darwin6.6) needs an extra flag. -if test "$host_vendor" = "apple" -a ${host_os:0:6} = "darwin"; then - echo "checking for Mac OS X... yes, adding -framework Carbon" - LIBS="$LIBS -framework Carbon" -fi - AC_SUBST(BUILD_FLAGS) AC_SUBST(SHARE_FLAGS) diff --git a/nufxlib/samples/Makefile.in b/nufxlib/samples/Makefile.in index ca765ef..7f436bf 100644 --- a/nufxlib/samples/Makefile.in +++ b/nufxlib/samples/Makefile.in @@ -35,28 +35,28 @@ all: $(PRODUCTS) @true exerciser: Exerciser.o $(LIB_PRODUCT) - $(PURIFY) $(QUANTIFY) $(CC) -o $@ Exerciser.o $(NUFXLIB) @LIBS@ + $(CC) -o $@ Exerciser.o $(NUFXLIB) @LIBS@ imgconv: ImgConv.o $(LIB_PRODUCT) - $(PURIFY) $(QUANTIFY) $(CC) -o $@ ImgConv.o $(NUFXLIB) @LIBS@ + $(CC) -o $@ ImgConv.o $(NUFXLIB) @LIBS@ launder: Launder.o $(LIB_PRODUCT) - $(PURIFY) $(QUANTIFY) $(CC) -o $@ Launder.o $(NUFXLIB) @LIBS@ + $(CC) -o $@ Launder.o $(NUFXLIB) @LIBS@ test-basic: TestBasic.o $(LIB_PRODUCT) - $(PURIFY) $(QUANTIFY) $(CC) -o $@ TestBasic.o $(NUFXLIB) @LIBS@ + $(CC) -o $@ TestBasic.o $(NUFXLIB) @LIBS@ test-extract: TestExtract.o $(LIB_PRODUCT) - $(PURIFY) $(QUANTIFY) $(CC) -o $@ TestExtract.o $(NUFXLIB) @LIBS@ + $(CC) -o $@ TestExtract.o $(NUFXLIB) @LIBS@ test-names: TestNames.o $(LIB_PRODUCT) - $(PURIFY) $(QUANTIFY) $(CC) -o $@ TestNames.o $(NUFXLIB) @LIBS@ + $(CC) -o $@ TestNames.o $(NUFXLIB) @LIBS@ test-simple: TestSimple.o $(LIB_PRODUCT) - $(PURIFY) $(QUANTIFY) $(CC) -o $@ TestSimple.o $(NUFXLIB) @LIBS@ + $(CC) -o $@ TestSimple.o $(NUFXLIB) @LIBS@ test-twirl: TestTwirl.o $(LIB_PRODUCT) - $(PURIFY) $(QUANTIFY) $(CC) -o $@ TestTwirl.o $(NUFXLIB) @LIBS@ + $(CC) -o $@ TestTwirl.o $(NUFXLIB) @LIBS@ tags:: ctags --totals -R ../* diff --git a/nulib2/Binary2.c b/nulib2/Binary2.c index 9cd0eff..ce42592 100644 --- a/nulib2/Binary2.c +++ b/nulib2/Binary2.c @@ -1342,8 +1342,16 @@ static NuError BNYExtract(BNYArchive* pBny, BNYEntry* pEntry, *pConsumedFlag = true; bail: - if (outfp != NULL && outfp != stdout) + if (outfp != NULL && outfp != stdout) { +#if defined(MAC_LIKE) + if (SetFinderInfo(fileno(outfp), pEntry->fileType, + pEntry->auxType) != kNuErrNone) + { + fprintf(stderr, "WARNING: unable to set finder info\n"); + } +#endif fclose(outfp); + } return err; } diff --git a/nulib2/Filename.c b/nulib2/Filename.c index 51c374c..a7bf2f7 100644 --- a/nulib2/Filename.c +++ b/nulib2/Filename.c @@ -309,8 +309,10 @@ const char* NormalizePath(NulibState* pState, NuPathnameProposal* pPathProposal) AddPreservationString(pState, pPathProposal, pathBuf); } else if (NuGetThreadID(pPathProposal->pThread) == kNuThreadIDRsrcFork) { +#ifndef HAS_RESOURCE_FORKS /* add this in lieu of the preservation extension */ strcat(pathBuf, kResourceStr); +#endif } startp = NULL; /* we're done */ diff --git a/nulib2/Makefile.in b/nulib2/Makefile.in index 2c81380..e0cf9fd 100644 --- a/nulib2/Makefile.in +++ b/nulib2/Makefile.in @@ -44,15 +44,6 @@ OPT = @CFLAGS@ GCC_FLAGS = -Wall -Wwrite-strings -Wstrict-prototypes -Wpointer-arith -Wshadow CFLAGS = @BUILD_FLAGS@ -I. -I$(NUFXSRCDIR) -I$(includedir) @DEFS@ -#ifdef PURIFY_BUILD -# PURIFY = purify -# CFLAGS += -DPURIFY -#endif -#ifdef QUANTIFY_BUILD -# QUANTIFY = quantify -# CFLAGS += -DQUANTIFY -#endif - SRCS = Add.c ArcUtils.c Binary2.c Delete.c Extract.c Filename.c \ List.c Main.c MiscStuff.c MiscUtils.c State.c SysUtils.c OBJS = Add.o ArcUtils.o Binary2.o Delete.o Extract.o Filename.o \ @@ -87,16 +78,8 @@ install-shared: shared:: LIB_PRODUCT="libnufx.so" $(MAKE) -e -quantify: - -rm -f $(PRODUCT) - @$(MAKE) QUANTIFY_BUILD=1 - -purify: - -rm -f $(PRODUCT) - @$(MAKE) PURIFY_BUILD=1 - $(PRODUCT): $(OBJS) $(NUFXLIB) - $(PURIFY) $(QUANTIFY) $(CC) -o $@ $(OBJS) -L$(NUFXSRCDIR) -L$(libdir) -lnufx @LIBS@ + $(CC) -o $@ $(OBJS) -L$(NUFXSRCDIR) -L$(libdir) -lnufx @LIBS@ clean: -rm -f *.o core diff --git a/nulib2/NuLib2.h b/nulib2/NuLib2.h index 1f2cc2f..6ce6a0b 100644 --- a/nulib2/NuLib2.h +++ b/nulib2/NuLib2.h @@ -106,6 +106,7 @@ NuError NormalizeFileName(NulibState* pState, const char* srcp, long srcLen, NuError NormalizeDirectoryName(NulibState* pState, const char* srcp, long srcLen, char fssep, char** pDstp, long dstLen); char* MakeTempArchiveName(NulibState* pState); +NuError SetFinderInfo(int fd, uint8_t proType, uint16_t proAux); NuError AddFile(NulibState* pState, NuArchive* pArchive, const char* pathname); NuError Mkdir(const char* dir); diff --git a/nulib2/README.txt b/nulib2/README.txt index 794e412..af1cace 100644 --- a/nulib2/README.txt +++ b/nulib2/README.txt @@ -1,9 +1,9 @@ -NuLib2 README, updated 2014/12/23 +NuLib2 README, updated 2015/01/03 http://www.nulib.com/ To build NuLib2, you will also need a copy of NufxLib. This should have come -in the same .tar.gz file. Build the NufxLib library first. +in the same distribution file. Build the NufxLib library first. UNIX diff --git a/nulib2/SysDefs.h b/nulib2/SysDefs.h index 26bb2a0..0e32f54 100644 --- a/nulib2/SysDefs.h +++ b/nulib2/SysDefs.h @@ -174,6 +174,16 @@ # define SYSTEM_DEFAULT_EOL "\r" #endif +#if defined(__APPLE__) && defined(__MACH__) /* OS X */ +# define MAC_LIKE +# define UNIX_LIKE +#endif + +/* not currently using filesystem resource forks */ +//#if defined(__ORCAC__) || defined(MAC_LIKE) +//# define HAS_RESOURCE_FORKS +//#endif + #if defined(APW) || defined(__ORCAC__) # define __appleiigs__ # pragma lint -1 diff --git a/nulib2/SysUtils.c b/nulib2/SysUtils.c index b1e917e..7f7928f 100644 --- a/nulib2/SysUtils.c +++ b/nulib2/SysUtils.c @@ -11,6 +11,9 @@ #ifdef HAVE_WINDOWS_H # include #endif +#ifdef MAC_LIKE +# include +#endif /* get a grip on this opendir/readdir stuff */ #if defined(UNIX_LIKE) @@ -60,6 +63,7 @@ * =========================================================================== */ +// 20150103: this makes me nervous #define kTempFileNameLen 20 @@ -411,6 +415,149 @@ static void UNIXTimeToDateTime(const time_t* pWhen, NuDateTime *pDateTime) } #endif +#if defined(MAC_LIKE) +/* + * Due to historical reasons, the XATTR_FINDERINFO_NAME (defined to be + * ``com.apple.FinderInfo'') extended attribute must be 32 bytes; see the + * ATTR_CMN_FNDRINFO section in getattrlist(2). + * + * The FinderInfo block is the concatenation of a FileInfo structure + * and an ExtendedFileInfo (or ExtendedFolderInfo) structure -- see + * ATTR_CMN_FNDRINFO in getattrlist(2). + * + * All we're really interested in is the file type and creator code, + * which are stored big-endian in the first 8 bytes. + */ +static const int kFinderInfoSize = 32; + +/* + * Obtains the creator and file type from the Finder info block, if any, + * and converts the types to ProDOS equivalents. + * + * If the attribute doesn't exist, this returns an error without modifying + * the output args. + */ +static NuError GetTypesFromFinder(const char* pathnameUNI, uint32_t* pFileType, + uint32_t* pAuxType) +{ + uint8_t fiBuf[kFinderInfoSize]; + + size_t actual = getxattr(pathnameUNI, XATTR_FINDERINFO_NAME, + fiBuf, sizeof(fiBuf), 0, 0); + if (actual != kFinderInfoSize) { + return kNuErrNotFound; + } + + uint32_t fileType, creator; + fileType = (fiBuf[0] << 24) | (fiBuf[1] << 16) | (fiBuf[2] << 8) | + fiBuf[3]; + creator = (fiBuf[4] << 24) | (fiBuf[5] << 16) | (fiBuf[6] << 8) | + fiBuf[7]; + + uint8_t proType; + uint16_t proAux; + + /* + * Convert to ProDOS file/aux type. + */ + if (creator == 'pdos') { + if (fileType == 'PSYS') { + proType = 0xFF; // SYS + proAux = 0x0000; + } else if (fileType == 'PS16') { + proType = 0xB3; // S16 + proAux = 0x0000; + } else { + if (((fileType >> 24) & 0xFF) == 'p') { + proType = (fileType >> 16) & 0xFF; + proAux = (uint16_t) fileType; + } else { + proType = 0x00; // NON + proAux = 0x0000; + } + } + } else if (creator == 'dCpy') { + if (fileType == 'dImg') { + proType = 0xE0; // LBR + proAux = 0x0005; + } else { + proType = 0x00; // NON + proAux = 0x0000; + } + } else { + switch(fileType) { + case 'BINA': + proType = 0x06; // BIN + proAux = 0x0000; + break; + case 'TEXT': + proType = 0x04; // TXT + proAux = 0x0000; + break; + case 'MIDI': + proType = 0xD7; // MDI + proAux = 0x0000; + break; + case 'AIFF': + proType = 0xD8; // SND + proAux = 0x0000; + break; + case 'AIFC': + proType = 0xD8; // SND + proAux = 0x0001; + break; + default: + proType = 0x00; // NON + proAux = 0x0000; + break; + } + } + + *pFileType = proType; + *pAuxType = proAux; + return kNuErrNone; +} + +/* + * Set the file type and creator type. + */ +NuError SetFinderInfo(int fd, uint8_t proType, uint16_t proAux) +{ + uint8_t fiBuf[kFinderInfoSize]; + + size_t actual = fgetxattr(fd, XATTR_FINDERINFO_NAME, + fiBuf, sizeof(fiBuf), 0, 0); + if (actual == (size_t) -1 && errno == ENOATTR) { + // doesn't yet have Finder info + memset(fiBuf, 0, sizeof(fiBuf)); + } else if (actual != kFinderInfoSize) { + return kNuErrFile; + } + + /* build type and creator from 8-bit type and 16-bit aux type */ + uint32_t fileType, creator; + fileType = ('p' << 24) | (proType << 16) | proAux; + creator = 'pdos'; + + fiBuf[0] = fileType >> 24; + fiBuf[1] = fileType >> 16; + fiBuf[2] = fileType >> 8; + fiBuf[3] = fileType; + fiBuf[4] = creator >> 24; + fiBuf[5] = creator >> 16; + fiBuf[6] = creator >> 8; + fiBuf[7] = creator; + + if (fsetxattr(fd, XATTR_FINDERINFO_NAME, fiBuf, sizeof(fiBuf), + 0, 0) != 0) + { + return kNuErrFile; + } + + return kNuErrNone; +} +#endif /*MAC_LIKE*/ + #if defined(UNIX_LIKE) || defined(WINDOWS_LIKE) /* * Replace "oldc" with "newc". If we find an instance of "newc" already @@ -493,6 +640,15 @@ static NuError GetFileDetails(NulibState* pState, const char* pathnameMOR, UNIXTimeToDateTime(&psb->st_mtime, &pDetails->modWhen); UNIXTimeToDateTime(&psb->st_mtime, &pDetails->createWhen); +#ifdef MAC_LIKE + /* + * Retrieve the file/aux type from the Finder info. We want the + * type-preservation string to take priority, so get this first. + */ + (void) GetTypesFromFinder(livePathStr, + &pDetails->fileType, &pDetails->extraType); +#endif + /* * Check for file type preservation info in the filename. If present, * set the file type values and truncate the filename. @@ -612,8 +768,8 @@ static NuError GetFileDetails(NulibState* pState, const char* pathnameMOR, * Do the system-independent part of the file add, including things like * adding comments. */ -NuError DoAddFile(NulibState* pState, NuArchive* pArchive, const char* pathname, - const NuFileDetails* pDetails) +static NuError DoAddFile(NulibState* pState, NuArchive* pArchive, + const char* pathname, const NuFileDetails* pDetails) { NuError err; NuRecordIdx recordIdx = 0; diff --git a/nulib2/configure b/nulib2/configure index 7850f6a..ba92dc3 100755 --- a/nulib2/configure +++ b/nulib2/configure @@ -4112,12 +4112,6 @@ if test "$host_os" = "beos"; then fi fi -if test "$host_vendor" = "apple" -a ${host_os:0:6} = "darwin"; then - echo "checking for Mac OS X... yes, adding -framework Carbon" - LIBS="$LIBS -framework Carbon" -fi - - if test "$host_cpu" = "powerpc" -a "$host_os" = "beos"; then CC=cc GCC= diff --git a/nulib2/configure.in b/nulib2/configure.in index 4ca3e2f..38f13f5 100644 --- a/nulib2/configure.in +++ b/nulib2/configure.in @@ -125,13 +125,6 @@ if test "$host_os" = "beos"; then fi fi -dnl Mac OS X (powerpc-apple-darwin6.6) needs an extra flag. -if test "$host_vendor" = "apple" -a ${host_os:0:6} = "darwin"; then - echo "checking for Mac OS X... yes, adding -framework Carbon" - LIBS="$LIBS -framework Carbon" -fi - - dnl Figure out what the build and link flags should be if test "$host_cpu" = "powerpc" -a "$host_os" = "beos"; then dnl BeOS/PPC with Metrowerks compiler