diff --git a/src/apps/bin/makeudfimage/Allocator.cpp b/src/apps/bin/makeudfimage/Allocator.cpp new file mode 100644 index 0000000000..9121bba240 --- /dev/null +++ b/src/apps/bin/makeudfimage/Allocator.cpp @@ -0,0 +1,217 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net +//---------------------------------------------------------------------- + +/*! \file Allocator.cpp + + Physical block allocator class implementation. +*/ + +#include "Allocator.h" + +#include + +#include "Utils.h" + +/*! \brief Creates a new Allocator object. +*/ +Allocator::Allocator(uint32 blockSize) + : fLength(0) + , fBlockSize(blockSize) + , fBlockShift(0) + , fInitStatus(B_NO_INIT) +{ + status_t error = Udf::get_block_shift(BlockSize(), fBlockShift); + if (!error) + fInitStatus = B_OK; +} + +status_t +Allocator::InitCheck() const +{ + return fInitStatus; +} + +/*! \brief Allocates the given block, if available. + + \return + - B_OK: Success. + - error code: Failure, the block has already been allocated. +*/ +status_t +Allocator::GetBlock(uint32 block) +{ + Udf::extent_address extent(block, BlockSize()); + return GetExtent(extent); +} + +/*! \brief Allocates the given extent, if available. + + \return + - B_OK: Success. + - error code: Failure, the extent (or some portion of it) has already + been allocated. +*/ +status_t +Allocator::GetExtent(Udf::extent_address extent) +{ + status_t error = InitCheck(); + if (!error) { + uint32 offset = extent.location(); + uint32 length = BlocksFor(extent.length()); + // First see if the extent is past the allocation tail, + // since we then don't have to do any chunklist traversal + if (offset >= Length()) { + // Add a new chunk to the end of the chunk list if + // necessary + if (offset > Length()) { + Udf::extent_address chunk(Length(), (offset-Length())<::iterator i = fChunkList.begin(); + i != fChunkList.end(); + i++) + { + uint32 chunkOffset = i->location(); + uint32 chunkLength = BlocksFor(i->length()); + if (chunkOffset <= offset && (offset+length) <= (chunkOffset+chunkLength)) { + // Found it. Split the chunk. First look for an orphan + // before the block, then after. + if (chunkOffset < offset) { + // Orhpan before; add a new chunk in front + // of the current one + Udf::extent_address chunk(chunkOffset, (offset-chunkOffset)<set_location(offset+length); + i->set_length(((chunkOffset+chunkLength)-(offset+length))<::iterator i = fChunkList.begin(); + i != fChunkList.end(); + i++) + { + uint32 chunkOffset = i->location(); + uint32 chunkLength = BlocksFor(i->length()); + if (length <= chunkLength) { + // Chunk is larger than necessary. Allocate first + // length blocks, and resize the chunk appropriately. + extent.set_location(chunkOffset); + extent.set_length(_length); + if (length != chunkLength) { + i->set_location(chunkOffset+length); + i->set_length((chunkLength-length)< maxLength) { + if (contiguous) + error = B_DEVICE_FULL; + else { + isPartial = true; + length = maxLength; + } + } + if (!error) { + extent.set_location(Length()); + extent.set_length(isPartial ? length< + +#include "UdfStructures.h" + +/*! \brief This class keeps track of allocated and unallocated + blocks in the range of 0 to 2^32. + + By default, all blocks are unallocated. +*/ +class Allocator { +public: + Allocator(uint32 blockSize); + status_t InitCheck() const; + + status_t GetBlock(uint32 block); + status_t GetExtent(Udf::extent_address extent); + + status_t GetNextBlock(uint32 &block); + status_t GetNextExtent(uint32 length, bool contiguous, + Udf::extent_address &extent); + + uint32 Length() const { return fLength; } + uint32 BlockSize() const { return fBlockSize; } + uint32 BlockShift() const { return fBlockShift; } + + uint32 BlocksFor(uint32 bytes); +private: + list fChunkList; + uint32 fLength; //!< Length of allocation so far, in blocks. + uint32 fBlockSize; + uint32 fBlockShift; + status_t fInitStatus; +}; + +#endif // _ALLOCATOR_H