From 087989661c4172c238712db27da5972273579923 Mon Sep 17 00:00:00 2001 From: Ryan Schmidt Date: Tue, 20 Sep 2022 23:51:10 -0500 Subject: [PATCH] MiniVMac.cc: Fix alias creation code * Convert all field values from host order to big-endian so they aren't byte-swapped when created on little-endian systems. * Pack the struct so the compiler doesn't insert padding on 64-bit systems. * Fix the volume and file creation timestamps by converting them from UNIX to Macintosh time base, using a function copied from hfsutils. * Pad volume and file names with null bytes instead of random memory. * Add the "end of variable-length data" marker so the OS doesn't crash when trying to resolve the alias. * Set the alias flag so the OS treats the file as an alias. --- LaunchAPPL/Client/MiniVMac.cc | 123 +++++++++++++++++++++++++++------- 1 file changed, 97 insertions(+), 26 deletions(-) diff --git a/LaunchAPPL/Client/MiniVMac.cc b/LaunchAPPL/Client/MiniVMac.cc index 199e658fb0..695de1809a 100644 --- a/LaunchAPPL/Client/MiniVMac.cc +++ b/LaunchAPPL/Client/MiniVMac.cc @@ -6,6 +6,11 @@ extern "C" { #include "hfs.h" +#include +#define HAVE_MKTIME +#ifdef HAVE_MKTIME +#include +#endif } #include @@ -29,39 +34,100 @@ namespace fs = boost::filesystem; /* Adapted from http://sebastien.kirche.free.fr/python_stuff/MacOS-aliases.txt */ typedef struct { - int16_t type; /* type of data */ - int16_t size; /* length of variable length data */ + uint16_t type; /* type of data */ + uint16_t size; /* length of variable-length data */ char data[]; /* actual data */ } VarData; +#pragma pack(push,1) typedef struct { /* Type Code: alis */ char userType[4] = {0, 0, 0, 0}; /* for application use, can be zeros */ - uint16_t size; /* alias record size, including variable length data */ - int16_t version = 2; /* alias version, current 2 */ - int16_t type = 0; /* file = 0, directory = 1 */ - char volumeNameSize; - char volumeName[27]; /* volume name */ + uint16_t size; /* alias record size, including variable-length data */ + int16_t version = htons(2); /* alias version, current 2 */ + int16_t type = htons(0); /* file = 0, directory = 1 */ + char volumeNameSize; /* length of volume name */ + char volumeName[27]; /* volume name padded with null bytes */ uint32_t volumeCreationDate; /* volume creation date, seconds since 1904 */ - uint16_t volumeSig = 0x4244; /*BD*/ /* volume signature MFS = RW, HFS = BD */ - int16_t volumeType = 5; /* [HD] = 0, Foreign = 1, Floppy: 400K, 800K, 1400K = 2-4, OtherEjectable = 5 */ + uint16_t volumeSig = htons(0x4244); /* volume signature MFS = RW, HFS = BD */ + int16_t volumeType = htons(5); /* [HD] = 0, Foreign = 1, Floppy: 400K, 800K, 1400K = 2-4, OtherEjectable = 5 */ int32_t parentDirID; /* parent directory ID, 0 for relative searches */ - char fileNameSize; - char fileName[63]; /* file or directory name */ + char fileNameSize; /* length of file or directory name */ + char fileName[63]; /* file or directory name padded with null bytes */ int32_t fileNum; /* file number or directory ID */ uint32_t fileCreationDate; /* file or directory creation date, seconds since 1904 */ char typeCode[4]; /* file type */ char creatorCode[4]; /* file's creator */ - int16_t nlvlFrom = 0; /* next level up from alias, used in relative searches */ - int16_t nlvlTo = 0; /* next level down to target, ditto */ - uint32_t volumeAttr = 0; /* various flags (locked, ejectable), see link above */ - int16_t volumeFSID = 0; /* file system ID for the volume, 0 for MFS, HFS */ - int16_t unused = 0; - uint32_t unused1 = 0; - uint32_t unused2 = 0; - VarData vdata[]; /* variable length data, see link above */ + int16_t nlvlFrom = htons(0); /* next level up from alias, used in relative searches */ + int16_t nlvlTo = htons(0); /* next level down to target, ditto */ + uint32_t volumeAttr = htonl(0); /* various flags (locked, ejectable), see link above */ + int16_t volumeFSID = htons(0); /* file system ID for the volume, 0 for MFS, HFS */ + int16_t unused = htons(0); + uint32_t unused1 = htonl(0); + uint32_t unused2 = htonl(0); + VarData vdata[1] = { /* variable-length data, see link above */ + {htons(0xFFFF), htons(0)} /* end of variable-length data marker, length 0 */ + }; } AliasData; +#pragma pack(pop) + + +/* Begin code copied from libhfs/data.c */ + +# define TIMEDIFF 2082844800UL + +static +time_t tzdiff = -1; + +/* + * NAME: calctzdiff() + * DESCRIPTION: calculate the timezone difference between local time and UTC + */ +static +void calctzdiff(void) +{ +# ifdef HAVE_MKTIME + + time_t t; + int isdst; + struct tm tm; + const struct tm *tmp; + + time(&t); + isdst = localtime(&t)->tm_isdst; + + tmp = gmtime(&t); + if (tmp) + { + tm = *tmp; + tm.tm_isdst = isdst; + + tzdiff = t - mktime(&tm); + } + else + tzdiff = 0; + +# else + + tzdiff = 0; + +# endif +} + +/* + * NAME: data->mtime() + * DESCRIPTION: convert local time to MacOS time + */ +unsigned long d_mtime(time_t ltime) +{ + if (tzdiff == -1) + calctzdiff(); + + return (unsigned long) (ltime + tzdiff) + TIMEDIFF; +} + +/* End code copied from libhfs/data.c */ class MiniVMacLauncher : public Launcher @@ -399,15 +465,17 @@ void MiniVMacLauncher::MakeAlias(const std::string& dest, const std::string& src hfs_vstat(vol, &vent); AliasData alias; - alias.size = sizeof(AliasData); - memcpy(&(alias.volumeName), vent.name, 27); + alias.size = htons(sizeof(AliasData)); alias.volumeNameSize = strlen(vent.name); - alias.volumeCreationDate = vent.crdate; - alias.parentDirID = ent.parid; - memcpy(&(alias.fileName), ent.name, 63); + memcpy(&(alias.volumeName), vent.name, alias.volumeNameSize); + memset(&(alias.volumeName[0]) + alias.volumeNameSize, 0, 27 - alias.volumeNameSize); + alias.volumeCreationDate = htonl(d_mtime(vent.crdate)); + alias.parentDirID = htonl(ent.parid); alias.fileNameSize = strlen(ent.name); - alias.fileNum = ent.cnid; - alias.fileCreationDate = ent.crdate; + memcpy(&(alias.fileName), ent.name, alias.fileNameSize); + memset(&(alias.fileName[0]) + alias.fileNameSize, 0, 63 - alias.fileNameSize); + alias.fileNum = htonl(ent.cnid); + alias.fileCreationDate = htonl(d_mtime(ent.crdate)); memcpy(&(alias.typeCode), ent.u.file.type, 4); memcpy(&(alias.creatorCode), ent.u.file.creator, 4); @@ -420,6 +488,9 @@ void MiniVMacLauncher::MakeAlias(const std::string& dest, const std::string& src hfsfile *falias = hfs_create(vol, dest.c_str(), "adrp", ent.u.file.creator); hfs_setfork(falias, 1); hfs_write(falias, ralias.data(), ralias.size()); + hfs_fstat(falias, &ent); + ent.fdflags |= HFS_FNDR_ISALIAS; + hfs_fsetattr(falias, &ent); hfs_close(falias); }