in hfs/rawfile.c [29:161]
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;
}