void displayFolder(HFSCatalogNodeID folderID, Volume* volume) { CatalogRecordList* list; CatalogRecordList* theList; HFSPlusCatalogFolder* folder; HFSPlusCatalogFile* file; time_t fileTime; struct tm *date; HFSPlusDecmpfs* compressData; size_t attrSize; theList = list = getFolderContents(folderID, volume); while(list != NULL) { if(list->record->recordType == kHFSPlusFolderRecord) { folder = (HFSPlusCatalogFolder*)list->record; printf("%06o ", folder->permissions.fileMode); printf("%3d ", folder->permissions.ownerID); printf("%3d ", folder->permissions.groupID); printf("%12d ", folder->valence); fileTime = APPLE_TO_UNIX_TIME(folder->contentModDate); } else if(list->record->recordType == kHFSPlusFileRecord) { file = (HFSPlusCatalogFile*)list->record; printf("%06o ", file->permissions.fileMode); printf("%3d ", file->permissions.ownerID); printf("%3d ", file->permissions.groupID); if(file->permissions.ownerFlags & UF_COMPRESSED) { attrSize = getAttribute(volume, file->fileID, "com.apple.decmpfs", (uint8_t**)(&compressData)); flipHFSPlusDecmpfs(compressData); printf("%12" PRId64 " ", compressData->size); free(compressData); } else { printf("%12" PRId64 " ", file->dataFork.logicalSize); } fileTime = APPLE_TO_UNIX_TIME(file->contentModDate); } date = localtime(&fileTime); if(date != NULL) { printf("%2d/%2d/%4d %02d:%02d ", date->tm_mon, date->tm_mday, date->tm_year + 1900, date->tm_hour, date->tm_min); } else { printf(" "); } printUnicode(&list->name); printf("\n"); list = list->next; } releaseCatalogRecordList(theList); }
void displayFileLSLine(Volume* volume, HFSPlusCatalogFile* file, const char* name) { time_t fileTime; struct tm *date; HFSPlusDecmpfs* compressData; printf("%06o ", file->permissions.fileMode); printf("%3d ", file->permissions.ownerID); printf("%3d ", file->permissions.groupID); if(file->permissions.ownerFlags & UF_COMPRESSED) { getAttribute(volume, file->fileID, "com.apple.decmpfs", (uint8_t**)(&compressData)); flipHFSPlusDecmpfs(compressData); printf("%12" PRId64 " ", compressData->size); free(compressData); } else { printf("%12" PRId64 " ", file->dataFork.logicalSize); } fileTime = APPLE_TO_UNIX_TIME(file->contentModDate); date = localtime(&fileTime); if(date != NULL) { printf("%2d/%2d/%4d %2d:%02d ", date->tm_mon, date->tm_mday, date->tm_year + 1900, date->tm_hour, date->tm_min); } else { printf(" "); } printf("%s\n", name); XAttrList* next; XAttrList* attrs = getAllExtendedAttributes(file->fileID, volume); if(attrs != NULL) { printf("Extended attributes\n"); while(attrs != NULL) { next = attrs->next; printf("\t%s\n", attrs->name); free(attrs->name); free(attrs); attrs = next; } } }
io_func* openHFSPlusCompressed(Volume* volume, HFSPlusCatalogFile* file) { io_func* io; HFSPlusCompressed* data; uLongf actualSize; io = (io_func*) malloc(sizeof(io_func)); data = (HFSPlusCompressed*) malloc(sizeof(HFSPlusCompressed)); data->volume = volume; data->file = file; io->data = data; io->read = &compressedRead; io->write = &compressedWrite; io->close = &closeHFSPlusCompressed; data->cached = NULL; data->cachedStart = 0; data->cachedEnd = 0; data->io = NULL; data->blocks = NULL; data->dirty = FALSE; data->decmpfsSize = getAttribute(volume, file->fileID, "com.apple.decmpfs", (uint8_t**)(&data->decmpfs)); if(data->decmpfsSize == 0) { data->decmpfs = (HFSPlusDecmpfs*) malloc(0x1000); data->decmpfs->size = 0; return io; // previously not compressed file } flipHFSPlusDecmpfs(data->decmpfs); if(data->decmpfs->flags == 0x3) { data->cached = (uint8_t*) malloc(data->decmpfs->size); actualSize = data->decmpfs->size; uncompress(data->cached, &actualSize, data->decmpfs->data, data->decmpfsSize - sizeof(HFSPlusDecmpfs)); if(actualSize != data->decmpfs->size) { fprintf(stderr, "decmpfs: size mismatch\n"); } data->cachedStart = 0; data->cachedEnd = actualSize; } else { data->io = openRawFile(file->fileID, &file->resourceFork, (HFSPlusCatalogRecord*)file, volume); if(!data->io) { hfs_panic("error opening resource fork"); } if(!READ(data->io, 0, sizeof(HFSPlusCmpfRsrcHead), &data->rsrcHead)) { hfs_panic("error reading"); } flipRsrcHead(&data->rsrcHead); data->blocks = (HFSPlusCmpfRsrcBlockHead*) malloc(sizeof(HFSPlusCmpfRsrcBlockHead)); if(!READ(data->io, data->rsrcHead.headerSize, sizeof(HFSPlusCmpfRsrcBlockHead), data->blocks)) { hfs_panic("error reading"); } flipRsrcBlockHead(data->blocks); data->blocks = (HFSPlusCmpfRsrcBlockHead*) realloc(data->blocks, sizeof(HFSPlusCmpfRsrcBlockHead) + (sizeof(HFSPlusCmpfRsrcBlock) * data->blocks->numBlocks)); if(!READ(data->io, data->rsrcHead.headerSize + sizeof(HFSPlusCmpfRsrcBlockHead), sizeof(HFSPlusCmpfRsrcBlock) * data->blocks->numBlocks, data->blocks->blocks)) { hfs_panic("error reading"); } int i; for(i = 0; i < data->blocks->numBlocks; i++) { flipRsrcBlock(&data->blocks->blocks[i]); } } return io; }
static void closeHFSPlusCompressed(io_func* io) { HFSPlusCompressed* data = (HFSPlusCompressed*) io->data; if(data->io) CLOSE(data->io); if(data->dirty) { int oldSize = data->decmpfsSize; if(data->blocks) free(data->blocks); data->decmpfs->magic = CMPFS_MAGIC; data->decmpfs->flags = 0x4; data->decmpfsSize = sizeof(HFSPlusDecmpfs); uint32_t numBlocks = (data->decmpfs->size + 0xFFFF) / 0x10000; uint32_t blocksSize = sizeof(HFSPlusCmpfRsrcBlockHead) + (numBlocks * sizeof(HFSPlusCmpfRsrcBlock)); data->blocks = (HFSPlusCmpfRsrcBlockHead*) malloc(sizeof(HFSPlusCmpfRsrcBlockHead) + (numBlocks * sizeof(HFSPlusCmpfRsrcBlock))); data->blocks->numBlocks = numBlocks; data->blocks->dataSize = blocksSize - sizeof(uint32_t); // without the front dataSize in BlockHead. data->rsrcHead.headerSize = 0x100; data->rsrcHead.dataSize = blocksSize; data->rsrcHead.totalSize = data->rsrcHead.headerSize + data->rsrcHead.dataSize; data->rsrcHead.flags = 0x32; uint8_t* buffer = (uint8_t*) malloc((0x10000 * 1.1) + 12); uint32_t curFileOffset = data->blocks->dataSize; uint32_t i; for(i = 0; i < numBlocks; i++) { data->blocks->blocks[i].offset = curFileOffset; uLongf actualSize = (0x10000 * 1.1) + 12; compress(buffer, &actualSize, data->cached + (0x10000 * i), (data->decmpfs->size - (0x10000 * i)) > 0x10000 ? 0x10000 : (data->decmpfs->size - (0x10000 * i))); data->blocks->blocks[i].size = actualSize; // check if we can fit the whole thing into an inline extended attribute // a little fudge factor here since sizeof(HFSPlusAttrKey) is bigger than it ought to be, since only 127 characters are strictly allowed if(numBlocks <= 1 && (actualSize + sizeof(HFSPlusDecmpfs) + sizeof(HFSPlusAttrKey)) <= 0x1000) { int newSize = (sizeof(HFSPlusDecmpfs) + actualSize + 1) & ~1; if (oldSize < newSize) { printf("growing "); data->decmpfs = realloc(data->decmpfs, newSize); memset(data->decmpfs->data + actualSize, 0, newSize - actualSize - sizeof(HFSPlusDecmpfs)); } data->decmpfs->flags = 0x3; memcpy(data->decmpfs->data, buffer, actualSize); data->decmpfsSize = newSize; printf("inline data\n"); break; } else { if(i == 0) { data->io = openRawFile(data->file->fileID, &data->file->resourceFork, (HFSPlusCatalogRecord*)data->file, data->volume); if(!data->io) { hfs_panic("error opening resource fork"); } } WRITE(data->io, data->rsrcHead.headerSize + sizeof(uint32_t) + data->blocks->blocks[i].offset, data->blocks->blocks[i].size, buffer); curFileOffset += data->blocks->blocks[i].size; data->blocks->dataSize += data->blocks->blocks[i].size; data->rsrcHead.dataSize += data->blocks->blocks[i].size; data->rsrcHead.totalSize += data->blocks->blocks[i].size; } } free(buffer); if(data->decmpfs->flags == 0x4) { flipRsrcHead(&data->rsrcHead); WRITE(data->io, 0, sizeof(HFSPlusCmpfRsrcHead), &data->rsrcHead); flipRsrcHead(&data->rsrcHead); for(i = 0; i < data->blocks->numBlocks; i++) { flipRsrcBlock(&data->blocks->blocks[i]); } flipRsrcBlockHead(data->blocks); WRITE(data->io, data->rsrcHead.headerSize, blocksSize, data->blocks); flipRsrcBlockHead(data->blocks); for(i = 0; i < data->blocks->numBlocks; i++) { flipRsrcBlock(&data->blocks->blocks[i]); } HFSPlusCmpfEnd end; memset(&end, 0, sizeof(HFSPlusCmpfEnd)); end.unk1 = 0x1C; end.unk2 = 0x32; end.unk3 = 0x0; end.magic = CMPFS_MAGIC; end.flags = 0xA; end.size = 0xFFFF01; end.unk4 = 0x0; flipHFSPlusCmpfEnd(&end); WRITE(data->io, data->rsrcHead.totalSize, sizeof(HFSPlusCmpfEnd), &end); flipHFSPlusCmpfEnd(&end); CLOSE(data->io); } flipHFSPlusDecmpfs(data->decmpfs); setAttribute(data->volume, data->file->fileID, "com.apple.decmpfs", (uint8_t*)(data->decmpfs), data->decmpfsSize); flipHFSPlusDecmpfs(data->decmpfs); } if(data->cached) free(data->cached); if(data->blocks) free(data->blocks); free(data->decmpfs); free(data); free(io); }