// _ReadIndirectItem status_t StreamReader::_ReadIndirectItem(off_t offset, void *buffer, size_t bufferSize) { //PRINT(("StreamReader::_ReadIndirectItem(%Ld, %p, %lu)\n", offset, buffer, bufferSize)); status_t error = B_OK; IndirectItem &indirect = *static_cast<IndirectItem*>(&fItem); // skip items until the offset is reached uint32 skipItems = 0; if (offset > 0) { skipItems = uint32(offset / fBlockSize); skipItems = min(skipItems, indirect.CountBlocks()); // not necessary } //PRINT((" skipItems: %lu\n", skipItems)); for (uint32 i = skipItems; error == B_OK && bufferSize > 0 && i < indirect.CountBlocks(); i++) { //PRINT((" child %lu\n", i)); // get the block Block *block = NULL; error = GetTree()->GetBlock(indirect.BlockNumberAt(i), &block); if (error == B_OK) { // copy the data into the buffer off_t blockOffset = i * (off_t)fBlockSize; uint32 localOffset = max(0LL, offset - blockOffset); uint32 toRead = min(fBlockSize - localOffset, bufferSize); memcpy(buffer, (uint8*)block->GetData() + localOffset, toRead); block->Put(); bufferSize -= toRead; buffer = (uint8*)buffer + toRead; } else { FATAL(("failed to get block %Lu\n", indirect.BlockNumberAt(i))); error = B_IO_ERROR; } } //PRINT(("StreamReader::_ReadIndirectItem() done: %s\n", strerror(error))) return error; }
// ResizeBlock Block * BlockAllocator::Area::ResizeBlock(Block *block, size_t newUsableSize, bool dontDefragment) { //PRINT(("Area::ResizeBlock(%p, %lu)\n", block, newUsableSize)); // newUsableSize must be >0 ! if (newUsableSize == 0) return NULL; Block *resultBlock = NULL; if (block) { size_t size = block->GetSize(); size_t newSize = max(newUsableSize + sizeof(BlockHeader), kMinBlockSize); newSize = block_align_ceil(newSize); if (newSize == size) { // size doesn't change: nothing to do resultBlock = block; } else if (newSize < size) { // shrink the block size_t sizeDiff = size - newSize; Block *nextBlock = block->GetNextBlock(); if (nextBlock && nextBlock->IsFree()) { // join the space with the adjoining free block TFreeBlock *freeBlock = nextBlock->ToFreeBlock(); _MoveResizeFreeBlock(freeBlock, -sizeDiff, freeBlock->GetSize() + sizeDiff); // resize the block and we're done block->SetSize(newSize, true); fFreeBytes += sizeDiff; } else if (sizeDiff >= sizeof(TFreeBlock)) { // the freed space is large enough for a free block TFreeBlock *newFree = _MakeFreeBlock(block, newSize, block, sizeDiff, nextBlock, NULL, NULL); _InsertFreeBlock(newFree); block->SetSize(newSize, true); if (fFreeBlockCount == 1) fFreeBytes += newFree->GetUsableSize(); else fFreeBytes += newFree->GetSize(); if (!dontDefragment && _DefragmentingRecommended()) _Defragment(); } // else: insufficient space for a free block: no changes resultBlock = block; } else { //PRINT((" grow...\n")); // grow the block size_t sizeDiff = newSize - size; Block *nextBlock = block->GetNextBlock(); if (nextBlock && nextBlock->IsFree() && nextBlock->GetSize() >= sizeDiff) { //PRINT((" adjoining free block\n")); // there is a adjoining free block and it is large enough TFreeBlock *freeBlock = nextBlock->ToFreeBlock(); size_t freeSize = freeBlock->GetSize(); if (freeSize - sizeDiff >= sizeof(TFreeBlock)) { // the remaining space is still large enough for a free // block _MoveResizeFreeBlock(freeBlock, sizeDiff, freeSize - sizeDiff); block->SetSize(newSize, true); fFreeBytes -= sizeDiff; } else { // the remaining free space wouldn't be large enough for // a free block: consume the free block completely Block *freeNext = freeBlock->GetNextBlock(); _RemoveFreeBlock(freeBlock); block->SetSize(size + freeSize, freeNext); _FixBlockList(block, block->GetPreviousBlock(), freeNext); if (fFreeBlockCount == 0) fFreeBytes = 0; else fFreeBytes -= freeSize; } resultBlock = block; } else { //PRINT((" no adjoining free block\n")); // no (large enough) adjoining free block: allocate // a new block and copy the data to it BlockReference *reference = block->GetReference(); resultBlock = AllocateBlock(newUsableSize, dontDefragment); block = reference->GetBlock(); if (resultBlock) { resultBlock->SetReference(reference); memcpy(resultBlock->GetData(), block->GetData(), block->GetUsableSize()); FreeBlock(block, dontDefragment); resultBlock = reference->GetBlock(); } } } } D(SanityCheck()); //PRINT(("Area::ResizeBlock() done: %p\n", resultBlock)); return resultBlock; }