in hfs/hfslib.c [419:502]
static void extractOne(HFSCatalogNodeID folderID, char* name, HFSPlusCatalogRecord* record, Volume* volume, char* cwd) {
HFSPlusCatalogFolder* folder;
HFSPlusCatalogFile* file;
AbstractFile* outFile;
struct stat status;
uint16_t fileType;
size_t size;
char* linkTarget;
#ifdef WIN32
HFSPlusCatalogRecord* targetRecord;
#endif
struct utimbuf times;
if(strncmp(name, ".HFS+ Private Directory Data", sizeof(".HFS+ Private Directory Data") - 1) == 0 || name[0] == '\0') {
return;
}
if(record->recordType == kHFSPlusFolderRecord) {
folder = (HFSPlusCatalogFolder*)record;
printf("folder: %s\n", name);
if(stat(name, &status) != 0) {
ASSERT(mkdir(name, 0755) == 0, "mkdir");
}
ASSERT(chdir(name) == 0, "chdir");
extractAllInFolder(folder->folderID, volume);
// TODO: chown . now that contents are extracted
ASSERT(chdir(cwd) == 0, "chdir");
chmod(name, folder->permissions.fileMode & 07777);
times.actime = APPLE_TO_UNIX_TIME(folder->accessDate);
times.modtime = APPLE_TO_UNIX_TIME(folder->contentModDate);
utime(name, ×);
} else if(record->recordType == kHFSPlusFileRecord) {
file = (HFSPlusCatalogFile*)record;
fileType = file->permissions.fileMode & S_IFMT;
if(fileType == S_IFLNK) {
// Symlinks are stored as a file with the symlink target in the file's data fork.
// We read the target into a data buffer, then pass that filename to symlink().
printf("symlink: %s\n", name);
size = file->dataFork.logicalSize;
if (size > 1024) {
printf("WARNING: symlink target for %s longer than PATH_MAX? Skipping.\n", name);
} else {
// symlink(3) needs a null terminator, which the file contents do not include
linkTarget = (char*)malloc(size + 1);
outFile = createAbstractFileFromMemory((void**)(&linkTarget), size);
// write target from volume into linkTarget
writeToFile(file, outFile, volume);
linkTarget[size] = 0; // null terminator
outFile->close(outFile);
#ifndef WIN32
symlink(linkTarget, name);
#else
// create copies instead of symlinks on Windows
targetRecord = getRecordFromPath3(linkTarget, volume, NULL, NULL, TRUE, TRUE, folderID);
if (targetRecord != NULL) {
extractOne(folderID, name, targetRecord, volume, cwd);
}
#endif
free(linkTarget);
}
} else if(fileType == S_IFREG) {
printf("file: %s\n", name);
outFile = createAbstractFileFromFile(fopen(name, "wb"));
if(outFile != NULL) {
writeToFile(file, outFile, volume);
// TODO: fchown to replicate ownership
#ifndef WIN32
fchmod(fileno((FILE*)outFile->data), file->permissions.fileMode & 07777);
#endif
outFile->close(outFile);
#ifdef WIN32
chmod(name, file->permissions.fileMode & 07777);
#endif
times.actime = APPLE_TO_UNIX_TIME(file->accessDate);
times.modtime = APPLE_TO_UNIX_TIME(file->contentModDate);
utime(name, ×);
} else {
printf("WARNING: cannot fopen %s\n", name);
}
} else {
printf("unsupported: %s\n", name);
}
}
}