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