From 9787066de44984da01fafd7cb2cc0c0740e387a2 Mon Sep 17 00:00:00 2001 From: Tyler Dauwalder Date: Thu, 31 Jul 2003 06:55:35 +0000 Subject: [PATCH] Initial checkin. Manages access to the different types of allocation descriptors supported. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4151 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../udf/AllocationDescriptorList.h | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 src/add-ons/kernel/file_systems/udf/AllocationDescriptorList.h diff --git a/src/add-ons/kernel/file_systems/udf/AllocationDescriptorList.h b/src/add-ons/kernel/file_systems/udf/AllocationDescriptorList.h new file mode 100644 index 0000000000..184a4718ab --- /dev/null +++ b/src/add-ons/kernel/file_systems/udf/AllocationDescriptorList.h @@ -0,0 +1,261 @@ +//---------------------------------------------------------------------- +// This software is part of the OpenBeOS distribution and is covered +// by the OpenBeOS license. +// +// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net +//--------------------------------------------------------------------- +#ifndef _UDF_ALLOCATION_DESCRIPTOR_LIST_H +#define _UDF_ALLOCATION_DESCRIPTOR_LIST_H + +/*! \file AllocationDescriptorList.h +*/ + +#include "cpp.h" +#include "UdfDebug.h" + +#include "DiskStructures.h" +#include "Icb.h" +#include "Volume.h" + +namespace Udf { + +/*! \brief Common interface for dealing with the three standard + forms of allocation descriptors used in UDF icbs. + + The \c Accessor class is an allocation descriptor accessor class + for the allocation scheme of interest. Instances of it should be + passable by value, and should define the following public members: + - typedef DescriptorType; + - inline uint8 GetType(DescriptorType &descriptor); + - inline uint32 GetBlock(DescriptorType &descriptor); + - inline uint16 GetPartition(DescriptorType &descriptor); + - inline uint32 GetLength(DescriptorType &descriptor); +*/ +template +class AllocationDescriptorList { +private: + typedef typename Accessor::DescriptorType Descriptor; +public: + AllocationDescriptorList(Icb *icb, Accessor accessor = Accessor()) + : fIcb(icb) + , fVolume(icb->GetVolume()) + , fIcbDescriptors(reinterpret_cast(icb->AllocationDescriptors())) + , fIcbDescriptorsSize(icb->AllocationDescriptorsSize()) + , fAdditionalDescriptors(icb->GetVolume()) + , fReadFromIcb(true) + , fAccessor(accessor) + , fDescriptorIndex(0) + , fDescriptorNumber(0) + , fBlockIndex(0) + { + DEBUG_INIT(CF_PUBLIC | CF_FILE_OPS | CF_HIGH_VOLUME, "AllocationDescriptorList<>"); + _WalkContinuationChain(_CurrentDescriptor()); + } + + /*! \brief Finds the extent for the given address in the stream, + returning it in the address pointed to by \a blockRun. + + \param start The byte address of interest + \param extent The extent containing the stream address given + by \c start. + \param isEmpty If set to true, indicates that the given extent is unrecorded + and thus its contents should be interpreted as all zeros. + */ + status_t FindExtent(off_t start, udf_long_address *extent, bool *isEmpty) { + DEBUG_INIT_ETC(CF_PUBLIC | CF_FILE_OPS | CF_HIGH_VOLUME, "AllocationDescriptorList<>", + ("start: %lld, extent: %p, isEmpty: %p", start, extent, isEmpty)); + off_t startBlock = start >> fVolume->BlockShift(); + + // This should never have to happen, as FindExtent is only called by + // Icb::_Read() sequentially as a file read is performed, but you + // never know. :-) + if (startBlock < _BlockIndex()) + _Rewind(); + + status_t err = B_OK; + while (true) { + Descriptor *descriptor = _CurrentDescriptor(); + if (descriptor) { + if (_BlockIndex() <= startBlock + && startBlock < _BlockIndex()+fAccessor.GetLength(*descriptor)) + { + // The start block is somewhere in this extent, so return + // the applicable tail end portion. + off_t offset = startBlock - _BlockIndex(); + extent->set_block(fAccessor.GetBlock(*descriptor)+offset); + extent->set_partition(fAccessor.GetPartition(*descriptor)); + extent->set_length(fAccessor.GetLength(*descriptor)-(offset*fVolume->BlockSize())); + extent->set_type(fAccessor.GetType(*descriptor)); + break; + } else { + _MoveToNextDescriptor(); + } + } else { + PRINT(("Descriptor #%ld found NULL\n", _DescriptorNumber())); + err = B_ERROR; + break; + } + } + RETURN(err); + } + +private: + + Descriptor* _CurrentDescriptor() const { + DEBUG_INIT(CF_PUBLIC | CF_FILE_OPS | CF_HIGH_VOLUME, "AllocationDescriptorList<>"); + PRINT(("(_DescriptorIndex()+1)*sizeof(Descriptor) = %ld\n", (_DescriptorIndex()+1)*sizeof(Descriptor))); + PRINT(("_DescriptorArraySize() = %ld\n", _DescriptorArraySize())); + PRINT(("_DescriptorArray() = %p\n", _DescriptorArray())); + return ((_DescriptorIndex()+1)*sizeof(Descriptor) <= _DescriptorArraySize()) + ? &(_DescriptorArray()[_DescriptorIndex()]) + : NULL; + } + + status_t _MoveToNextDescriptor() { + DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "AllocationDescriptorList<>"); + + Descriptor* descriptor = _CurrentDescriptor(); + if (!descriptor) { + RETURN(B_ENTRY_NOT_FOUND); + } else { + // Increment our indices and get the next descriptor + // from this extent. + fBlockIndex += fAccessor.GetLength(*descriptor); + fDescriptorIndex++; + fDescriptorNumber++; + descriptor = _CurrentDescriptor(); + + // If no such descriptor exists, we've run out of + // descriptors in this extent, and we're done. The + // next time _CurrentDescriptor() is called, it will + // return NULL, signifying this. Otherwise, we have to + // see if the new descriptor identifies the next extent + // of allocation descriptors, in which case we have to + // load up the appropriate extent (guaranteed to be at + // most one block in length by UDF-2.01 5.1 and UDF-2.01 + // 2.3.11). + _WalkContinuationChain(descriptor); + } + + + RETURN(B_ERROR); + } + + void _WalkContinuationChain(Descriptor *descriptor) { + DEBUG_INIT_ETC(CF_PUBLIC | CF_FILE_OPS | CF_HIGH_VOLUME, "AllocationDescriptorList<>", + ("descriptor: %p", descriptor)); + if (descriptor && fAccessor.GetType(*descriptor) == EXTENT_TYPE_CONTINUATION) { + // Load the new block, make sure we're not trying + // to read from the icb descriptors anymore, and + // reset the descriptor index. + fAdditionalDescriptors.SetTo(fAccessor, *descriptor); + fReadFromIcb = false; + fDescriptorIndex = 0; + + // Make sure that the first descriptor in this extent isn't + // another continuation. That would be stupid, but not + // technically illegal. + _WalkContinuationChain(_CurrentDescriptor()); + + } + + + } + + void _Rewind() { + fDescriptorIndex = 0; + fDescriptorNumber = 0; + fReadFromIcb = true; + } + + Descriptor *_DescriptorArray() const { + return fReadFromIcb + ? fIcbDescriptors + : reinterpret_cast(fAdditionalDescriptors.Block()); + } + + size_t _DescriptorArraySize() const { + return fReadFromIcb ? fIcbDescriptorsSize : fAdditionalDescriptors.BlockSize(); + } + + int32 _DescriptorIndex() const { + return fDescriptorIndex; + } + + int32 _DescriptorNumber() const { + return fDescriptorNumber; + } + + off_t _BlockIndex() const { + return fBlockIndex; + } + + Icb *fIcb; + Volume *fVolume; + Descriptor *fIcbDescriptors; + int32 fIcbDescriptorsSize; + CachedBlock fAdditionalDescriptors; + bool fReadFromIcb; + + Accessor fAccessor; + int32 fDescriptorIndex; + int32 fDescriptorNumber; + off_t fBlockIndex; + +}; + +// Accessors + +class ShortDescriptorAccessor { +public: + ShortDescriptorAccessor(uint16 partition) + : fPartition(partition) + { + } + + typedef udf_short_address DescriptorType; + + inline uint8 GetType(DescriptorType &descriptor) const { + return descriptor.type(); + } + + inline uint32 GetBlock(DescriptorType &descriptor) const { + return descriptor.block(); + } + + inline uint16 GetPartition(DescriptorType &descriptor) const { + return fPartition; + } + + inline uint32 GetLength(DescriptorType &descriptor) const { + return descriptor.length(); + } +private: + uint16 fPartition; +}; + +class LongDescriptorAccessor { +public: + typedef udf_long_address DescriptorType; + + inline uint8 GetType(DescriptorType &descriptor) const { + return descriptor.type(); + } + + inline uint32 GetBlock(DescriptorType &descriptor) const { + return descriptor.block(); + } + + inline uint16 GetPartition(DescriptorType &descriptor) const { + return descriptor.partition(); + } + + inline uint32 GetLength(DescriptorType &descriptor) const { + return descriptor.length(); + } +}; + + +}; // namespace Udf + +#endif // _UDF_ALLOCATION_DESCRIPTOR_LIST_H