initial code for dumping imessages in a reasonable format
This commit is contained in:
502
dump-imessages/iphone-dataprotection/emf_decrypter/hfs/rawfile.c
Normal file
502
dump-imessages/iphone-dataprotection/emf_decrypter/hfs/rawfile.c
Normal file
@@ -0,0 +1,502 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <hfs/hfsplus.h>
|
||||
|
||||
int writeExtents(RawFile* rawFile);
|
||||
|
||||
int isBlockUsed(Volume* volume, uint32_t block)
|
||||
{
|
||||
unsigned char byte;
|
||||
|
||||
READ(volume->allocationFile, block / 8, 1, &byte);
|
||||
return (byte & (1 << (7 - (block % 8)))) != 0;
|
||||
}
|
||||
|
||||
int setBlockUsed(Volume* volume, uint32_t block, int used) {
|
||||
unsigned char byte;
|
||||
|
||||
READ(volume->allocationFile, block / 8, 1, &byte);
|
||||
if(used) {
|
||||
byte |= (1 << (7 - (block % 8)));
|
||||
} else {
|
||||
byte &= ~(1 << (7 - (block % 8)));
|
||||
}
|
||||
ASSERT(WRITE(volume->allocationFile, block / 8, 1, &byte), "WRITE");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int allocate(RawFile* rawFile, off_t size) {
|
||||
unsigned char* zeros;
|
||||
Volume* volume;
|
||||
HFSPlusForkData* forkData;
|
||||
uint32_t blocksNeeded;
|
||||
uint32_t blocksToAllocate;
|
||||
Extent* extent;
|
||||
Extent* lastExtent;
|
||||
|
||||
uint32_t curBlock;
|
||||
|
||||
volume = rawFile->volume;
|
||||
forkData = rawFile->forkData;
|
||||
extent = rawFile->extents;
|
||||
|
||||
blocksNeeded = ((uint64_t)size / (uint64_t)volume->volumeHeader->blockSize) + (((size % volume->volumeHeader->blockSize) == 0) ? 0 : 1);
|
||||
|
||||
if(blocksNeeded > forkData->totalBlocks) {
|
||||
zeros = (unsigned char*) malloc(volume->volumeHeader->blockSize);
|
||||
memset(zeros, 0, volume->volumeHeader->blockSize);
|
||||
|
||||
blocksToAllocate = blocksNeeded - forkData->totalBlocks;
|
||||
|
||||
if(blocksToAllocate > volume->volumeHeader->freeBlocks) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
lastExtent = NULL;
|
||||
while(extent != NULL) {
|
||||
lastExtent = extent;
|
||||
extent = extent->next;
|
||||
}
|
||||
|
||||
if(lastExtent == NULL) {
|
||||
rawFile->extents = (Extent*) malloc(sizeof(Extent));
|
||||
lastExtent = rawFile->extents;
|
||||
lastExtent->blockCount = 0;
|
||||
lastExtent->next = NULL;
|
||||
curBlock = volume->volumeHeader->nextAllocation;
|
||||
} else {
|
||||
curBlock = lastExtent->startBlock + lastExtent->blockCount;
|
||||
}
|
||||
|
||||
while(blocksToAllocate > 0) {
|
||||
if(isBlockUsed(volume, curBlock)) {
|
||||
if(lastExtent->blockCount > 0) {
|
||||
lastExtent->next = (Extent*) malloc(sizeof(Extent));
|
||||
lastExtent = lastExtent->next;
|
||||
lastExtent->blockCount = 0;
|
||||
lastExtent->next = NULL;
|
||||
}
|
||||
curBlock = volume->volumeHeader->nextAllocation;
|
||||
volume->volumeHeader->nextAllocation++;
|
||||
if(volume->volumeHeader->nextAllocation >= volume->volumeHeader->totalBlocks) {
|
||||
volume->volumeHeader->nextAllocation = 0;
|
||||
}
|
||||
} else {
|
||||
if(lastExtent->blockCount == 0) {
|
||||
lastExtent->startBlock = curBlock;
|
||||
}
|
||||
|
||||
/* zero out allocated block */
|
||||
ASSERT(WRITE(volume->image, curBlock * volume->volumeHeader->blockSize, volume->volumeHeader->blockSize, zeros), "WRITE");
|
||||
|
||||
setBlockUsed(volume, curBlock, TRUE);
|
||||
volume->volumeHeader->freeBlocks--;
|
||||
blocksToAllocate--;
|
||||
curBlock++;
|
||||
lastExtent->blockCount++;
|
||||
|
||||
if(curBlock >= volume->volumeHeader->totalBlocks) {
|
||||
curBlock = volume->volumeHeader->nextAllocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(zeros);
|
||||
} else if(blocksNeeded < forkData->totalBlocks) {
|
||||
blocksToAllocate = blocksNeeded;
|
||||
|
||||
lastExtent = NULL;
|
||||
|
||||
while(blocksToAllocate > 0) {
|
||||
if(blocksToAllocate > extent->blockCount) {
|
||||
blocksToAllocate -= extent->blockCount;
|
||||
lastExtent = extent;
|
||||
extent = extent->next;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(blocksToAllocate == 0 && lastExtent != NULL) {
|
||||
// snip the extent list here, since we don't need the rest
|
||||
lastExtent->next = NULL;
|
||||
} else if(blocksNeeded == 0) {
|
||||
rawFile->extents = NULL;
|
||||
}
|
||||
|
||||
do {
|
||||
for(curBlock = (extent->startBlock + blocksToAllocate); curBlock < (extent->startBlock + extent->blockCount); curBlock++) {
|
||||
setBlockUsed(volume, curBlock, FALSE);
|
||||
volume->volumeHeader->freeBlocks++;
|
||||
}
|
||||
lastExtent = extent;
|
||||
extent = extent->next;
|
||||
|
||||
if(blocksToAllocate == 0)
|
||||
{
|
||||
free(lastExtent);
|
||||
} else {
|
||||
lastExtent->next = NULL;
|
||||
lastExtent->blockCount = blocksToAllocate;
|
||||
}
|
||||
|
||||
blocksToAllocate = 0;
|
||||
} while(extent != NULL);
|
||||
}
|
||||
|
||||
writeExtents(rawFile);
|
||||
|
||||
forkData->logicalSize = size;
|
||||
forkData->totalBlocks = blocksNeeded;
|
||||
|
||||
updateVolume(rawFile->volume);
|
||||
|
||||
if(rawFile->catalogRecord != NULL) {
|
||||
updateCatalog(rawFile->volume, rawFile->catalogRecord);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int rawFileRead(io_func* io,off_t location, size_t size, void *buffer) {
|
||||
RawFile* rawFile;
|
||||
Volume* volume;
|
||||
Extent* extent;
|
||||
|
||||
size_t blockSize;
|
||||
off_t fileLoc;
|
||||
off_t locationInBlock;
|
||||
size_t possible;
|
||||
|
||||
rawFile = (RawFile*) io->data;
|
||||
volume = rawFile->volume;
|
||||
blockSize = volume->volumeHeader->blockSize;
|
||||
|
||||
if(!rawFile->extents)
|
||||
return FALSE;
|
||||
|
||||
extent = rawFile->extents;
|
||||
fileLoc = 0;
|
||||
|
||||
locationInBlock = location;
|
||||
while(TRUE) {
|
||||
fileLoc += extent->blockCount * blockSize;
|
||||
if(fileLoc <= location) {
|
||||
locationInBlock -= extent->blockCount * blockSize;
|
||||
extent = extent->next;
|
||||
if(extent == NULL)
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while(size > 0) {
|
||||
if(extent == NULL)
|
||||
return FALSE;
|
||||
|
||||
possible = extent->blockCount * blockSize - locationInBlock;
|
||||
|
||||
if(size > possible) {
|
||||
ASSERT(READ(volume->image, extent->startBlock * blockSize + locationInBlock, possible, buffer), "READ");
|
||||
size -= possible;
|
||||
buffer = (void*)(((size_t)buffer) + possible);
|
||||
extent = extent->next;
|
||||
} else {
|
||||
ASSERT(READ(volume->image, extent->startBlock * blockSize + locationInBlock, size, buffer), "READ");
|
||||
break;
|
||||
}
|
||||
|
||||
locationInBlock = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int rawFileWrite(io_func* io,off_t location, size_t size, void *buffer) {
|
||||
RawFile* rawFile;
|
||||
Volume* volume;
|
||||
Extent* extent;
|
||||
|
||||
size_t blockSize;
|
||||
off_t fileLoc;
|
||||
off_t locationInBlock;
|
||||
size_t possible;
|
||||
|
||||
rawFile = (RawFile*) io->data;
|
||||
volume = rawFile->volume;
|
||||
blockSize = volume->volumeHeader->blockSize;
|
||||
|
||||
if(rawFile->forkData->logicalSize < (location + size)) {
|
||||
ASSERT(allocate(rawFile, location + size), "allocate");
|
||||
}
|
||||
|
||||
extent = rawFile->extents;
|
||||
fileLoc = 0;
|
||||
|
||||
locationInBlock = location;
|
||||
while(TRUE) {
|
||||
fileLoc += extent->blockCount * blockSize;
|
||||
if(fileLoc <= location) {
|
||||
locationInBlock -= extent->blockCount * blockSize;
|
||||
extent = extent->next;
|
||||
if(extent == NULL)
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while(size > 0) {
|
||||
if(extent == NULL)
|
||||
return FALSE;
|
||||
|
||||
possible = extent->blockCount * blockSize - locationInBlock;
|
||||
|
||||
if(size > possible) {
|
||||
ASSERT(WRITE(volume->image, extent->startBlock * blockSize + locationInBlock, possible, buffer), "WRITE");
|
||||
size -= possible;
|
||||
buffer = (void*)(((size_t)buffer) + possible);
|
||||
extent = extent->next;
|
||||
} else {
|
||||
ASSERT(WRITE(volume->image, extent->startBlock * blockSize + locationInBlock, size, buffer), "WRITE");
|
||||
break;
|
||||
}
|
||||
|
||||
locationInBlock = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void closeRawFile(io_func* io) {
|
||||
RawFile* rawFile;
|
||||
Extent* extent;
|
||||
Extent* toRemove;
|
||||
|
||||
rawFile = (RawFile*) io->data;
|
||||
extent = rawFile->extents;
|
||||
|
||||
while(extent != NULL) {
|
||||
toRemove = extent;
|
||||
extent = extent->next;
|
||||
free(toRemove);
|
||||
}
|
||||
|
||||
free(rawFile);
|
||||
free(io);
|
||||
}
|
||||
|
||||
int removeExtents(RawFile* rawFile) {
|
||||
uint32_t blocksLeft;
|
||||
HFSPlusForkData* forkData;
|
||||
uint32_t currentBlock;
|
||||
|
||||
uint32_t startBlock;
|
||||
uint32_t blockCount;
|
||||
|
||||
HFSPlusExtentDescriptor* descriptor;
|
||||
int currentExtent;
|
||||
HFSPlusExtentKey extentKey;
|
||||
int exact;
|
||||
|
||||
extentKey.keyLength = sizeof(HFSPlusExtentKey) - sizeof(extentKey.keyLength);
|
||||
extentKey.forkType = 0;
|
||||
extentKey.fileID = rawFile->id;
|
||||
|
||||
forkData = rawFile->forkData;
|
||||
blocksLeft = forkData->totalBlocks;
|
||||
currentExtent = 0;
|
||||
currentBlock = 0;
|
||||
descriptor = (HFSPlusExtentDescriptor*) forkData->extents;
|
||||
|
||||
while(blocksLeft > 0) {
|
||||
if(currentExtent == 8) {
|
||||
if(rawFile->volume->extentsTree == NULL) {
|
||||
hfs_panic("no extents overflow file loaded yet!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(descriptor != ((HFSPlusExtentDescriptor*) forkData->extents)) {
|
||||
free(descriptor);
|
||||
}
|
||||
|
||||
extentKey.startBlock = currentBlock;
|
||||
descriptor = (HFSPlusExtentDescriptor*) search(rawFile->volume->extentsTree, (BTKey*)(&extentKey), &exact, NULL, NULL);
|
||||
if(descriptor == NULL || exact == FALSE) {
|
||||
hfs_panic("inconsistent extents information!");
|
||||
return FALSE;
|
||||
} else {
|
||||
removeFromBTree(rawFile->volume->extentsTree, (BTKey*)(&extentKey));
|
||||
currentExtent = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
startBlock = descriptor[currentExtent].startBlock;
|
||||
blockCount = descriptor[currentExtent].blockCount;
|
||||
|
||||
currentBlock += blockCount;
|
||||
blocksLeft -= blockCount;
|
||||
currentExtent++;
|
||||
}
|
||||
|
||||
if(descriptor != ((HFSPlusExtentDescriptor*) forkData->extents)) {
|
||||
free(descriptor);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int writeExtents(RawFile* rawFile) {
|
||||
Extent* extent;
|
||||
int currentExtent;
|
||||
HFSPlusExtentKey extentKey;
|
||||
HFSPlusExtentDescriptor descriptor[8];
|
||||
HFSPlusForkData* forkData;
|
||||
|
||||
removeExtents(rawFile);
|
||||
|
||||
forkData = rawFile->forkData;
|
||||
currentExtent = 0;
|
||||
extent = rawFile->extents;
|
||||
|
||||
memset(forkData->extents, 0, sizeof(HFSPlusExtentRecord));
|
||||
while(extent != NULL && currentExtent < 8) {
|
||||
((HFSPlusExtentDescriptor*)forkData->extents)[currentExtent].startBlock = extent->startBlock;
|
||||
((HFSPlusExtentDescriptor*)forkData->extents)[currentExtent].blockCount = extent->blockCount;
|
||||
extent = extent->next;
|
||||
currentExtent++;
|
||||
}
|
||||
|
||||
if(extent != NULL) {
|
||||
extentKey.keyLength = sizeof(HFSPlusExtentKey) - sizeof(extentKey.keyLength);
|
||||
extentKey.forkType = 0;
|
||||
extentKey.fileID = rawFile->id;
|
||||
|
||||
currentExtent = 0;
|
||||
|
||||
while(extent != NULL) {
|
||||
if(currentExtent == 0) {
|
||||
memset(descriptor, 0, sizeof(HFSPlusExtentRecord));
|
||||
}
|
||||
|
||||
if(currentExtent == 8) {
|
||||
extentKey.startBlock = descriptor[0].startBlock;
|
||||
addToBTree(rawFile->volume->extentsTree, (BTKey*)(&extentKey), sizeof(HFSPlusExtentRecord), (unsigned char *)(&(descriptor[0])));
|
||||
currentExtent = 0;
|
||||
}
|
||||
|
||||
descriptor[currentExtent].startBlock = extent->startBlock;
|
||||
descriptor[currentExtent].blockCount = extent->blockCount;
|
||||
|
||||
currentExtent++;
|
||||
extent = extent->next;
|
||||
}
|
||||
|
||||
extentKey.startBlock = descriptor[0].startBlock;
|
||||
addToBTree(rawFile->volume->extentsTree, (BTKey*)(&extentKey), sizeof(HFSPlusExtentRecord), (unsigned char *)(&(descriptor[0])));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int readExtents(RawFile* rawFile) {
|
||||
uint32_t blocksLeft;
|
||||
HFSPlusForkData* forkData;
|
||||
uint32_t currentBlock;
|
||||
|
||||
Extent* extent;
|
||||
Extent* lastExtent;
|
||||
|
||||
HFSPlusExtentDescriptor* descriptor;
|
||||
int currentExtent;
|
||||
HFSPlusExtentKey extentKey;
|
||||
int exact;
|
||||
|
||||
extentKey.keyLength = sizeof(HFSPlusExtentKey) - sizeof(extentKey.keyLength);
|
||||
extentKey.forkType = 0;
|
||||
extentKey.fileID = rawFile->id;
|
||||
|
||||
forkData = rawFile->forkData;
|
||||
blocksLeft = forkData->totalBlocks;
|
||||
currentExtent = 0;
|
||||
currentBlock = 0;
|
||||
descriptor = (HFSPlusExtentDescriptor*) forkData->extents;
|
||||
|
||||
lastExtent = NULL;
|
||||
|
||||
while(blocksLeft > 0) {
|
||||
extent = (Extent*) malloc(sizeof(Extent));
|
||||
|
||||
if(currentExtent == 8) {
|
||||
if(rawFile->volume->extentsTree == NULL) {
|
||||
hfs_panic("no extents overflow file loaded yet!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(descriptor != ((HFSPlusExtentDescriptor*) forkData->extents)) {
|
||||
free(descriptor);
|
||||
}
|
||||
|
||||
extentKey.startBlock = currentBlock;
|
||||
descriptor = (HFSPlusExtentDescriptor*) search(rawFile->volume->extentsTree, (BTKey*)(&extentKey), &exact, NULL, NULL);
|
||||
if(descriptor == NULL || exact == FALSE) {
|
||||
hfs_panic("inconsistent extents information!");
|
||||
return FALSE;
|
||||
} else {
|
||||
currentExtent = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
extent->startBlock = descriptor[currentExtent].startBlock;
|
||||
extent->blockCount = descriptor[currentExtent].blockCount;
|
||||
extent->next = NULL;
|
||||
|
||||
currentBlock += extent->blockCount;
|
||||
blocksLeft -= extent->blockCount;
|
||||
currentExtent++;
|
||||
|
||||
if(lastExtent == NULL) {
|
||||
rawFile->extents = extent;
|
||||
} else {
|
||||
lastExtent->next = extent;
|
||||
}
|
||||
|
||||
lastExtent = extent;
|
||||
}
|
||||
|
||||
if(descriptor != ((HFSPlusExtentDescriptor*) forkData->extents)) {
|
||||
free(descriptor);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
io_func* openRawFile(HFSCatalogNodeID id, HFSPlusForkData* forkData, HFSPlusCatalogRecord* catalogRecord, Volume* volume) {
|
||||
io_func* io;
|
||||
RawFile* rawFile;
|
||||
|
||||
io = (io_func*) malloc(sizeof(io_func));
|
||||
rawFile = (RawFile*) malloc(sizeof(RawFile));
|
||||
|
||||
rawFile->id = id;
|
||||
rawFile->volume = volume;
|
||||
rawFile->forkData = forkData;
|
||||
rawFile->catalogRecord = catalogRecord;
|
||||
rawFile->extents = NULL;
|
||||
|
||||
io->data = rawFile;
|
||||
io->read = &rawFileRead;
|
||||
io->write = &rawFileWrite;
|
||||
io->close = &closeRawFile;
|
||||
|
||||
if(!readExtents(rawFile)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return io;
|
||||
}
|
||||
Reference in New Issue
Block a user