in hfs/hfscompress.c [114:222]
static void closeHFSPlusCompressed(io_func* io) {
HFSPlusCompressed* data = (HFSPlusCompressed*) io->data;
if(data->io)
CLOSE(data->io);
if(data->dirty) {
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) {
data->decmpfs->flags = 0x3;
memcpy(data->decmpfs->data, buffer, actualSize);
data->decmpfsSize = sizeof(HFSPlusDecmpfs) + actualSize;
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);
}