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
This commit is contained in:
@@ -0,0 +1,261 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#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 Accessor>
|
||||||
|
class AllocationDescriptorList {
|
||||||
|
private:
|
||||||
|
typedef typename Accessor::DescriptorType Descriptor;
|
||||||
|
public:
|
||||||
|
AllocationDescriptorList(Icb *icb, Accessor accessor = Accessor())
|
||||||
|
: fIcb(icb)
|
||||||
|
, fVolume(icb->GetVolume())
|
||||||
|
, fIcbDescriptors(reinterpret_cast<Descriptor*>(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<Descriptor*>(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
|
||||||
Reference in New Issue
Block a user