static void extractOne()

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, &times);
	} 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, &times);
			} else {
				printf("WARNING: cannot fopen %s\n", name);
			}
		} else {
			printf("unsupported: %s\n", name);
		}
	}
}