copied udf R5 version to tests
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18732 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 "kernel_cpp.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
#include "UdfStructures.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("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, long_address *extent, bool *isEmpty) {
|
||||||
|
DEBUG_INIT_ETC("AllocationDescriptorList<>",
|
||||||
|
("start: %Ld, 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 error = 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()));
|
||||||
|
error = B_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Descriptor* _CurrentDescriptor() const {
|
||||||
|
DEBUG_INIT("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("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("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 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 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
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _UDF_ARRAY_H
|
||||||
|
#define _UDF_ARRAY_H
|
||||||
|
|
||||||
|
#include "kernel_cpp.h"
|
||||||
|
|
||||||
|
#include "SupportDefs.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
/*! \brief Slightly more typesafe static array type than built-in arrays,
|
||||||
|
with array length information stored implicitly (i.e. consuming no
|
||||||
|
physical space in the actual struct) via the \c arrayLength template
|
||||||
|
parameter.
|
||||||
|
*/
|
||||||
|
template<typename DataType, uint32 arrayLength>
|
||||||
|
struct array {
|
||||||
|
public:
|
||||||
|
void dump() const {
|
||||||
|
for (uint32 i = 0; i < arrayLength; i++)
|
||||||
|
data[i].print();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 length() const { return arrayLength; }
|
||||||
|
uint32 size() const { return arrayLength * sizeof(DataType); }
|
||||||
|
|
||||||
|
// This doesn't appear to work. I don't know why.
|
||||||
|
DataType operator[] (int index) const { return data[index]; }
|
||||||
|
|
||||||
|
DataType data[arrayLength];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief \c uint8 specialization of the \c array template struct.
|
||||||
|
*/
|
||||||
|
template<uint32 arrayLength>
|
||||||
|
struct array<uint8, arrayLength> {
|
||||||
|
void dump() const
|
||||||
|
{
|
||||||
|
const uint8 bytesPerRow = 8;
|
||||||
|
char classname[40];
|
||||||
|
sprintf(classname, "array<uint8, %ld>", arrayLength);
|
||||||
|
|
||||||
|
DUMP_INIT(classname);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < arrayLength; i++) {
|
||||||
|
if (i % bytesPerRow == 0)
|
||||||
|
PRINT(("[%ld:%ld]: ", i, i+bytesPerRow-1));
|
||||||
|
SIMPLE_PRINT(("0x%.2x ", data[i]));
|
||||||
|
if ((i+1) % bytesPerRow == 0 || i+1 == arrayLength)
|
||||||
|
SIMPLE_PRINT(("\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32 length() const { return arrayLength; }
|
||||||
|
uint32 size() const { return arrayLength; }
|
||||||
|
uint8 data[arrayLength];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief \c char specialization of the \c array template struct.
|
||||||
|
*/
|
||||||
|
template<uint32 arrayLength>
|
||||||
|
struct array<char, arrayLength> {
|
||||||
|
void dump() const
|
||||||
|
{
|
||||||
|
const uint8 bytesPerRow = 8;
|
||||||
|
char classname[40];
|
||||||
|
sprintf(classname, "array<uint8, %ld>", arrayLength);
|
||||||
|
|
||||||
|
DUMP_INIT(classname);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < arrayLength; i++) {
|
||||||
|
if (i % bytesPerRow == 0)
|
||||||
|
PRINT(("[%ld:%ld]: ", i, i+bytesPerRow-1));
|
||||||
|
SIMPLE_PRINT(("0x%.2x ", data[i]));
|
||||||
|
if ((i+1) % bytesPerRow == 0 || i+1 == arrayLength)
|
||||||
|
SIMPLE_PRINT(("\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32 length() const { return arrayLength; }
|
||||||
|
uint32 size() const { return arrayLength; }
|
||||||
|
uint8 data[arrayLength];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}; // namespace UDF
|
||||||
|
|
||||||
|
#endif // _UDF_ARRAY_H
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
// Based on the CachedBlock class from OpenBFS,
|
||||||
|
// Copyright (c) 2002 Axel Dörfler, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_CACHED_BLOCK_H
|
||||||
|
#define _UDF_CACHED_BLOCK_H
|
||||||
|
|
||||||
|
/*! \file CachedBlock.h
|
||||||
|
|
||||||
|
Based on the CachedBlock class from OpenBFS, written by
|
||||||
|
Axel Dörfler, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include "fsproto.h"
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#ifndef _IMPEXP_KERNEL
|
||||||
|
# define _IMPEXP_KERNEL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "lock.h"
|
||||||
|
#include "cache.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "kernel_cpp.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
#include "UdfStructures.h"
|
||||||
|
#include "Volume.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
class CachedBlock {
|
||||||
|
public:
|
||||||
|
CachedBlock(Volume *volume);
|
||||||
|
CachedBlock(Volume *volume, off_t block, bool empty = false);
|
||||||
|
CachedBlock(CachedBlock *cached);
|
||||||
|
~CachedBlock();
|
||||||
|
|
||||||
|
inline void Keep();
|
||||||
|
inline void Unset();
|
||||||
|
inline uint8 *SetTo(off_t block, bool empty = false);
|
||||||
|
inline uint8 *SetTo(long_address address, bool empty = false);
|
||||||
|
template <class Accessor, class Descriptor>
|
||||||
|
inline uint8* SetTo(Accessor &accessor, Descriptor &descriptor,
|
||||||
|
bool empty = false);
|
||||||
|
|
||||||
|
uint8 *Block() const { return fBlock; }
|
||||||
|
off_t BlockNumber() const { return fBlockNumber; }
|
||||||
|
uint32 BlockSize() const { return fVolume->BlockSize(); }
|
||||||
|
uint32 BlockShift() const { return fVolume->BlockShift(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
CachedBlock(const CachedBlock &); // unimplemented
|
||||||
|
CachedBlock &operator=(const CachedBlock &); // unimplemented
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Volume *fVolume;
|
||||||
|
off_t fBlockNumber;
|
||||||
|
uint8 *fBlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
CachedBlock::CachedBlock(Volume *volume)
|
||||||
|
:
|
||||||
|
fVolume(volume),
|
||||||
|
fBlock(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
CachedBlock::CachedBlock(Volume *volume, off_t block, bool empty = false)
|
||||||
|
:
|
||||||
|
fVolume(volume),
|
||||||
|
fBlock(NULL)
|
||||||
|
{
|
||||||
|
SetTo(block, empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
CachedBlock::CachedBlock(CachedBlock *cached)
|
||||||
|
: fVolume(cached->fVolume)
|
||||||
|
, fBlockNumber(cached->BlockNumber())
|
||||||
|
, fBlock(cached->fBlock)
|
||||||
|
{
|
||||||
|
cached->Keep();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
CachedBlock::~CachedBlock()
|
||||||
|
{
|
||||||
|
Unset();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
CachedBlock::Keep()
|
||||||
|
{
|
||||||
|
fBlock = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
CachedBlock::Unset()
|
||||||
|
{
|
||||||
|
DEBUG_INIT("CachedBlock");
|
||||||
|
if (fBlock) {
|
||||||
|
PRINT(("releasing block #%Ld\n", BlockNumber()));
|
||||||
|
release_block(fVolume->Device(), fBlockNumber);
|
||||||
|
} else {
|
||||||
|
PRINT(("no block to release\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8 *
|
||||||
|
CachedBlock::SetTo(off_t block, bool empty = false)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("CachedBlock", ("block: %Ld, empty: %s",
|
||||||
|
block, (empty ? "true" : "false")));
|
||||||
|
Unset();
|
||||||
|
fBlockNumber = block;
|
||||||
|
PRINT(("getting block #%Ld\n", block));
|
||||||
|
return fBlock = empty ? (uint8 *)get_empty_block(fVolume->Device(), block, BlockSize())
|
||||||
|
: (uint8 *)get_block(fVolume->Device(), block, BlockSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint8 *
|
||||||
|
CachedBlock::SetTo(long_address address, bool empty = false)
|
||||||
|
{
|
||||||
|
off_t block;
|
||||||
|
if (fVolume->MapBlock(address, &block) == B_OK)
|
||||||
|
return SetTo(block, empty);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Accessor, class Descriptor>
|
||||||
|
inline uint8*
|
||||||
|
CachedBlock::SetTo(Accessor &accessor, Descriptor &descriptor, bool empty = false)
|
||||||
|
{
|
||||||
|
// Make a long_address out of the descriptor and call it a day
|
||||||
|
long_address address;
|
||||||
|
address.set_to(accessor.GetBlock(descriptor),
|
||||||
|
accessor.GetPartition(descriptor));
|
||||||
|
return SetTo(address, empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_CACHED_BLOCK_H
|
||||||
|
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
#include "DString.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
/*! \brief Creates a useless, empty string object.
|
||||||
|
*/
|
||||||
|
DString::DString()
|
||||||
|
: fString(NULL)
|
||||||
|
, fLength(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Create a new DString object that is a copy of \a ref.
|
||||||
|
*/
|
||||||
|
DString::DString(const DString &ref)
|
||||||
|
: fString(NULL)
|
||||||
|
, fLength(0)
|
||||||
|
{
|
||||||
|
SetTo(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Creates a new DString \a fieldLength bytes long that contains
|
||||||
|
at most the first \c (fieldLength-1) bytes of \a string.Cs0().
|
||||||
|
*/
|
||||||
|
DString::DString(const Udf::String &string, uint8 fieldLength)
|
||||||
|
: fString(NULL)
|
||||||
|
, fLength(0)
|
||||||
|
{
|
||||||
|
SetTo(string, fieldLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Creates a new DString \a fieldLength bytes long that contains
|
||||||
|
at most the first \c (fieldLength-1) bytes of the Cs0 representation
|
||||||
|
of the NULL-terminated UTF8 string \a utf8.
|
||||||
|
*/
|
||||||
|
DString::DString(const char *utf8, uint8 fieldLength)
|
||||||
|
: fString(NULL)
|
||||||
|
, fLength(0)
|
||||||
|
{
|
||||||
|
SetTo(utf8, fieldLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DString::SetTo(const DString &ref)
|
||||||
|
{
|
||||||
|
_Clear();
|
||||||
|
if (ref.Length() > 0) {
|
||||||
|
fString = new(nothrow) uint8[ref.Length()];
|
||||||
|
if (fString) {
|
||||||
|
fLength = ref.Length();
|
||||||
|
memcpy(fString, ref.String(), fLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Sets the DString be \a fieldLength bytes long and contain
|
||||||
|
at most the first \c (fieldLength-1) bytes of \a string.Cs0().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
DString::SetTo(const Udf::String &string, uint8 fieldLength)
|
||||||
|
{
|
||||||
|
_Clear();
|
||||||
|
if (fieldLength > 0) {
|
||||||
|
// Allocate our string
|
||||||
|
fString = new(nothrow) uint8[fieldLength];
|
||||||
|
status_t error = fString ? B_OK : B_NO_MEMORY;
|
||||||
|
if (!error) {
|
||||||
|
// Figure out how many bytes to copy
|
||||||
|
uint32 sourceLength = string.Cs0Length();
|
||||||
|
if (sourceLength > 0) {
|
||||||
|
uint8 destLength = sourceLength > uint8(fieldLength-1)
|
||||||
|
? uint8(fieldLength-1)
|
||||||
|
: uint8(sourceLength);
|
||||||
|
// If the source string is 16-bit unicode, make sure any dangling
|
||||||
|
// half-character at the end of the string is not copied
|
||||||
|
if (string.Cs0()[1] == '\x10' && destLength > 0 && destLength % 2 == 0)
|
||||||
|
destLength--;
|
||||||
|
// Copy
|
||||||
|
memcpy(fString, string.Cs0(), destLength);
|
||||||
|
// Zero any characters between the end of the string and
|
||||||
|
// the terminating string length character
|
||||||
|
if (destLength < fieldLength-1)
|
||||||
|
memset(&fString[destLength], 0, fieldLength-1-destLength);
|
||||||
|
// Write the string length to the last character in the field
|
||||||
|
fString[fieldLength-1] = destLength;
|
||||||
|
} else {
|
||||||
|
// Empty strings are to contain all zeros
|
||||||
|
memset(fString, 0, fieldLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Sets the DString be \a fieldLength bytes long and contain
|
||||||
|
at most the first \c (fieldLength-1) bytes of the Cs0 representation
|
||||||
|
of the NULL-terminated UTF8 string \a utf8.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
DString::SetTo(const char *utf8, uint8 fieldLength)
|
||||||
|
{
|
||||||
|
Udf::String string(utf8);
|
||||||
|
SetTo(string, fieldLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DString::_Clear()
|
||||||
|
{
|
||||||
|
DEBUG_INIT("DString");
|
||||||
|
delete [] fString;
|
||||||
|
fString = NULL;
|
||||||
|
fLength = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _D_STRING_H
|
||||||
|
#define _D_STRING_H
|
||||||
|
|
||||||
|
#include "kernel_cpp.h"
|
||||||
|
#include "UdfString.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
/*! \brief Fixed-length d-string class that takes a Udf::String as input
|
||||||
|
and provides a properly formatted ECMA-167 d-string of the given
|
||||||
|
field length as ouput.
|
||||||
|
|
||||||
|
For d-string info, see: ECMA-167 1/7.2.12, UDF-2.50 2.1.3
|
||||||
|
*/
|
||||||
|
class DString {
|
||||||
|
public:
|
||||||
|
DString();
|
||||||
|
DString(const DString &ref);
|
||||||
|
DString(const Udf::String &string, uint8 fieldLength);
|
||||||
|
DString(const char *utf8, uint8 fieldLength);
|
||||||
|
|
||||||
|
void SetTo(const DString &ref);
|
||||||
|
void SetTo(const Udf::String &string, uint8 fieldLength);
|
||||||
|
void SetTo(const char *utf8, uint8 fieldLength);
|
||||||
|
|
||||||
|
const uint8* String() const { return fString; }
|
||||||
|
uint8 Length() const { return fLength; }
|
||||||
|
private:
|
||||||
|
void _Clear();
|
||||||
|
|
||||||
|
uint8 *fString;
|
||||||
|
uint8 fLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace UDF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _D_STRING_H
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*! \file DirectoryIterator.cpp
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DirectoryIterator.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "Icb.h"
|
||||||
|
|
||||||
|
#include "UdfString.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DirectoryIterator::GetNextEntry(char *name, uint32 *length, vnode_id *id)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("DirectoryIterator",
|
||||||
|
("name: %p, length: %p, id: %p", name, length, id));
|
||||||
|
|
||||||
|
if (!id || !name || !length)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
PRINT(("fPosition: %Ld\n", fPosition));
|
||||||
|
PRINT(("Parent()->Length(): %Ld\n", Parent()->Length()));
|
||||||
|
|
||||||
|
|
||||||
|
status_t error = B_OK;
|
||||||
|
if (fAtBeginning) {
|
||||||
|
sprintf(name, ".");
|
||||||
|
*length = 2;
|
||||||
|
*id = Parent()->Id();
|
||||||
|
fAtBeginning = false;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (uint64(fPosition) >= Parent()->Length())
|
||||||
|
RETURN(B_ENTRY_NOT_FOUND);
|
||||||
|
|
||||||
|
uint8 data[kMaxFileIdSize];
|
||||||
|
file_id_descriptor *entry = reinterpret_cast<file_id_descriptor*>(data);
|
||||||
|
|
||||||
|
uint32 block = 0;
|
||||||
|
off_t offset = fPosition;
|
||||||
|
|
||||||
|
size_t entryLength = kMaxFileIdSize;
|
||||||
|
// First read in the static portion of the file id descriptor,
|
||||||
|
// then, based on the information therein, read in the variable
|
||||||
|
// length tail portion as well.
|
||||||
|
error = Parent()->Read(offset, entry, &entryLength, &block);
|
||||||
|
if (!error && entryLength >= sizeof(file_id_descriptor) && entry->tag().init_check(block) == B_OK) {
|
||||||
|
PDUMP(entry);
|
||||||
|
offset += entry->total_length();
|
||||||
|
|
||||||
|
if (entry->is_parent()) {
|
||||||
|
sprintf(name, "..");
|
||||||
|
*length = 3;
|
||||||
|
} else {
|
||||||
|
String string(entry->id(), entry->id_length());
|
||||||
|
PRINT(("id == `%s'\n", string.Utf8()));
|
||||||
|
DUMP(entry->icb());
|
||||||
|
sprintf(name, "%s", string.Utf8());
|
||||||
|
*length = string.Utf8Length();
|
||||||
|
}
|
||||||
|
*id = to_vnode_id(entry->icb());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
fPosition = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* \brief Rewinds the iterator to point to the first
|
||||||
|
entry in the directory.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
DirectoryIterator::Rewind()
|
||||||
|
{
|
||||||
|
fPosition = 0;
|
||||||
|
fAtBeginning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::DirectoryIterator(Icb *parent)
|
||||||
|
: fParent(parent)
|
||||||
|
, fPosition(0)
|
||||||
|
, fAtBeginning(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DirectoryIterator::Invalidate()
|
||||||
|
{
|
||||||
|
fParent = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_DIRECTORY_ITERATOR_H
|
||||||
|
#define _UDF_DIRECTORY_ITERATOR_H
|
||||||
|
|
||||||
|
/*! \file DirectoryIterator.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IMPEXP_KERNEL
|
||||||
|
# define _IMPEXP_KERNEL
|
||||||
|
#endif
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include "fsproto.h"
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "kernel_cpp.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
class Icb;
|
||||||
|
|
||||||
|
class DirectoryIterator {
|
||||||
|
public:
|
||||||
|
|
||||||
|
status_t GetNextEntry(char *name, uint32 *length, vnode_id *id);
|
||||||
|
void Rewind();
|
||||||
|
|
||||||
|
Icb* Parent() { return fParent; }
|
||||||
|
const Icb* Parent() const { return fParent; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class Icb;
|
||||||
|
|
||||||
|
DirectoryIterator(); // unimplemented
|
||||||
|
DirectoryIterator(Icb *parent); // called by Icb::GetDirectoryIterator()
|
||||||
|
void Invalidate(); // called by Icb::~Icb()
|
||||||
|
|
||||||
|
Icb *fParent;
|
||||||
|
off_t fPosition;
|
||||||
|
bool fAtBeginning;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_DIRECTORY_ITERATOR_H
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#include "Icb.h"
|
||||||
|
|
||||||
|
#include "time.h"
|
||||||
|
|
||||||
|
#include "AllocationDescriptorList.h"
|
||||||
|
#include "DirectoryIterator.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "Volume.h"
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
Icb::Icb(Volume *volume, long_address address)
|
||||||
|
: fVolume(volume)
|
||||||
|
, fData(volume)
|
||||||
|
, fInitStatus(B_NO_INIT)
|
||||||
|
, fId(to_vnode_id(address))
|
||||||
|
, fFileEntry(&fData)
|
||||||
|
, fExtendedEntry(&fData)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("Icb", ("volume: %p, address(block: %ld, "
|
||||||
|
"partition: %d, length: %ld)", volume, address.block(),
|
||||||
|
address.partition(), address.length()));
|
||||||
|
status_t error = volume ? B_OK : B_BAD_VALUE;
|
||||||
|
if (!error) {
|
||||||
|
off_t block;
|
||||||
|
error = fVolume->MapBlock(address, &block);
|
||||||
|
if (!error) {
|
||||||
|
icb_header *header = reinterpret_cast<icb_header*>(fData.SetTo(block));
|
||||||
|
if (header->tag().id() == TAGID_FILE_ENTRY) {
|
||||||
|
file_icb_entry *entry = reinterpret_cast<file_icb_entry*>(header);
|
||||||
|
PDUMP(entry);
|
||||||
|
(void)entry; // warning death
|
||||||
|
} else if (header->tag().id() == TAGID_EXTENDED_FILE_ENTRY) {
|
||||||
|
extended_file_icb_entry *entry = reinterpret_cast<extended_file_icb_entry*>(header);
|
||||||
|
PDUMP(entry);
|
||||||
|
(void)entry; // warning death
|
||||||
|
} else {
|
||||||
|
PDUMP(header);
|
||||||
|
}
|
||||||
|
error = header->tag().init_check(address.block());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fInitStatus = error;
|
||||||
|
PRINT(("result: 0x%lx, `%s'\n", error, strerror(error)));
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Icb::InitCheck()
|
||||||
|
{
|
||||||
|
return fInitStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t
|
||||||
|
Icb::AccessTime()
|
||||||
|
{
|
||||||
|
return make_time(FileEntry()->access_date_and_time());
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t
|
||||||
|
Icb::ModificationTime()
|
||||||
|
{
|
||||||
|
return make_time(FileEntry()->modification_date_and_time());
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Icb::Read(off_t pos, void *buffer, size_t *length, uint32 *block)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("Icb",
|
||||||
|
("pos: %Ld, buffer: %p, length: (%p)->%ld", pos, buffer, length, (length ? *length : 0)));
|
||||||
|
|
||||||
|
if (!buffer || !length || pos < 0)
|
||||||
|
RETURN(B_BAD_VALUE);
|
||||||
|
|
||||||
|
if (uint64(pos) >= Length()) {
|
||||||
|
*length = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (IcbTag().descriptor_flags()) {
|
||||||
|
case ICB_DESCRIPTOR_TYPE_SHORT: {
|
||||||
|
PRINT(("descriptor type: short\n"));
|
||||||
|
AllocationDescriptorList<ShortDescriptorAccessor> list(this, ShortDescriptorAccessor(0));
|
||||||
|
RETURN(_Read(list, pos, buffer, length, block));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ICB_DESCRIPTOR_TYPE_LONG: {
|
||||||
|
PRINT(("descriptor type: long\n"));
|
||||||
|
AllocationDescriptorList<LongDescriptorAccessor> list(this);
|
||||||
|
RETURN(_Read(list, pos, buffer, length, block));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ICB_DESCRIPTOR_TYPE_EXTENDED: {
|
||||||
|
PRINT(("descriptor type: extended\n"));
|
||||||
|
// AllocationDescriptorList<ExtendedDescriptorAccessor> list(this, ExtendedDescriptorAccessor(0));
|
||||||
|
// RETURN(_Read(list, pos, buffer, length, block));
|
||||||
|
RETURN(B_ERROR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ICB_DESCRIPTOR_TYPE_EMBEDDED: {
|
||||||
|
PRINT(("descriptor type: embedded\n"));
|
||||||
|
RETURN(B_ERROR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
PRINT(("Invalid icb descriptor flags! (flags = %d)\n", IcbTag().descriptor_flags()));
|
||||||
|
RETURN(B_BAD_VALUE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Icb::GetDirectoryIterator(DirectoryIterator **iterator)
|
||||||
|
{
|
||||||
|
status_t error = iterator ? B_OK : B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
*iterator = new(nothrow) DirectoryIterator(this);
|
||||||
|
if (*iterator) {
|
||||||
|
error = fIteratorList.PushBack(*iterator);
|
||||||
|
} else {
|
||||||
|
error = B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Icb::Find(const char *filename, vnode_id *id)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("Icb",
|
||||||
|
("filename: `%s', id: %p", filename, id));
|
||||||
|
|
||||||
|
if (!filename || !id)
|
||||||
|
RETURN(B_BAD_VALUE);
|
||||||
|
|
||||||
|
DirectoryIterator *i;
|
||||||
|
status_t error = GetDirectoryIterator(&i);
|
||||||
|
if (!error) {
|
||||||
|
vnode_id entryId;
|
||||||
|
uint32 length = B_FILE_NAME_LENGTH;
|
||||||
|
char name[B_FILE_NAME_LENGTH];
|
||||||
|
|
||||||
|
bool foundIt = false;
|
||||||
|
while (i->GetNextEntry(name, &length, &entryId) == B_OK)
|
||||||
|
{
|
||||||
|
if (strcmp(filename, name) == 0) {
|
||||||
|
foundIt = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundIt) {
|
||||||
|
*id = entryId;
|
||||||
|
} else {
|
||||||
|
error = B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
@@ -0,0 +1,321 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_ICB_H
|
||||||
|
#define _UDF_ICB_H
|
||||||
|
|
||||||
|
/*! \file Icb.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IMPEXP_KERNEL
|
||||||
|
# define _IMPEXP_KERNEL
|
||||||
|
#endif
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include "fsproto.h"
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "kernel_cpp.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
#include "CachedBlock.h"
|
||||||
|
#include "UdfStructures.h"
|
||||||
|
#include "SinglyLinkedList.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
class DirectoryIterator;
|
||||||
|
class Volume;
|
||||||
|
|
||||||
|
/*! \brief Abstract interface to file entry structure members
|
||||||
|
that are not commonly accessible through file_icb_entry().
|
||||||
|
|
||||||
|
This is necessary, since we can't use virtual functions in
|
||||||
|
the disk structure structs themselves, since we generally
|
||||||
|
don't create disk structure objects by calling new, but
|
||||||
|
rather just cast a chunk of memory read off disk to be
|
||||||
|
a pointer to the struct of interest (which works fine
|
||||||
|
for regular functions, but fails miserably for virtuals
|
||||||
|
due to the vtable not being setup properly).
|
||||||
|
*/
|
||||||
|
class AbstractFileEntry {
|
||||||
|
public:
|
||||||
|
virtual uint8* AllocationDescriptors() = 0;
|
||||||
|
virtual uint32 AllocationDescriptorsLength() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Descriptor>
|
||||||
|
class FileEntry : public AbstractFileEntry {
|
||||||
|
public:
|
||||||
|
FileEntry(CachedBlock *descriptorBlock = NULL);
|
||||||
|
void SetTo(CachedBlock *descriptorBlock);
|
||||||
|
virtual uint8* AllocationDescriptors();
|
||||||
|
virtual uint32 AllocationDescriptorsLength();
|
||||||
|
private:
|
||||||
|
Descriptor* _Descriptor();
|
||||||
|
|
||||||
|
CachedBlock *fDescriptorBlock;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Icb {
|
||||||
|
public:
|
||||||
|
Icb(Volume *volume, long_address address);
|
||||||
|
status_t InitCheck();
|
||||||
|
vnode_id Id() { return fId; }
|
||||||
|
|
||||||
|
// categorization
|
||||||
|
uint8 Type() { return IcbTag().file_type(); }
|
||||||
|
bool IsFile() { return InitCheck() == B_OK && Type() == ICB_TYPE_REGULAR_FILE; }
|
||||||
|
bool IsDirectory() { return InitCheck() == B_OK
|
||||||
|
&& (Type() == ICB_TYPE_DIRECTORY || Type() == ICB_TYPE_STREAM_DIRECTORY); }
|
||||||
|
|
||||||
|
uint32 Uid() { return 0; }//FileEntry()->uid(); }
|
||||||
|
uint32 Gid() { return 0; }
|
||||||
|
uint16 FileLinkCount() { return FileEntry()->file_link_count(); }
|
||||||
|
uint64 Length() { return FileEntry()->information_length(); }
|
||||||
|
mode_t Mode() { return (IsDirectory() ? S_IFDIR : S_IFREG) | S_IRUSR | S_IRGRP | S_IROTH; }
|
||||||
|
time_t AccessTime();
|
||||||
|
time_t ModificationTime();
|
||||||
|
|
||||||
|
uint8 *AllocationDescriptors() { return AbstractEntry()->AllocationDescriptors(); }
|
||||||
|
uint32 AllocationDescriptorsSize() { return AbstractEntry()->AllocationDescriptorsLength(); }
|
||||||
|
|
||||||
|
status_t Read(off_t pos, void *buffer, size_t *length, uint32 *block = NULL);
|
||||||
|
|
||||||
|
// for directories only
|
||||||
|
status_t GetDirectoryIterator(DirectoryIterator **iterator);
|
||||||
|
status_t Find(const char *filename, vnode_id *id);
|
||||||
|
|
||||||
|
Volume* GetVolume() const { return fVolume; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Icb(); // unimplemented
|
||||||
|
|
||||||
|
descriptor_tag & Tag() { return (reinterpret_cast<icb_header*>(fData.Block()))->tag(); }
|
||||||
|
icb_entry_tag& IcbTag() { return (reinterpret_cast<icb_header*>(fData.Block()))->icb_tag(); }
|
||||||
|
AbstractFileEntry* AbstractEntry() {
|
||||||
|
DEBUG_INIT("Icb");
|
||||||
|
return (Tag().id() == TAGID_EXTENDED_FILE_ENTRY)
|
||||||
|
// ? reinterpret_cast<extended_file_icb_entry*>(fData.Block())
|
||||||
|
// : reinterpret_cast<file_icb_entry*>(fData.Block()));
|
||||||
|
? &fExtendedEntry
|
||||||
|
: &fFileEntry;
|
||||||
|
}
|
||||||
|
file_icb_entry* FileEntry() { return (reinterpret_cast<file_icb_entry*>(fData.Block())); }
|
||||||
|
extended_file_icb_entry& ExtendedEntry() { return *(reinterpret_cast<extended_file_icb_entry*>(fData.Block())); }
|
||||||
|
|
||||||
|
template <class DescriptorList>
|
||||||
|
status_t _Read(DescriptorList &list, off_t pos, void *buffer, size_t *length, uint32 *block);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
Volume *fVolume;
|
||||||
|
CachedBlock fData;
|
||||||
|
status_t fInitStatus;
|
||||||
|
vnode_id fId;
|
||||||
|
SinglyLinkedList<DirectoryIterator*> fIteratorList;
|
||||||
|
/* [zooey]: gcc-2.95.3 requires the explicit namespace here, otherwise
|
||||||
|
it complains about a syntax error(!). This is most probably a bug. */
|
||||||
|
Udf::FileEntry<file_icb_entry> fFileEntry;
|
||||||
|
Udf::FileEntry<extended_file_icb_entry> fExtendedEntry;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief Does the dirty work of reading using the given DescriptorList object
|
||||||
|
to access the allocation descriptors properly.
|
||||||
|
*/
|
||||||
|
template <class DescriptorList>
|
||||||
|
status_t
|
||||||
|
Icb::_Read(DescriptorList &list, off_t pos, void *_buffer, size_t *length, uint32 *block)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("Icb", ("list: %p, pos: %Ld, buffer: %p, length: (%p)->%ld",
|
||||||
|
&list, pos, _buffer, length, (length ? *length : 0)));
|
||||||
|
if (!_buffer || !length)
|
||||||
|
RETURN(B_BAD_VALUE);
|
||||||
|
|
||||||
|
uint64 bytesLeftInFile = uint64(pos) > Length() ? 0 : Length() - pos;
|
||||||
|
size_t bytesLeft = (*length >= bytesLeftInFile) ? bytesLeftInFile : *length;
|
||||||
|
size_t bytesRead = 0;
|
||||||
|
|
||||||
|
Volume *volume = GetVolume();
|
||||||
|
status_t error = B_OK;
|
||||||
|
uint8 *buffer = reinterpret_cast<uint8*>(_buffer);
|
||||||
|
bool isFirstBlock = true;
|
||||||
|
|
||||||
|
while (bytesLeft > 0 && !error) {
|
||||||
|
|
||||||
|
PRINT(("pos: %Ld\n", pos));
|
||||||
|
PRINT(("bytesLeft: %ld\n", bytesLeft));
|
||||||
|
|
||||||
|
long_address extent;
|
||||||
|
bool isEmpty = false;
|
||||||
|
error = list.FindExtent(pos, &extent, &isEmpty);
|
||||||
|
if (!error) {
|
||||||
|
PRINT(("found extent for offset %Ld: (block: %ld, partition: %d, length: %ld, type: %d)\n",
|
||||||
|
pos, extent.block(), extent.partition(), extent.length(), extent.type()));
|
||||||
|
|
||||||
|
switch (extent.type()) {
|
||||||
|
case EXTENT_TYPE_RECORDED:
|
||||||
|
isEmpty = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXTENT_TYPE_ALLOCATED:
|
||||||
|
case EXTENT_TYPE_UNALLOCATED:
|
||||||
|
isEmpty = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
PRINT(("Invalid extent type found: %d\n", extent.type()));
|
||||||
|
error = B_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
// Note the unmapped first block of the total read in
|
||||||
|
// the block output parameter if provided
|
||||||
|
if (isFirstBlock) {
|
||||||
|
isFirstBlock = false;
|
||||||
|
if (block)
|
||||||
|
*block = extent.block();
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t blockOffset = pos - off_t((pos >> volume->BlockShift()) << volume->BlockShift());
|
||||||
|
size_t fullBlocksLeft = bytesLeft >> volume->BlockShift();
|
||||||
|
|
||||||
|
if (fullBlocksLeft > 0 && blockOffset == 0) {
|
||||||
|
PRINT(("reading full block (or more)\n"));
|
||||||
|
// Block aligned and at least one full block left. Read in using
|
||||||
|
// cached_read() calls.
|
||||||
|
off_t diskBlock;
|
||||||
|
error = volume->MapBlock(extent, &diskBlock);
|
||||||
|
if (!error) {
|
||||||
|
size_t fullBlockBytesLeft = fullBlocksLeft << volume->BlockShift();
|
||||||
|
size_t readLength = fullBlockBytesLeft < extent.length()
|
||||||
|
? fullBlockBytesLeft
|
||||||
|
: extent.length();
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
PRINT(("reading %ld empty bytes as zeros\n", readLength));
|
||||||
|
memset(buffer, 0, readLength);
|
||||||
|
} else {
|
||||||
|
off_t diskBlock;
|
||||||
|
error = volume->MapBlock(extent, &diskBlock);
|
||||||
|
if (!error) {
|
||||||
|
PRINT(("reading %ld bytes from disk block %Ld using cached_read()\n",
|
||||||
|
readLength, diskBlock));
|
||||||
|
error = cached_read(volume->Device(), diskBlock, buffer,
|
||||||
|
readLength >> volume->BlockShift(),
|
||||||
|
volume->BlockSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
bytesLeft -= readLength;
|
||||||
|
bytesRead += readLength;
|
||||||
|
pos += readLength;
|
||||||
|
buffer += readLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PRINT(("partial block\n"));
|
||||||
|
off_t partialOffset;
|
||||||
|
size_t partialLength;
|
||||||
|
if (blockOffset == 0) {
|
||||||
|
// Block aligned, but only a partial block's worth remaining. Read
|
||||||
|
// in remaining bytes of file
|
||||||
|
partialOffset = 0;
|
||||||
|
partialLength = bytesLeft;
|
||||||
|
} else {
|
||||||
|
// Not block aligned, so just read up to the next block boundary.
|
||||||
|
partialOffset = blockOffset;
|
||||||
|
partialLength = volume->BlockSize() - blockOffset;
|
||||||
|
if (bytesLeft < partialLength)
|
||||||
|
partialLength = bytesLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT(("partialOffset: %Ld\n", partialOffset));
|
||||||
|
PRINT(("partialLength: %ld\n", partialLength));
|
||||||
|
|
||||||
|
if (isEmpty) {
|
||||||
|
PRINT(("reading %ld empty bytes as zeros\n", partialLength));
|
||||||
|
memset(buffer, 0, partialLength);
|
||||||
|
} else {
|
||||||
|
off_t diskBlock;
|
||||||
|
error = volume->MapBlock(extent, &diskBlock);
|
||||||
|
if (!error) {
|
||||||
|
PRINT(("reading %ld bytes from disk block %Ld using get_block()\n",
|
||||||
|
partialLength, diskBlock));
|
||||||
|
uint8 *data = (uint8*)get_block(volume->Device(), diskBlock, volume->BlockSize());
|
||||||
|
error = data ? B_OK : B_BAD_DATA;
|
||||||
|
if (!error) {
|
||||||
|
memcpy(buffer, data+partialOffset, partialLength);
|
||||||
|
release_block(volume->Device(), diskBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
bytesLeft -= partialLength;
|
||||||
|
bytesRead += partialLength;
|
||||||
|
pos += partialLength;
|
||||||
|
buffer += partialLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PRINT(("error finding extent for offset %Ld: 0x%lx, `%s'", pos,
|
||||||
|
error, strerror(error)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*length = bytesRead;
|
||||||
|
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Descriptor>
|
||||||
|
FileEntry<Descriptor>::FileEntry(CachedBlock *descriptorBlock)
|
||||||
|
: fDescriptorBlock(descriptorBlock)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Descriptor>
|
||||||
|
void
|
||||||
|
FileEntry<Descriptor>::SetTo(CachedBlock *descriptorBlock)
|
||||||
|
{
|
||||||
|
fDescriptorBlock = descriptorBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Descriptor>
|
||||||
|
uint8*
|
||||||
|
FileEntry<Descriptor>::AllocationDescriptors()
|
||||||
|
{
|
||||||
|
Descriptor* descriptor = _Descriptor();
|
||||||
|
return descriptor ? descriptor->allocation_descriptors() : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Descriptor>
|
||||||
|
uint32
|
||||||
|
FileEntry<Descriptor>::AllocationDescriptorsLength()
|
||||||
|
{
|
||||||
|
Descriptor* descriptor = _Descriptor();
|
||||||
|
return descriptor ? descriptor->allocation_descriptors_length() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Descriptor>
|
||||||
|
Descriptor*
|
||||||
|
FileEntry<Descriptor>::_Descriptor()
|
||||||
|
{
|
||||||
|
return fDescriptorBlock ? reinterpret_cast<Descriptor*>(fDescriptorBlock->Block()) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_ICB_H
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel file_systems udf ;
|
||||||
|
|
||||||
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
|
SubDirC++Flags -fno-rtti ;
|
||||||
|
|
||||||
|
# save original optimization level
|
||||||
|
oldOPTIM = $(OPTIM) ;
|
||||||
|
|
||||||
|
# set some additional defines
|
||||||
|
{
|
||||||
|
local defines =
|
||||||
|
KEEP_WRONG_DIRENT_RECLEN
|
||||||
|
;
|
||||||
|
|
||||||
|
defines += COMPILE_FOR_R5 ;
|
||||||
|
|
||||||
|
if $(DEBUG) = 0 {
|
||||||
|
# the gcc on BeOS doesn't compile BFS correctly with -O2 or more
|
||||||
|
OPTIM = -O1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
defines = [ FDefines $(defines) ] ;
|
||||||
|
SubDirCcFlags $(defines) -Wall -Wno-multichar ;
|
||||||
|
SubDirC++Flags $(defines) -Wall -Wno-multichar ;
|
||||||
|
}
|
||||||
|
|
||||||
|
UsePrivateHeaders kernel ; # For kernel_cpp.cpp
|
||||||
|
UsePrivateHeaders [ FDirName kernel util ] ; # For all the UDF source files
|
||||||
|
|
||||||
|
KernelAddon udf : kernel file_systems :
|
||||||
|
kernel_cpp.cpp
|
||||||
|
udf.cpp
|
||||||
|
|
||||||
|
DirectoryIterator.cpp
|
||||||
|
DString.cpp
|
||||||
|
Icb.cpp
|
||||||
|
MetadataPartition.cpp
|
||||||
|
PhysicalPartition.cpp
|
||||||
|
Recognition.cpp
|
||||||
|
SparablePartition.cpp
|
||||||
|
UdfDebug.cpp
|
||||||
|
UdfString.cpp
|
||||||
|
UdfStructures.cpp
|
||||||
|
Utils.cpp
|
||||||
|
VirtualPartition.cpp
|
||||||
|
Volume.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
SEARCH on [ FGristFiles
|
||||||
|
kernel_cpp.cpp
|
||||||
|
] = [ FDirName $(HAIKU_TOP) src system kernel util ] ;
|
||||||
|
|
||||||
|
|
||||||
|
rule InstallUDF
|
||||||
|
{
|
||||||
|
Depends $(<) : $(>) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
actions ignore InstallUDF
|
||||||
|
{
|
||||||
|
cp $(>) /boot/home/config/add-ons/kernel/file_systems/
|
||||||
|
}
|
||||||
|
|
||||||
|
InstallUDF install : udf ;
|
||||||
|
|
||||||
|
# restore original optimization level
|
||||||
|
OPTIM = $(oldOPTIM) ;
|
||||||
|
|
||||||
|
SubInclude HAIKU_TOP src add-ons kernel file_systems udf drive_setup_addon ;
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _UDF_MEMORY_CHUNK_H
|
||||||
|
#define _UDF_MEMORY_CHUNK_H
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "kernel_cpp.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
/*! Simple class to encapsulate the boring details of allocating
|
||||||
|
and deallocating a chunk of memory.
|
||||||
|
|
||||||
|
The main use for this class is cleanly and simply allocating
|
||||||
|
arbitrary chunks of data on the stack.
|
||||||
|
*/
|
||||||
|
class MemoryChunk {
|
||||||
|
public:
|
||||||
|
MemoryChunk(uint32 blockSize)
|
||||||
|
: fSize(blockSize)
|
||||||
|
, fData(malloc(blockSize))
|
||||||
|
, fOwnsData(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryChunk(uint32 blockSize, void *blockData)
|
||||||
|
: fSize(blockSize)
|
||||||
|
, fData(blockData)
|
||||||
|
, fOwnsData(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~MemoryChunk()
|
||||||
|
{
|
||||||
|
if (fOwnsData)
|
||||||
|
free(Data());
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Size() { return fSize; }
|
||||||
|
void* Data() { return fData; }
|
||||||
|
status_t InitCheck() { return Data() ? B_OK : B_NO_MEMORY; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemoryChunk();
|
||||||
|
MemoryChunk(const MemoryChunk&);
|
||||||
|
MemoryChunk& operator=(const MemoryChunk&);
|
||||||
|
|
||||||
|
uint32 fSize;
|
||||||
|
void *fData;
|
||||||
|
bool fOwnsData;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <uint32 size>
|
||||||
|
class StaticMemoryChunk {
|
||||||
|
public:
|
||||||
|
uint32 Size() { return size; }
|
||||||
|
void* Data() { return reinterpret_cast<void*>(fData); }
|
||||||
|
status_t InitCheck() { return B_OK; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 fData[size];
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_MEMORY_CHUNK_H
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#include "MetadataPartition.h"
|
||||||
|
|
||||||
|
#define B_NOT_IMPLEMENTED B_ERROR
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
/*! \brief Creates a new MetadataPartition object.
|
||||||
|
*/
|
||||||
|
MetadataPartition::MetadataPartition(Partition &parentPartition,
|
||||||
|
uint32 metadataFileLocation,
|
||||||
|
uint32 metadataMirrorFileLocation,
|
||||||
|
uint32 metadataBitmapFileLocation,
|
||||||
|
uint32 allocationUnitSize,
|
||||||
|
uint16 alignmentUnitSize,
|
||||||
|
bool metadataIsDuplicated)
|
||||||
|
: fParentPartition(parentPartition)
|
||||||
|
, fAllocationUnitSize(allocationUnitSize)
|
||||||
|
, fAlignmentUnitSize(alignmentUnitSize)
|
||||||
|
, fMetadataIsDuplicated(metadataIsDuplicated)
|
||||||
|
, fInitStatus(B_NO_INIT)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Destroys the MetadataPartition object.
|
||||||
|
*/
|
||||||
|
MetadataPartition::~MetadataPartition()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Maps the given logical block to a physical block on disc.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
MetadataPartition::MapBlock(uint32 logicalBlock, off_t &physicalBlock)
|
||||||
|
{
|
||||||
|
return B_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Returns the initialization status of the object.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
MetadataPartition::InitCheck()
|
||||||
|
{
|
||||||
|
return fInitStatus;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_METADATA_PARTITION_H
|
||||||
|
#define _UDF_METADATA_PARTITION_H
|
||||||
|
|
||||||
|
/*! \file MetadataPartition.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kernel_cpp.h>
|
||||||
|
|
||||||
|
#include "Partition.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
/*! \brief Type 2 metadata partition
|
||||||
|
|
||||||
|
Metadata partitions allow for clustering of metadata (ICBs, directory
|
||||||
|
contents, etc.) and also provide the option of metadata duplication.
|
||||||
|
|
||||||
|
See also UDF-2.50 2.2.10, UDF-2.50 2.2.13
|
||||||
|
*/
|
||||||
|
class MetadataPartition : public Partition {
|
||||||
|
public:
|
||||||
|
MetadataPartition(Partition &parentPartition, uint32 metadataFileLocation,
|
||||||
|
uint32 metadataMirrorFileLocation, uint32 metadataBitmapFileLocation,
|
||||||
|
uint32 allocationUnitSize, uint16 alignmentUnitSize,
|
||||||
|
bool metadataIsDuplicated);
|
||||||
|
virtual ~MetadataPartition();
|
||||||
|
virtual status_t MapBlock(uint32 logicalBlock, off_t &physicalBlock);
|
||||||
|
|
||||||
|
status_t InitCheck();
|
||||||
|
|
||||||
|
uint32 AllocationUnitSize() const { return fAllocationUnitSize; }
|
||||||
|
uint16 AlignmentUnitSize() const { return fAlignmentUnitSize; }
|
||||||
|
uint32 MetadataIsDuplicated() const { return fMetadataIsDuplicated; }
|
||||||
|
private:
|
||||||
|
Partition &fParentPartition;
|
||||||
|
uint32 fAllocationUnitSize;
|
||||||
|
uint16 fAlignmentUnitSize;
|
||||||
|
bool fMetadataIsDuplicated;
|
||||||
|
status_t fInitStatus;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_METADATA_PARTITION_H
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_PARTITION_H
|
||||||
|
#define _UDF_PARTITION_H
|
||||||
|
|
||||||
|
/*! \file Partition.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
/*! \brief Abstract base class for various UDF partition types.
|
||||||
|
*/
|
||||||
|
class Partition {
|
||||||
|
public:
|
||||||
|
virtual ~Partition() {}
|
||||||
|
virtual status_t MapBlock(uint32 logicalBlock, off_t &physicalBlock) = 0;
|
||||||
|
// virtual status_t MapExtent(uint32 logicalBlock, uint32 logicalLength,
|
||||||
|
// uint32 &physicalBlock, uint32 &physicalLength) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_PARTITION_H
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#include "PhysicalPartition.h"
|
||||||
|
|
||||||
|
#define B_NOT_IMPLEMENTED B_ERROR
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
/*! \brief Creates a new PhysicalPartition object.
|
||||||
|
*/
|
||||||
|
PhysicalPartition::PhysicalPartition(uint16 number, uint32 start, uint32 length)
|
||||||
|
: fNumber(number)
|
||||||
|
, fStart(start)
|
||||||
|
, fLength(length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Destroys the PhysicalPartition object.
|
||||||
|
*/
|
||||||
|
PhysicalPartition::~PhysicalPartition()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Maps the given logical block to a physical block on disc.
|
||||||
|
|
||||||
|
The given logical block is simply treated as an offset from the
|
||||||
|
start of the physical partition.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
PhysicalPartition::MapBlock(uint32 logicalBlock, off_t &physicalBlock)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("PhysicalPartition", ("%ld", logicalBlock));
|
||||||
|
if (logicalBlock >= fLength) {
|
||||||
|
PRINT(("invalid logical block: %ld, length: %ld\n", logicalBlock, fLength));
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
} else {
|
||||||
|
physicalBlock = fStart + logicalBlock;
|
||||||
|
PRINT(("mapped %ld to %Ld\n", logicalBlock, physicalBlock));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_PHYSICAL_PARTITION_H
|
||||||
|
#define _UDF_PHYSICAL_PARTITION_H
|
||||||
|
|
||||||
|
/*! \file PhysicalPartition.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kernel_cpp.h>
|
||||||
|
|
||||||
|
#include "Partition.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
/*! \brief Standard type 1 physical partition
|
||||||
|
|
||||||
|
PhysicalPartitions map logical block numbers directly to physical
|
||||||
|
block numbers.
|
||||||
|
|
||||||
|
See also: ECMA-167 10.7.2
|
||||||
|
*/
|
||||||
|
class PhysicalPartition : public Partition {
|
||||||
|
public:
|
||||||
|
PhysicalPartition(uint16 number, uint32 start, uint32 length);
|
||||||
|
virtual ~PhysicalPartition();
|
||||||
|
virtual status_t MapBlock(uint32 logicalBlock, off_t &physicalBlock);
|
||||||
|
|
||||||
|
uint16 Number() const { return fNumber; }
|
||||||
|
uint32 Start() const { return fStart; }
|
||||||
|
uint32 Length() const { return fLength; }
|
||||||
|
private:
|
||||||
|
uint16 fNumber;
|
||||||
|
uint32 fStart;
|
||||||
|
uint32 fLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_PHYSICAL_PARTITION_H
|
||||||
@@ -0,0 +1,549 @@
|
|||||||
|
#include "Recognition.h"
|
||||||
|
|
||||||
|
#include "UdfString.h"
|
||||||
|
#include "MemoryChunk.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// forward declarations
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
walk_volume_recognition_sequence(int device, off_t offset,
|
||||||
|
uint32 blockSize,
|
||||||
|
uint32 blockShift);
|
||||||
|
static status_t
|
||||||
|
walk_anchor_volume_descriptor_sequences(int device, off_t offset, off_t length,
|
||||||
|
uint32 blockSize, uint32 blockShift,
|
||||||
|
logical_volume_descriptor &logicalVolumeDescriptor,
|
||||||
|
partition_descriptor partitionDescriptors[],
|
||||||
|
uint8 &partitionDescriptorCount);
|
||||||
|
static status_t
|
||||||
|
walk_volume_descriptor_sequence(extent_address descriptorSequence,
|
||||||
|
int device, uint32 blockSize, uint32 blockShift,
|
||||||
|
logical_volume_descriptor &logicalVolumeDescriptor,
|
||||||
|
partition_descriptor partitionDescriptors[],
|
||||||
|
uint8 &partitionDescriptorCount);
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
walk_integrity_sequence(int device, uint32 blockSize, uint32 blockShift,
|
||||||
|
extent_address descriptorSequence, uint32 sequenceNumber = 0);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// externally visible functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Udf::udf_recognize(int device, off_t offset, off_t length, uint32 blockSize,
|
||||||
|
uint32 &blockShift, logical_volume_descriptor &logicalVolumeDescriptor,
|
||||||
|
partition_descriptor partitionDescriptors[],
|
||||||
|
uint8 &partitionDescriptorCount)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC(NULL, ("device: %d, offset: %Ld, length: %Ld, "
|
||||||
|
"blockSize: %ld, [...descriptors, etc...]", device, offset,
|
||||||
|
length, blockSize));
|
||||||
|
|
||||||
|
// Check the block size
|
||||||
|
status_t error = get_block_shift(blockSize, blockShift);
|
||||||
|
if (!error) {
|
||||||
|
PRINT(("blockShift: %ld\n", blockShift));
|
||||||
|
|
||||||
|
// Check for a valid volume recognition sequence
|
||||||
|
error = walk_volume_recognition_sequence(device, offset, blockSize, blockShift);
|
||||||
|
|
||||||
|
// Now hunt down a volume descriptor sequence from one of
|
||||||
|
// the anchor volume pointers (if there are any).
|
||||||
|
if (!error) {
|
||||||
|
error = walk_anchor_volume_descriptor_sequences(device, offset, length,
|
||||||
|
blockSize, blockShift,
|
||||||
|
logicalVolumeDescriptor,
|
||||||
|
partitionDescriptors,
|
||||||
|
partitionDescriptorCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now walk the integrity sequence and make sure the last integrity
|
||||||
|
// descriptor is a closed descriptor
|
||||||
|
if (!error) {
|
||||||
|
error = walk_integrity_sequence(device, blockSize, blockShift,
|
||||||
|
logicalVolumeDescriptor.integrity_sequence_extent());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PRINT(("Block size must be a positive power of two! (blockSize = %ld)\n", blockSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Udf::udf_recognize(int device, off_t offset, off_t length, uint32 blockSize,
|
||||||
|
char *volumeName)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC(NULL, ("device: %d, offset: %Ld, length: %Ld, "
|
||||||
|
"blockSize: %ld, volumeName: %p", device, offset, length,
|
||||||
|
blockSize, volumeName));
|
||||||
|
logical_volume_descriptor logicalVolumeDescriptor;
|
||||||
|
partition_descriptor partitionDescriptors[Udf::kMaxPartitionDescriptors];
|
||||||
|
uint8 partitionDescriptorCount;
|
||||||
|
uint32 blockShift;
|
||||||
|
status_t error = udf_recognize(device, offset, length, blockSize, blockShift,
|
||||||
|
logicalVolumeDescriptor, partitionDescriptors,
|
||||||
|
partitionDescriptorCount);
|
||||||
|
if (!error && volumeName) {
|
||||||
|
String name(logicalVolumeDescriptor.logical_volume_identifier());
|
||||||
|
strcpy(volumeName, name.Utf8());
|
||||||
|
}
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// local functions
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static
|
||||||
|
status_t
|
||||||
|
walk_volume_recognition_sequence(int device, off_t offset, uint32 blockSize, uint32 blockShift)
|
||||||
|
{
|
||||||
|
DEBUG_INIT(NULL);
|
||||||
|
// vrs starts at block 16. Each volume structure descriptor (vsd)
|
||||||
|
// should be one block long. We're expecting to find 0 or more iso9660
|
||||||
|
// vsd's followed by some ECMA-167 vsd's.
|
||||||
|
MemoryChunk chunk(blockSize);
|
||||||
|
status_t error = chunk.InitCheck();
|
||||||
|
if (!error) {
|
||||||
|
bool foundISO = false;
|
||||||
|
bool foundExtended = false;
|
||||||
|
bool foundECMA167 = false;
|
||||||
|
bool foundECMA168 = false;
|
||||||
|
bool foundBoot = false;
|
||||||
|
for (uint32 block = 16; true; block++) {
|
||||||
|
PRINT(("block %ld: ", block))
|
||||||
|
off_t address = (offset + block) << blockShift;
|
||||||
|
ssize_t bytesRead = read_pos(device, address, chunk.Data(), blockSize);
|
||||||
|
if (bytesRead == (ssize_t)blockSize)
|
||||||
|
{
|
||||||
|
volume_structure_descriptor_header* descriptor =
|
||||||
|
reinterpret_cast<volume_structure_descriptor_header*>(chunk.Data());
|
||||||
|
if (descriptor->id_matches(kVSDID_ISO)) {
|
||||||
|
SIMPLE_PRINT(("found ISO9660 descriptor\n"));
|
||||||
|
foundISO = true;
|
||||||
|
} else if (descriptor->id_matches(kVSDID_BEA)) {
|
||||||
|
SIMPLE_PRINT(("found BEA descriptor\n"));
|
||||||
|
foundExtended = true;
|
||||||
|
} else if (descriptor->id_matches(kVSDID_TEA)) {
|
||||||
|
SIMPLE_PRINT(("found TEA descriptor\n"));
|
||||||
|
foundExtended = true;
|
||||||
|
} else if (descriptor->id_matches(kVSDID_ECMA167_2)) {
|
||||||
|
SIMPLE_PRINT(("found ECMA-167 rev 2 descriptor\n"));
|
||||||
|
foundECMA167 = true;
|
||||||
|
} else if (descriptor->id_matches(kVSDID_ECMA167_3)) {
|
||||||
|
SIMPLE_PRINT(("found ECMA-167 rev 3 descriptor\n"));
|
||||||
|
foundECMA167 = true;
|
||||||
|
} else if (descriptor->id_matches(kVSDID_BOOT)) {
|
||||||
|
SIMPLE_PRINT(("found boot descriptor\n"));
|
||||||
|
foundBoot = true;
|
||||||
|
} else if (descriptor->id_matches(kVSDID_ECMA168)) {
|
||||||
|
SIMPLE_PRINT(("found ECMA-168 descriptor\n"));
|
||||||
|
foundECMA168 = true;
|
||||||
|
} else {
|
||||||
|
SIMPLE_PRINT(("found invalid descriptor, id = `%.5s'\n", descriptor->id));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SIMPLE_PRINT(("read_pos(pos:%Ld, len:%ld) failed with: 0x%lx\n", address,
|
||||||
|
blockSize, bytesRead));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we find an ECMA-167 descriptor, OR if we find a beginning
|
||||||
|
// or terminating extended area descriptor with NO ECMA-168
|
||||||
|
// descriptors, we return B_OK to signal that we should go
|
||||||
|
// looking for valid anchors.
|
||||||
|
error = foundECMA167 || (foundExtended && !foundECMA168) ? B_OK : B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
status_t
|
||||||
|
walk_anchor_volume_descriptor_sequences(int device, off_t offset, off_t length,
|
||||||
|
uint32 blockSize, uint32 blockShift,
|
||||||
|
logical_volume_descriptor &logicalVolumeDescriptor,
|
||||||
|
partition_descriptor partitionDescriptors[],
|
||||||
|
uint8 &partitionDescriptorCount)
|
||||||
|
{
|
||||||
|
DEBUG_INIT(NULL);
|
||||||
|
const uint8 avds_location_count = 4;
|
||||||
|
const off_t avds_locations[avds_location_count] = {
|
||||||
|
256,
|
||||||
|
length-1-256,
|
||||||
|
length-1,
|
||||||
|
512,
|
||||||
|
};
|
||||||
|
bool found_vds = false;
|
||||||
|
for (int32 i = 0; i < avds_location_count; i++) {
|
||||||
|
off_t block = avds_locations[i];
|
||||||
|
off_t address = (offset + block) << blockShift;
|
||||||
|
MemoryChunk chunk(blockSize);
|
||||||
|
anchor_volume_descriptor *anchor = NULL;
|
||||||
|
|
||||||
|
status_t anchorErr = chunk.InitCheck();
|
||||||
|
if (!anchorErr) {
|
||||||
|
ssize_t bytesRead = read_pos(device, address, chunk.Data(), blockSize);
|
||||||
|
anchorErr = bytesRead == (ssize_t)blockSize ? B_OK : B_IO_ERROR;
|
||||||
|
if (anchorErr) {
|
||||||
|
PRINT(("block %Ld: read_pos(pos:%Ld, len:%ld) failed with error 0x%lx\n",
|
||||||
|
block, address, blockSize, bytesRead));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!anchorErr) {
|
||||||
|
anchor = reinterpret_cast<anchor_volume_descriptor*>(chunk.Data());
|
||||||
|
anchorErr = anchor->tag().init_check(block+offset);
|
||||||
|
if (anchorErr) {
|
||||||
|
PRINT(("block %Ld: invalid anchor\n", block));
|
||||||
|
} else {
|
||||||
|
PRINT(("block %Ld: valid anchor\n", block));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!anchorErr) {
|
||||||
|
PRINT(("block %Ld: anchor:\n", block));
|
||||||
|
PDUMP(anchor);
|
||||||
|
// Found an avds, so try the main sequence first, then
|
||||||
|
// the reserve sequence if the main one fails.
|
||||||
|
anchorErr = walk_volume_descriptor_sequence(anchor->main_vds(), device,
|
||||||
|
blockSize, blockShift,
|
||||||
|
logicalVolumeDescriptor,
|
||||||
|
partitionDescriptors,
|
||||||
|
partitionDescriptorCount);
|
||||||
|
if (anchorErr)
|
||||||
|
anchorErr = walk_volume_descriptor_sequence(anchor->reserve_vds(), device,
|
||||||
|
blockSize, blockShift,
|
||||||
|
logicalVolumeDescriptor,
|
||||||
|
partitionDescriptors,
|
||||||
|
partitionDescriptorCount);
|
||||||
|
}
|
||||||
|
if (!anchorErr) {
|
||||||
|
PRINT(("block %Ld: found valid vds\n", avds_locations[i]));
|
||||||
|
found_vds = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Both failed, so loop around and try another avds
|
||||||
|
PRINT(("block %Ld: vds search failed\n", avds_locations[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status_t error = found_vds ? B_OK : B_ERROR;
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
status_t
|
||||||
|
walk_volume_descriptor_sequence(extent_address descriptorSequence,
|
||||||
|
int device, uint32 blockSize, uint32 blockShift,
|
||||||
|
logical_volume_descriptor &logicalVolumeDescriptor,
|
||||||
|
partition_descriptor partitionDescriptors[],
|
||||||
|
uint8 &partitionDescriptorCount)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC(NULL, ("descriptorSequence.loc:%ld, descriptorSequence.len:%ld",
|
||||||
|
descriptorSequence.location(), descriptorSequence.length()));
|
||||||
|
uint32 count = descriptorSequence.length() >> blockShift;
|
||||||
|
|
||||||
|
bool foundLogicalVolumeDescriptor = false;
|
||||||
|
bool foundUnallocatedSpaceDescriptor = false;
|
||||||
|
bool foundUdfImplementationUseDescriptor = false;
|
||||||
|
uint8 uniquePartitions = 0;
|
||||||
|
status_t error = B_OK;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
off_t block = descriptorSequence.location()+i;
|
||||||
|
off_t address = block << blockShift;
|
||||||
|
MemoryChunk chunk(blockSize);
|
||||||
|
descriptor_tag *tag = NULL;
|
||||||
|
|
||||||
|
PRINT(("descriptor #%ld (block %Ld):\n", i, block));
|
||||||
|
|
||||||
|
status_t loopError = chunk.InitCheck();
|
||||||
|
if (!loopError) {
|
||||||
|
ssize_t bytesRead = read_pos(device, address, chunk.Data(), blockSize);
|
||||||
|
loopError = bytesRead == (ssize_t)blockSize ? B_OK : B_IO_ERROR;
|
||||||
|
if (loopError) {
|
||||||
|
PRINT(("block %Ld: read_pos(pos:%Ld, len:%ld) failed with error 0x%lx\n",
|
||||||
|
block, address, blockSize, bytesRead));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!loopError) {
|
||||||
|
tag = reinterpret_cast<descriptor_tag *>(chunk.Data());
|
||||||
|
loopError = tag->init_check(block);
|
||||||
|
}
|
||||||
|
if (!loopError) {
|
||||||
|
// Now decide what type of descriptor we have
|
||||||
|
switch (tag->id()) {
|
||||||
|
case TAGID_UNDEFINED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAGID_PRIMARY_VOLUME_DESCRIPTOR:
|
||||||
|
{
|
||||||
|
primary_volume_descriptor *primary = reinterpret_cast<primary_volume_descriptor*>(tag);
|
||||||
|
PDUMP(primary);
|
||||||
|
(void)primary; // kill the warning
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TAGID_ANCHOR_VOLUME_DESCRIPTOR_POINTER:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAGID_VOLUME_DESCRIPTOR_POINTER:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAGID_IMPLEMENTATION_USE_VOLUME_DESCRIPTOR:
|
||||||
|
{
|
||||||
|
implementation_use_descriptor *impUse = reinterpret_cast<implementation_use_descriptor*>(tag);
|
||||||
|
PDUMP(impUse);
|
||||||
|
// Check for a matching implementation id string (note that the
|
||||||
|
// revision version is not checked)
|
||||||
|
if (impUse->tag().init_check(block) == B_OK
|
||||||
|
&& impUse->implementation_id().matches(kLogicalVolumeInfoId201))
|
||||||
|
{
|
||||||
|
foundUdfImplementationUseDescriptor = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TAGID_PARTITION_DESCRIPTOR:
|
||||||
|
{
|
||||||
|
partition_descriptor *partition = reinterpret_cast<partition_descriptor*>(tag);
|
||||||
|
PDUMP(partition);
|
||||||
|
if (partition->tag().init_check(block) == B_OK) {
|
||||||
|
// Check for a previously discovered partition descriptor with
|
||||||
|
// the same number as this partition. If found, keep the one with
|
||||||
|
// the higher vds number.
|
||||||
|
bool foundDuplicate = false;
|
||||||
|
int num;
|
||||||
|
for (num = 0; num < uniquePartitions; num++) {
|
||||||
|
if (partitionDescriptors[num].partition_number()
|
||||||
|
== partition->partition_number())
|
||||||
|
{
|
||||||
|
foundDuplicate = true;
|
||||||
|
if (partitionDescriptors[num].vds_number()
|
||||||
|
< partition->vds_number())
|
||||||
|
{
|
||||||
|
partitionDescriptors[num] = *partition;
|
||||||
|
PRINT(("Replacing previous partition #%d (vds_number: %ld) with "
|
||||||
|
"new partition #%d (vds_number: %ld)\n",
|
||||||
|
partitionDescriptors[num].partition_number(),
|
||||||
|
partitionDescriptors[num].vds_number(),
|
||||||
|
partition->partition_number(),
|
||||||
|
partition->vds_number()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we didn't find a duplicate, see if we have any open descriptor
|
||||||
|
// spaces left.
|
||||||
|
if (!foundDuplicate) {
|
||||||
|
if (num < Udf::kMaxPartitionDescriptors) {
|
||||||
|
// At least one more partition descriptor allowed
|
||||||
|
partitionDescriptors[num] = *partition;
|
||||||
|
uniquePartitions++;
|
||||||
|
PRINT(("Adding partition #%d (vds_number: %ld)\n",
|
||||||
|
partition->partition_number(),
|
||||||
|
partition->vds_number()));
|
||||||
|
} else {
|
||||||
|
// We've found more than kMaxPartitionDescriptor uniquely-
|
||||||
|
// numbered partitions. So, search through the partitions
|
||||||
|
// we already have again, this time just looking for a
|
||||||
|
// partition with a lower vds number. If we find one,
|
||||||
|
// replace it with this one. If we don't, scream bloody
|
||||||
|
// murder.
|
||||||
|
bool foundReplacement = false;
|
||||||
|
for (int j = 0; j < uniquePartitions; j++) {
|
||||||
|
if (partitionDescriptors[j].vds_number()
|
||||||
|
< partition->vds_number())
|
||||||
|
{
|
||||||
|
foundReplacement = true;
|
||||||
|
partitionDescriptors[j] = *partition;
|
||||||
|
PRINT(("Replacing partition #%d (vds_number: %ld) "
|
||||||
|
"with partition #%d (vds_number: %ld)\n",
|
||||||
|
partitionDescriptors[j].partition_number(),
|
||||||
|
partitionDescriptors[j].vds_number(),
|
||||||
|
partition->partition_number(),
|
||||||
|
partition->vds_number()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundReplacement) {
|
||||||
|
PRINT(("Found more than kMaxPartitionDescriptors == %d "
|
||||||
|
"unique partition descriptors!\n",
|
||||||
|
kMaxPartitionDescriptors));
|
||||||
|
error = B_BAD_VALUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TAGID_LOGICAL_VOLUME_DESCRIPTOR:
|
||||||
|
{
|
||||||
|
logical_volume_descriptor *logical = reinterpret_cast<logical_volume_descriptor*>(tag);
|
||||||
|
PDUMP(logical);
|
||||||
|
if (foundLogicalVolumeDescriptor) {
|
||||||
|
// Keep the vd with the highest vds_number
|
||||||
|
if (logicalVolumeDescriptor.vds_number() < logical->vds_number())
|
||||||
|
logicalVolumeDescriptor = *logical;
|
||||||
|
} else {
|
||||||
|
logicalVolumeDescriptor = *logical;
|
||||||
|
foundLogicalVolumeDescriptor = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TAGID_UNALLOCATED_SPACE_DESCRIPTOR:
|
||||||
|
{
|
||||||
|
unallocated_space_descriptor *unallocated = reinterpret_cast<unallocated_space_descriptor*>(tag);
|
||||||
|
PDUMP(unallocated);
|
||||||
|
foundUnallocatedSpaceDescriptor = true;
|
||||||
|
(void)unallocated; // kill the warning
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TAGID_TERMINATING_DESCRIPTOR:
|
||||||
|
{
|
||||||
|
terminating_descriptor *terminating = reinterpret_cast<terminating_descriptor*>(tag);
|
||||||
|
PDUMP(terminating);
|
||||||
|
(void)terminating; // kill the warning
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TAGID_LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR:
|
||||||
|
// Not found in this descriptor sequence
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT(("found %d unique partition%s\n", uniquePartitions,
|
||||||
|
(uniquePartitions == 1 ? "" : "s")));
|
||||||
|
|
||||||
|
if (!error && !foundUdfImplementationUseDescriptor) {
|
||||||
|
INFORM(("WARNING: no valid udf implementation use descriptor found\n"));
|
||||||
|
}
|
||||||
|
if (!error)
|
||||||
|
error = foundLogicalVolumeDescriptor
|
||||||
|
&& foundUnallocatedSpaceDescriptor
|
||||||
|
? B_OK : B_ERROR;
|
||||||
|
if (!error)
|
||||||
|
error = uniquePartitions >= 1 ? B_OK : B_ERROR;
|
||||||
|
if (!error)
|
||||||
|
partitionDescriptorCount = uniquePartitions;
|
||||||
|
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Walks the integrity sequence in the extent given by \a descriptorSequence.
|
||||||
|
|
||||||
|
\return
|
||||||
|
- \c B_OK: Success. the sequence was terminated by a valid, closed
|
||||||
|
integrity descriptor.
|
||||||
|
- \c B_ENTRY_NOT_FOUND: The sequence was empty.
|
||||||
|
- (other error code): The sequence was non-empty and did not end in a valid,
|
||||||
|
closed integrity descriptor.
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
walk_integrity_sequence(int device, uint32 blockSize, uint32 blockShift,
|
||||||
|
extent_address descriptorSequence, uint32 sequenceNumber)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC(NULL, ("descriptorSequence.loc:%ld, descriptorSequence.len:%ld",
|
||||||
|
descriptorSequence.location(), descriptorSequence.length()));
|
||||||
|
uint32 count = descriptorSequence.length() >> blockShift;
|
||||||
|
|
||||||
|
bool lastDescriptorWasClosed = false;
|
||||||
|
uint16 highestMinimumUDFReadRevision = 0x0000;
|
||||||
|
status_t error = count > 0 ? B_OK : B_ENTRY_NOT_FOUND;
|
||||||
|
for (uint32 i = 0; error == B_OK && i < count; i++)
|
||||||
|
{
|
||||||
|
off_t block = descriptorSequence.location()+i;
|
||||||
|
off_t address = block << blockShift;
|
||||||
|
MemoryChunk chunk(blockSize);
|
||||||
|
descriptor_tag *tag = NULL;
|
||||||
|
|
||||||
|
PRINT(("integrity descriptor #%ld:%ld (block %Ld):\n", sequenceNumber, i, block));
|
||||||
|
|
||||||
|
status_t loopError = chunk.InitCheck();
|
||||||
|
if (!loopError) {
|
||||||
|
ssize_t bytesRead = read_pos(device, address, chunk.Data(), blockSize);
|
||||||
|
loopError = check_size_error(bytesRead, blockSize);
|
||||||
|
if (loopError) {
|
||||||
|
PRINT(("block %Ld: read_pos(pos:%Ld, len:%ld) failed with error 0x%lx\n",
|
||||||
|
block, address, blockSize, bytesRead));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!loopError) {
|
||||||
|
tag = reinterpret_cast<descriptor_tag *>(chunk.Data());
|
||||||
|
loopError = tag->init_check(block);
|
||||||
|
}
|
||||||
|
if (!loopError) {
|
||||||
|
// Check the descriptor type and see if it's closed.
|
||||||
|
loopError = tag->id() == TAGID_LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR
|
||||||
|
? B_OK : B_BAD_DATA;
|
||||||
|
if (!loopError) {
|
||||||
|
logical_volume_integrity_descriptor *descriptor =
|
||||||
|
reinterpret_cast<logical_volume_integrity_descriptor*>(chunk.Data());
|
||||||
|
PDUMP(descriptor);
|
||||||
|
lastDescriptorWasClosed = descriptor->integrity_type() == INTEGRITY_CLOSED;
|
||||||
|
if (lastDescriptorWasClosed) {
|
||||||
|
uint16 minimumRevision = descriptor->minimum_udf_read_revision();
|
||||||
|
if (minimumRevision > highestMinimumUDFReadRevision) {
|
||||||
|
highestMinimumUDFReadRevision = minimumRevision;
|
||||||
|
} else if (minimumRevision < highestMinimumUDFReadRevision) {
|
||||||
|
INFORM(("WARNING: found decreasing minimum udf read revision in integrity "
|
||||||
|
"sequence (last highest: 0x%04x, current: 0x%04x); using higher "
|
||||||
|
"revision.\n", highestMinimumUDFReadRevision, minimumRevision));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check a continuation extent if necessary. Note that this effectively
|
||||||
|
// ends our search through this extent
|
||||||
|
extent_address &next = descriptor->next_integrity_extent();
|
||||||
|
if (next.length() > 0) {
|
||||||
|
status_t nextError = walk_integrity_sequence(device, blockSize, blockShift,
|
||||||
|
next, sequenceNumber+1);
|
||||||
|
if (nextError && nextError != B_ENTRY_NOT_FOUND) {
|
||||||
|
// Continuation proved invalid
|
||||||
|
error = nextError;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Either the continuation was valid or empty; either way,
|
||||||
|
// we're done searching.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PDUMP(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we hit an error on the first item, consider the extent empty,
|
||||||
|
// otherwise just break out of the loop and assume part of the
|
||||||
|
// extent is unrecorded
|
||||||
|
if (loopError) {
|
||||||
|
if (i == 0)
|
||||||
|
error = B_ENTRY_NOT_FOUND;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!error)
|
||||||
|
error = lastDescriptorWasClosed ? B_OK : B_BAD_DATA;
|
||||||
|
if (!error)
|
||||||
|
error = highestMinimumUDFReadRevision <= UDF_MAX_READ_REVISION ? B_OK : B_ERROR;
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_RECOGNITION_H
|
||||||
|
#define _UDF_RECOGNITION_H
|
||||||
|
|
||||||
|
/*! \file Recognition.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UdfStructures.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
status_t udf_recognize(int device, off_t offset, off_t length,
|
||||||
|
uint32 blockSize, uint32 &blockShift,
|
||||||
|
logical_volume_descriptor &logicalVolumeDescriptor,
|
||||||
|
partition_descriptor partitionDescriptors[],
|
||||||
|
uint8 &partitionDescriptorCount);
|
||||||
|
status_t udf_recognize(int device, off_t offset, off_t length,
|
||||||
|
uint32 blockSize, char *volumeName);
|
||||||
|
|
||||||
|
} // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_RECOGNITION_H
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#include "SparablePartition.h"
|
||||||
|
|
||||||
|
#define B_NOT_IMPLEMENTED B_ERROR
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
/*! \brief Creates a new SparablePartition object.
|
||||||
|
*/
|
||||||
|
SparablePartition::SparablePartition(uint16 number, uint32 start, uint32 length,
|
||||||
|
uint16 packetLength, uint8 tableCount,
|
||||||
|
uint32 *tableLocations)
|
||||||
|
: fNumber(number)
|
||||||
|
, fStart(start)
|
||||||
|
, fLength(length)
|
||||||
|
, fPacketLength(packetLength)
|
||||||
|
, fTableCount(tableCount)
|
||||||
|
, fInitStatus(B_NO_INIT)
|
||||||
|
{
|
||||||
|
status_t error = (0 < TableCount() && TableCount() <= kMaxSparingTableCount)
|
||||||
|
? B_OK : B_BAD_VALUE;
|
||||||
|
if (!error) {
|
||||||
|
for (uint8 i = 0; i < TableCount(); i++)
|
||||||
|
fTableLocations[i] = tableLocations[i];
|
||||||
|
}
|
||||||
|
if (!error)
|
||||||
|
fInitStatus = B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Destroys the SparablePartition object.
|
||||||
|
*/
|
||||||
|
SparablePartition::~SparablePartition()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Maps the given logical block to a physical block on disc.
|
||||||
|
|
||||||
|
The sparing tables are first checked to see if the logical block has
|
||||||
|
been remapped from a defective location to a non-defective one. If
|
||||||
|
not, the given logical block is then simply treated as an offset from
|
||||||
|
the start of the physical partition.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
SparablePartition::MapBlock(uint32 logicalBlock, off_t &physicalBlock)
|
||||||
|
{
|
||||||
|
status_t error = InitCheck();
|
||||||
|
if (!error) {
|
||||||
|
if (logicalBlock >= fLength)
|
||||||
|
error = B_BAD_ADDRESS;
|
||||||
|
else {
|
||||||
|
// Check for the logical block in the sparing tables. If not
|
||||||
|
// found, map directly to physical space.
|
||||||
|
|
||||||
|
//physicalBlock = fStart + logicalBlock;
|
||||||
|
//return B_OK;
|
||||||
|
error = B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Returns the initialization status of the object.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
SparablePartition::InitCheck()
|
||||||
|
{
|
||||||
|
return fInitStatus;
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_SPARABLE_PARTITION_H
|
||||||
|
#define _UDF_SPARABLE_PARTITION_H
|
||||||
|
|
||||||
|
/*! \file SparablePartition.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kernel_cpp.h>
|
||||||
|
|
||||||
|
#include "UdfStructures.h"
|
||||||
|
#include "Partition.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
/*! \brief Type 2 sparable partition
|
||||||
|
|
||||||
|
Sparable partitions provide a defect-managed partition
|
||||||
|
space for media that does not implicitly provide defect management,
|
||||||
|
such as CD-RW. Arbitrary packets of blocks in the sparable partition
|
||||||
|
may be transparently remapped to other locations on disc should the
|
||||||
|
original locations become defective.
|
||||||
|
|
||||||
|
Per UDF-2.01 2.2.11, sparable partitions shall be recorded only on
|
||||||
|
disk/drive systems that do not perform defect management.
|
||||||
|
|
||||||
|
See also UDF-2.01 2.2.9, UDF-2.01 2.2.11
|
||||||
|
*/
|
||||||
|
class SparablePartition : public Partition {
|
||||||
|
public:
|
||||||
|
SparablePartition(uint16 number, uint32 start, uint32 length, uint16 packetLength,
|
||||||
|
uint8 tableCount, uint32 *tableLocations);
|
||||||
|
virtual ~SparablePartition();
|
||||||
|
virtual status_t MapBlock(uint32 logicalBlock, off_t &physicalBlock);
|
||||||
|
|
||||||
|
status_t InitCheck();
|
||||||
|
|
||||||
|
uint16 Number() const { return fNumber; }
|
||||||
|
uint32 Start() const { return fStart; }
|
||||||
|
uint32 Length() const { return fLength; }
|
||||||
|
uint32 PacketLength() const { return fPacketLength; }
|
||||||
|
uint8 TableCount() const { return fTableCount; }
|
||||||
|
|
||||||
|
//! Maximum number of redundant sparing tables per SparablePartition
|
||||||
|
static const uint8 kMaxSparingTableCount = UDF_MAX_SPARING_TABLE_COUNT;
|
||||||
|
private:
|
||||||
|
uint16 fNumber;
|
||||||
|
uint32 fStart;
|
||||||
|
uint32 fLength;
|
||||||
|
uint32 fPacketLength;
|
||||||
|
uint8 fTableCount;
|
||||||
|
uint32 fTableLocations[kMaxSparingTableCount];
|
||||||
|
status_t fInitStatus;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_SPARABLE_PARTITION_H
|
||||||
@@ -0,0 +1,344 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// This version copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
// Initial version copyright (c) 2002 Axel Dörfler, [email protected]
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*! \file Debug.cpp
|
||||||
|
|
||||||
|
Support code for handy debugging macros.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <TLS.h>
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Long-winded overview of the debug output macros:
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def DEBUG_INIT()
|
||||||
|
\brief Increases the indentation level, prints out the enclosing function's
|
||||||
|
name, and creates a \c DebugHelper object on the stack to automatically
|
||||||
|
decrease the indentation level upon function exit.
|
||||||
|
|
||||||
|
This macro should be called at the very beginning of any function in
|
||||||
|
which you wish to use any of the other debugging macros.
|
||||||
|
|
||||||
|
If DEBUG is undefined, does nothing.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def PRINT(x)
|
||||||
|
\brief Prints out the enclosing function's name followed by the contents
|
||||||
|
of \a x at the current indentation level.
|
||||||
|
|
||||||
|
\param x A printf-style format string enclosed in an extra set of parenteses,
|
||||||
|
e.g. PRINT(("%d\n", 0));
|
||||||
|
|
||||||
|
If DEBUG is undefined, does nothing.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def LPRINT(x)
|
||||||
|
\brief Identical to \c PRINT(x), except that the line number in the source
|
||||||
|
file at which the macro is invoked is also printed.
|
||||||
|
|
||||||
|
\param x A printf-style format string enclosed in an extra set of parenteses,
|
||||||
|
e.g. PRINT(("%d\n", 0));
|
||||||
|
|
||||||
|
If DEBUG is undefined, does nothing.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def SIMPLE_PRINT(x)
|
||||||
|
\brief Directly prints the contents of \a x with no extra formatting or
|
||||||
|
information included (just like a straight \c printf() call).
|
||||||
|
|
||||||
|
\param x A printf-style format string enclosed in an extra set of parenteses,
|
||||||
|
e.g. PRINT(("%d\n", 0));
|
||||||
|
|
||||||
|
If DEBUG is undefined, does nothing.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def PRINT_INDENT()
|
||||||
|
\brief Prints out enough indentation characters to indent the current line
|
||||||
|
to the current indentation level (assuming the cursor was flush left to
|
||||||
|
begin with...).
|
||||||
|
|
||||||
|
This function is called by the other \c *PRINT* macros, and isn't really
|
||||||
|
intended for general consumption, but you might find it useful.
|
||||||
|
|
||||||
|
If DEBUG is undefined, does nothing.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def REPORT_ERROR(error)
|
||||||
|
\brief Calls \c LPRINT(x) with a format string listing the error
|
||||||
|
code in \c error (assumed to be a \c status_t value) and the
|
||||||
|
corresponding text error code returned by a call to \c strerror().
|
||||||
|
|
||||||
|
This function is called by the \c RETURN* macros, and isn't really
|
||||||
|
intended for general consumption, but you might find it useful.
|
||||||
|
|
||||||
|
\param error A \c status_t error code to report.
|
||||||
|
|
||||||
|
If DEBUG is undefined, does nothing.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def RETURN_ERROR(error)
|
||||||
|
\brief Calls \c REPORT_ERROR(error) if error is a an error code (i.e.
|
||||||
|
negative), otherwise remains silent. In either case, the enclosing
|
||||||
|
function is then exited with a call to \c "return error;".
|
||||||
|
|
||||||
|
\param error A \c status_t error code to report (if negative) and return.
|
||||||
|
|
||||||
|
If DEBUG is undefined, silently returns the value in \c error.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def RETURN(error)
|
||||||
|
\brief Prints out a description of the error code being returned
|
||||||
|
(which, in this case, may be either "erroneous" or "successful")
|
||||||
|
and then exits the enclosing function with a call to \c "return error;".
|
||||||
|
|
||||||
|
\param error A \c status_t error code to report and return.
|
||||||
|
|
||||||
|
If DEBUG is undefined, silently returns the value in \c error.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def FATAL(x)
|
||||||
|
\brief Prints out a fatal error message.
|
||||||
|
|
||||||
|
This one's still a work in progress...
|
||||||
|
|
||||||
|
\param x A printf-style format string enclosed in an extra set of parenteses,
|
||||||
|
e.g. PRINT(("%d\n", 0));
|
||||||
|
|
||||||
|
If DEBUG is undefined, does nothing.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def INFORM(x)
|
||||||
|
\brief Directly prints the contents of \a x with no extra formatting or
|
||||||
|
information included (just like a straight \c printf() call). Does so
|
||||||
|
whether \c DEBUG is defined or not.
|
||||||
|
|
||||||
|
\param x A printf-style format string enclosed in an extra set of parenteses,
|
||||||
|
e.g. PRINT(("%d\n", 0));
|
||||||
|
|
||||||
|
I'll say it again: Prints its output regardless to DEBUG being defined or
|
||||||
|
undefined.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def DBG(x)
|
||||||
|
\brief If debug is defined, \a x is passed along to the code and
|
||||||
|
executed unmodified. If \c DEBUG is undefined, the contents of
|
||||||
|
\a x disappear into the ether.
|
||||||
|
|
||||||
|
\param x Damn near anything resembling valid C\C++.
|
||||||
|
*/
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
/*! \def DIE(x)
|
||||||
|
\brief Drops the user into the appropriate debugger (user or kernel)
|
||||||
|
after printing out the handy message bundled in the parenthesee
|
||||||
|
enclosed printf-style format string found in \a x.
|
||||||
|
|
||||||
|
\param x A printf-style format string enclosed in an extra set of parenteses,
|
||||||
|
e.g. PRINT(("%d\n", 0));
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// declarations
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void indent(uint8 tabCount);
|
||||||
|
static void unindent(uint8 tabCount);
|
||||||
|
#if !_KERNEL_MODE
|
||||||
|
static int32 get_tls_handle();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Used to keep the tls handle from being allocated more than once.
|
||||||
|
vint32 tls_spinlock = 0;
|
||||||
|
|
||||||
|
/*! \brief Used to flag whether the tls handle has been allocated yet.
|
||||||
|
|
||||||
|
Not sure if this really needs to be \c volatile or not...
|
||||||
|
*/
|
||||||
|
volatile bool tls_handle_initialized = false;
|
||||||
|
|
||||||
|
//! The tls handle of the tls var used to store indentation info.
|
||||||
|
int32 tls_handle = 0;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// public functions
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*! \brief Returns the current debug indentation level for the
|
||||||
|
current thread.
|
||||||
|
|
||||||
|
NOTE: indentation is currently unsupported for R5::kernelland due
|
||||||
|
to lack of thread local storage support.
|
||||||
|
*/
|
||||||
|
int32
|
||||||
|
_get_debug_indent_level()
|
||||||
|
{
|
||||||
|
#if !_KERNEL_MODE
|
||||||
|
return (int32)tls_get(get_tls_handle());
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// static functions
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*! \brief Increases the current debug indentation level for
|
||||||
|
the current thread by 1.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
indent(uint8 tabCount)
|
||||||
|
{
|
||||||
|
#if !_KERNEL_MODE
|
||||||
|
tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()+tabCount));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Decreases the current debug indentation level for
|
||||||
|
the current thread by 1.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
unindent(uint8 tabCount)
|
||||||
|
{
|
||||||
|
#if !_KERNEL_MODE
|
||||||
|
tls_set(get_tls_handle(), (void*)(_get_debug_indent_level()-tabCount));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !_KERNEL_MODE
|
||||||
|
/*! \brief Returns the thread local storage handle used to store
|
||||||
|
indentation information, allocating the handle first if
|
||||||
|
necessary.
|
||||||
|
*/
|
||||||
|
int32
|
||||||
|
get_tls_handle()
|
||||||
|
{
|
||||||
|
// Init the tls handle if this is the first call.
|
||||||
|
if (!tls_handle_initialized) {
|
||||||
|
if (atomic_or(&tls_spinlock, 1) == 0) {
|
||||||
|
// First one in gets to init
|
||||||
|
tls_handle = tls_allocate();
|
||||||
|
tls_handle_initialized = true;
|
||||||
|
atomic_and(&tls_spinlock, 0);
|
||||||
|
} else {
|
||||||
|
// All others must wait patiently
|
||||||
|
while (!tls_handle_initialized) {
|
||||||
|
snooze(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tls_handle;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \brief Helper class for initializing the debugging output
|
||||||
|
file.
|
||||||
|
|
||||||
|
Note that this hummer isn't threadsafe, but it doesn't really
|
||||||
|
matter for our concerns, since the worst it'll result in is
|
||||||
|
a dangling file descriptor, and that would be in the case of
|
||||||
|
two or more volumes being mounted almost simultaneously...
|
||||||
|
not too big of a worry.
|
||||||
|
*/
|
||||||
|
class DebugOutputFile {
|
||||||
|
public:
|
||||||
|
DebugOutputFile(const char *filename = NULL)
|
||||||
|
: fFile(-1)
|
||||||
|
{
|
||||||
|
Init(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DebugOutputFile() {
|
||||||
|
if (fFile >= 0)
|
||||||
|
close(fFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Init(const char *filename) {
|
||||||
|
if (fFile < 0 && filename)
|
||||||
|
fFile = open(filename, O_RDWR | O_CREAT | O_TRUNC);
|
||||||
|
}
|
||||||
|
|
||||||
|
int File() const { return fFile; }
|
||||||
|
private:
|
||||||
|
int fFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
DebugOutputFile *out = NULL;
|
||||||
|
|
||||||
|
/*! \brief It doesn't appear that the constructor for the global
|
||||||
|
\c out variable is called when built as an R5 filesystem add-on,
|
||||||
|
so this function needs to be called in udf_mount to let the
|
||||||
|
magic happen.
|
||||||
|
*/
|
||||||
|
void initialize_debugger(const char *filename)
|
||||||
|
{
|
||||||
|
#if DEBUG_TO_FILE
|
||||||
|
if (!out) {
|
||||||
|
out = new(nothrow) DebugOutputFile(filename);
|
||||||
|
dbg_printf("out was NULL!\n");
|
||||||
|
} else {
|
||||||
|
DebugOutputFile *temp = out;
|
||||||
|
out = new(nothrow) DebugOutputFile(filename);
|
||||||
|
dbg_printf("out was %p!\n", temp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// dbg_printf, stolen from Ingo's ReiserFS::Debug.cpp.
|
||||||
|
void
|
||||||
|
dbg_printf(const char *format,...)
|
||||||
|
{
|
||||||
|
#if DEBUG_TO_FILE
|
||||||
|
if (!out)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
// no vsnprintf() on PPC
|
||||||
|
#if defined(__INTEL__) && !_KERNEL_MODE
|
||||||
|
vsnprintf(buffer, sizeof(buffer) - 1, format, args);
|
||||||
|
#else
|
||||||
|
vsprintf(buffer, format, args);
|
||||||
|
#endif
|
||||||
|
va_end(args);
|
||||||
|
buffer[sizeof(buffer) - 1] = '\0';
|
||||||
|
write(out->File(), buffer, strlen(buffer));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// DebugHelper
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*! \brief Increases the current indentation level.
|
||||||
|
*/
|
||||||
|
DebugHelper::DebugHelper(const char *className, uint8 tabCount)
|
||||||
|
: fTabCount(tabCount)
|
||||||
|
, fClassName(NULL)
|
||||||
|
{
|
||||||
|
indent(fTabCount);
|
||||||
|
if (className) {
|
||||||
|
fClassName = (char*)malloc(strlen(className)+1);
|
||||||
|
if (fClassName)
|
||||||
|
strcpy(fClassName, className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Decreases the current indentation level.
|
||||||
|
*/
|
||||||
|
DebugHelper::~DebugHelper()
|
||||||
|
{
|
||||||
|
unindent(fTabCount);
|
||||||
|
free(fClassName);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// This version copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
// Initial version copyright (c) 2002 Axel Dörfler, [email protected]
|
||||||
|
// dbg_printf() function copyright (c) 2003 Ingo Weinhold, [email protected]
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_DEBUG_H
|
||||||
|
#define _UDF_DEBUG_H
|
||||||
|
|
||||||
|
/*! \file Debug.h
|
||||||
|
|
||||||
|
Handy debugging macros.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
#ifdef DEBUG
|
||||||
|
//# include <string.h>
|
||||||
|
#endif
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define DEBUG_TO_FILE 0
|
||||||
|
|
||||||
|
# include <stdio.h>
|
||||||
|
#if DEBUG_TO_FILE
|
||||||
|
//# include <stdio.h>
|
||||||
|
# include <stdarg.h>
|
||||||
|
extern "C" int vsprintf(char *s, const char *format, va_list arg);
|
||||||
|
# include <fcntl.h>
|
||||||
|
# define __out dbg_printf
|
||||||
|
void dbg_printf(const char *format,...);
|
||||||
|
void initialize_debugger(const char *filename);
|
||||||
|
#else
|
||||||
|
# if !_KERNEL_MODE
|
||||||
|
//# include <stdio.h>
|
||||||
|
# define __out printf
|
||||||
|
# else
|
||||||
|
//# include <null.h>
|
||||||
|
# define __out dprintf
|
||||||
|
# endif
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <malloc.h>
|
||||||
|
//# define __out printf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "kernel_cpp.h"
|
||||||
|
|
||||||
|
class DebugHelper;
|
||||||
|
|
||||||
|
int32 _get_debug_indent_level();
|
||||||
|
|
||||||
|
/*! \brief Helper class that is allocated on the stack by
|
||||||
|
the \c DEBUG_INIT() macro. On creation, it increases the
|
||||||
|
current indentation level by the amount specified via its
|
||||||
|
constructor's \c tabCount parameter; on destruction, it
|
||||||
|
decreases it.
|
||||||
|
*/
|
||||||
|
class DebugHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DebugHelper(const char *className = NULL, uint8 tabCount = 1);
|
||||||
|
~DebugHelper();
|
||||||
|
|
||||||
|
uint8 TabCount() const { return fTabCount; }
|
||||||
|
const char* ClassName() const { return fClassName; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 fTabCount;
|
||||||
|
char *fClassName;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// NOTE: See Debug.cpp for complete descriptions of the following
|
||||||
|
// debug macros.
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// DEBUG-independent macros
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
#define INFORM(x) { __out("udf: "); __out x; }
|
||||||
|
#if !_KERNEL_MODE
|
||||||
|
# define DIE(x) debugger x
|
||||||
|
#else
|
||||||
|
# define DIE(x) kernel_debugger x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// DEBUG-dependent macros
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
#ifdef DEBUG
|
||||||
|
#if DEBUG_TO_FILE
|
||||||
|
#define INITIALIZE_DEBUGGING_OUTPUT_FILE(filename) initialize_debugger(filename);
|
||||||
|
#else
|
||||||
|
#define INITIALIZE_DEBUGGING_OUTPUT_FILE(filename) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG_INIT_SILENT(className) \
|
||||||
|
DebugHelper _debugHelper(className, 2);
|
||||||
|
|
||||||
|
#define DEBUG_INIT(className) \
|
||||||
|
DEBUG_INIT_SILENT(className); \
|
||||||
|
PRINT(("\n"));
|
||||||
|
|
||||||
|
#define DEBUG_INIT_ETC(className, arguments) \
|
||||||
|
DEBUG_INIT_SILENT(className) \
|
||||||
|
{ \
|
||||||
|
PRINT_INDENT(); \
|
||||||
|
if (_debugHelper.ClassName()) { \
|
||||||
|
__out("udf: %s::%s(", \
|
||||||
|
_debugHelper.ClassName(), __FUNCTION__); \
|
||||||
|
} else { \
|
||||||
|
__out("udf: %s(", __FUNCTION__); \
|
||||||
|
} \
|
||||||
|
__out arguments; \
|
||||||
|
__out("):\n"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DUMP_INIT(className) \
|
||||||
|
DEBUG_INIT_SILENT(className);
|
||||||
|
|
||||||
|
#define PRINT(x) { \
|
||||||
|
{ \
|
||||||
|
PRINT_INDENT(); \
|
||||||
|
if (_debugHelper.ClassName()) { \
|
||||||
|
__out("udf: %s::%s(): ", \
|
||||||
|
_debugHelper.ClassName(), __FUNCTION__); \
|
||||||
|
} else { \
|
||||||
|
__out("udf: %s(): ", __FUNCTION__); \
|
||||||
|
} \
|
||||||
|
__out x; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LPRINT(x) { \
|
||||||
|
{ \
|
||||||
|
PRINT_INDENT(); \
|
||||||
|
if (_debugHelper.ClassName()) { \
|
||||||
|
__out("udf: %s::%s(): line %d: ", \
|
||||||
|
_debugHelper.ClassName(), __FUNCTION__, __LINE__); \
|
||||||
|
} else { \
|
||||||
|
__out("udf: %s(): line %d: ", \
|
||||||
|
__FUNCTION__, __LINE__); \
|
||||||
|
} \
|
||||||
|
__out x; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SIMPLE_PRINT(x) { \
|
||||||
|
{ \
|
||||||
|
__out x; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PRINT_INDENT() { \
|
||||||
|
{ \
|
||||||
|
int32 _level = _get_debug_indent_level(); \
|
||||||
|
for (int32 i = 0; i < _level-_debugHelper.TabCount(); i++) { \
|
||||||
|
__out(" "); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PRINT_DIVIDER() \
|
||||||
|
PRINT_INDENT(); \
|
||||||
|
SIMPLE_PRINT(("------------------------------------------------------------\n"));
|
||||||
|
|
||||||
|
#define DUMP(object) \
|
||||||
|
{ \
|
||||||
|
(object).dump(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PDUMP(objectPointer) \
|
||||||
|
{ \
|
||||||
|
(objectPointer)->dump(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define REPORT_ERROR(error) { \
|
||||||
|
LPRINT(("returning error 0x%lx, `%s'\n", error, strerror(error))); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RETURN_ERROR(error) { \
|
||||||
|
status_t _status = error; \
|
||||||
|
if (_status < (status_t)B_OK) \
|
||||||
|
REPORT_ERROR(_status); \
|
||||||
|
return _status; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RETURN(error) { \
|
||||||
|
status_t _status = error; \
|
||||||
|
if (_status < (status_t)B_OK) { \
|
||||||
|
REPORT_ERROR(_status); \
|
||||||
|
} else if (_status == (status_t)B_OK) { \
|
||||||
|
LPRINT(("returning B_OK\n")); \
|
||||||
|
} else { \
|
||||||
|
LPRINT(("returning 0x%lx = %ld\n", _status, _status)); \
|
||||||
|
} \
|
||||||
|
return _status; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FATAL(x) { \
|
||||||
|
PRINT(("fatal error: ")); SIMPLE_PRINT(x); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DBG(x) x ;
|
||||||
|
|
||||||
|
#else // ifdef DEBUG
|
||||||
|
#define INITIALIZE_DEBUGGING_OUTPUT_FILE(filename) ;
|
||||||
|
#define DEBUG_INIT_SILENT(className) ;
|
||||||
|
#define DEBUG_INIT(className) ;
|
||||||
|
#define DEBUG_INIT_ETC(className, arguments) ;
|
||||||
|
#define DUMP_INIT(className) ;
|
||||||
|
#define PRINT(x) ;
|
||||||
|
#define LPRINT(x) ;
|
||||||
|
#define SIMPLE_PRINT(x) ;
|
||||||
|
#define PRINT_INDENT(x) ;
|
||||||
|
#define PRINT_DIVIDER() ;
|
||||||
|
#define DUMP(object) ;
|
||||||
|
#define PDUMP(objectPointer) ;
|
||||||
|
#define REPORT_ERROR(status) ;
|
||||||
|
#define RETURN_ERROR(status) return status;
|
||||||
|
#define RETURN(status) return status;
|
||||||
|
#define FATAL(x) { __out("udf: fatal error: "); __out x; }
|
||||||
|
#define DBG(x) ;
|
||||||
|
#define DUMP(x) ;
|
||||||
|
#endif // ifdef DEBUG else
|
||||||
|
|
||||||
|
#define TRACE(x) DBG(dprintf x)
|
||||||
|
|
||||||
|
// These macros turn on or off extensive and generally unnecessary
|
||||||
|
// debugging output regarding table of contents parsing
|
||||||
|
//#define WARN(x) (dprintf x)
|
||||||
|
//#define WARN(x)
|
||||||
|
#define WARN(x) DBG(dprintf x)
|
||||||
|
|
||||||
|
#endif // _UDF_DEBUG_H
|
||||||
@@ -0,0 +1,312 @@
|
|||||||
|
#include "UdfString.h"
|
||||||
|
|
||||||
|
#include "ByteOrder.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Converts the given unicode character to utf8.
|
||||||
|
|
||||||
|
\param c The unicode character.
|
||||||
|
\param out Pointer to a C-string of at least 4 characters
|
||||||
|
long into which the output utf8 characters will
|
||||||
|
be written. The string that is pointed to will
|
||||||
|
be incremented to reflect the number of characters
|
||||||
|
written, i.e. if \a out initially points to a pointer
|
||||||
|
to the first character in string named \c str, and
|
||||||
|
the function writes 4 characters to \c str, then
|
||||||
|
upon returning, out will point to a pointer to
|
||||||
|
the fifth character in \c str.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void
|
||||||
|
unicode_to_utf8(uint32 c, char **out)
|
||||||
|
{
|
||||||
|
char *s = *out;
|
||||||
|
|
||||||
|
if (c < 0x80)
|
||||||
|
*(s++) = c;
|
||||||
|
else if (c < 0x800) {
|
||||||
|
*(s++) = 0xc0 | (c>>6);
|
||||||
|
*(s++) = 0x80 | (c & 0x3f);
|
||||||
|
} else if (c < 0x10000) {
|
||||||
|
*(s++) = 0xe0 | (c>>12);
|
||||||
|
*(s++) = 0x80 | ((c>>6) & 0x3f);
|
||||||
|
*(s++) = 0x80 | (c & 0x3f);
|
||||||
|
} else if (c <= 0x10ffff) {
|
||||||
|
*(s++) = 0xf0 | (c>>18);
|
||||||
|
*(s++) = 0x80 | ((c>>12) & 0x3f);
|
||||||
|
*(s++) = 0x80 | ((c>>6) & 0x3f);
|
||||||
|
*(s++) = 0x80 | (c & 0x3f);
|
||||||
|
}
|
||||||
|
*out = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Converts the given utf8 character to 4-byte unicode.
|
||||||
|
|
||||||
|
\param in Pointer to a C-String from which utf8 characters
|
||||||
|
will be read. *in will be incremented to reflect
|
||||||
|
the number of characters read, similarly to the
|
||||||
|
\c out parameter for Udf::unicode_to_utf8().
|
||||||
|
|
||||||
|
\return The 4-byte unicode character, or **in if passed an
|
||||||
|
invalid character, or 0 if passed any NULL pointers.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
uint32
|
||||||
|
utf8_to_unicode(const char **in)
|
||||||
|
{
|
||||||
|
if (!in)
|
||||||
|
return 0;
|
||||||
|
uint8 *bytes = (uint8 *)*in;
|
||||||
|
if (!bytes)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int32 length;
|
||||||
|
uint8 mask = 0x1f;
|
||||||
|
|
||||||
|
switch (bytes[0] & 0xf0) {
|
||||||
|
case 0xc0:
|
||||||
|
case 0xd0: length = 2; break;
|
||||||
|
case 0xe0: length = 3; break;
|
||||||
|
case 0xf0:
|
||||||
|
mask = 0x0f;
|
||||||
|
length = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// valid 1-byte character
|
||||||
|
// and invalid characters
|
||||||
|
(*in)++;
|
||||||
|
return bytes[0];
|
||||||
|
}
|
||||||
|
uint32 c = bytes[0] & mask;
|
||||||
|
int32 i = 1;
|
||||||
|
for (;i < length && (bytes[i] & 0x80) > 0;i++)
|
||||||
|
c = (c << 6) | (bytes[i] & 0x3f);
|
||||||
|
|
||||||
|
if (i < length) {
|
||||||
|
// invalid character
|
||||||
|
(*in)++;
|
||||||
|
return (uint32)bytes[0];
|
||||||
|
}
|
||||||
|
*in += length;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
/*! \brief Creates an empty string object.
|
||||||
|
*/
|
||||||
|
String::String()
|
||||||
|
: fCs0String(NULL)
|
||||||
|
, fUtf8String(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Creates a new String object from the given Utf8 string.
|
||||||
|
*/
|
||||||
|
String::String(const char *utf8)
|
||||||
|
: fCs0String(NULL)
|
||||||
|
, fUtf8String(NULL)
|
||||||
|
{
|
||||||
|
SetTo(utf8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Creates a new String object from the given Cs0 string.
|
||||||
|
*/
|
||||||
|
String::String(const char *cs0, uint32 length)
|
||||||
|
: fCs0String(NULL)
|
||||||
|
, fUtf8String(NULL)
|
||||||
|
{
|
||||||
|
SetTo(cs0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::~String()
|
||||||
|
{
|
||||||
|
DEBUG_INIT("String");
|
||||||
|
|
||||||
|
_Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Assignment from a Utf8 string.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
String::SetTo(const char *utf8)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("String", ("utf8: `%s', strlen(utf8): %ld", utf8,
|
||||||
|
utf8 ? strlen(utf8) : 0));
|
||||||
|
_Clear();
|
||||||
|
if (!utf8) {
|
||||||
|
PRINT(("passed NULL utf8 string\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32 length = strlen(utf8);
|
||||||
|
// First copy the utf8 string
|
||||||
|
fUtf8String = new(nothrow) char[length+1];
|
||||||
|
if (!fUtf8String){
|
||||||
|
PRINT(("new fUtf8String[%ld] allocation failed\n", length+1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(fUtf8String, utf8, length+1);
|
||||||
|
// Next convert to raw 4-byte unicode. Then we'll do some
|
||||||
|
// analysis to figure out if we have any invalid characters,
|
||||||
|
// and whether we can get away with compressed 8-bit unicode,
|
||||||
|
// or have to use burly 16-bit unicode.
|
||||||
|
uint32 *raw = new(nothrow) uint32[length];
|
||||||
|
if (!raw) {
|
||||||
|
PRINT(("new uint32 raw[%ld] temporary string allocation failed\n", length));
|
||||||
|
_Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const char *in = utf8;
|
||||||
|
uint32 rawLength = 0;
|
||||||
|
for (uint32 i = 0; i < length && uint32(in-utf8) < length; i++, rawLength++)
|
||||||
|
raw[i] = utf8_to_unicode(&in);
|
||||||
|
// Check for invalids.
|
||||||
|
uint32 mask = 0xffff0000;
|
||||||
|
for (uint32 i = 0; i < rawLength; i++) {
|
||||||
|
if (raw[i] & mask) {
|
||||||
|
PRINT(("WARNING: utf8 string contained a multi-byte sequence which "
|
||||||
|
"was converted into a unicode character larger than 16-bits; "
|
||||||
|
"character will be converted to an underscore character for "
|
||||||
|
"safety.\n"));
|
||||||
|
raw[i] = '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// See if we can get away with 8-bit compressed unicode
|
||||||
|
mask = 0xffffff00;
|
||||||
|
bool canUse8bit = true;
|
||||||
|
for (uint32 i = 0; i < rawLength; i++) {
|
||||||
|
if (raw[i] & mask) {
|
||||||
|
canUse8bit = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Build our cs0 string
|
||||||
|
if (canUse8bit) {
|
||||||
|
fCs0Length = rawLength+1;
|
||||||
|
fCs0String = new(nothrow) char[fCs0Length];
|
||||||
|
if (fCs0String) {
|
||||||
|
fCs0String[0] = '\x08'; // 8-bit compressed unicode
|
||||||
|
for (uint32 i = 0; i < rawLength; i++)
|
||||||
|
fCs0String[i+1] = raw[i] % 256;
|
||||||
|
} else {
|
||||||
|
PRINT(("new fCs0String[%ld] allocation failed\n", fCs0Length));
|
||||||
|
_Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fCs0Length = rawLength*2+1;
|
||||||
|
fCs0String = new(nothrow) char[fCs0Length];
|
||||||
|
if (fCs0String) {
|
||||||
|
uint32 pos = 0;
|
||||||
|
fCs0String[pos++] = '\x10'; // 16-bit unicode
|
||||||
|
for (uint32 i = 0; i < rawLength; i++) {
|
||||||
|
// 16-bit unicode chars must be written big endian
|
||||||
|
uint16 value = uint16(raw[i]);
|
||||||
|
uint8 high = uint8(value >> 8 & 0xff);
|
||||||
|
uint8 low = uint8(value & 0xff);
|
||||||
|
fCs0String[pos++] = high;
|
||||||
|
fCs0String[pos++] = low;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PRINT(("new fCs0String[%ld] allocation failed\n", fCs0Length));
|
||||||
|
_Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clean up
|
||||||
|
delete [] raw;
|
||||||
|
raw = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Assignment from a Cs0 string.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
String::SetTo(const char *cs0, uint32 length)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("String", ("cs0: %p, length: %ld", cs0, length));
|
||||||
|
|
||||||
|
_Clear();
|
||||||
|
if (length == 0)
|
||||||
|
return;
|
||||||
|
if (!cs0) {
|
||||||
|
PRINT(("passed NULL cs0 string\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First copy the Cs0 string and length
|
||||||
|
fCs0String = new(nothrow) char[length];
|
||||||
|
if (fCs0String) {
|
||||||
|
memcpy(fCs0String, cs0, length);
|
||||||
|
fCs0Length = length;
|
||||||
|
} else {
|
||||||
|
PRINT(("new fCs0String[%ld] allocation failed\n", length));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now convert to utf8
|
||||||
|
|
||||||
|
// The first byte of the CS0 string is the compression ID.
|
||||||
|
// - 8: 1 byte characters
|
||||||
|
// - 16: 2 byte, big endian characters
|
||||||
|
// - 254: "CS0 expansion is empty and unique", 1 byte characters
|
||||||
|
// - 255: "CS0 expansion is empty and unique", 2 byte, big endian characters
|
||||||
|
PRINT(("compression ID: %d\n", cs0[0]));
|
||||||
|
switch (reinterpret_cast<const uint8*>(cs0)[0]) {
|
||||||
|
case 8:
|
||||||
|
case 254:
|
||||||
|
{
|
||||||
|
const uint8 *inputString = reinterpret_cast<const uint8*>(&(cs0[1]));
|
||||||
|
int32 maxLength = length-1; // Max length of input string in uint8 characters
|
||||||
|
int32 allocationLength = maxLength*2+1; // Need at most 2 utf8 chars per uint8 char
|
||||||
|
fUtf8String = new(nothrow) char[allocationLength];
|
||||||
|
if (fUtf8String) {
|
||||||
|
char *outputString = fUtf8String;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < maxLength && inputString[i]; i++) {
|
||||||
|
unicode_to_utf8(inputString[i], &outputString);
|
||||||
|
}
|
||||||
|
outputString[0] = 0;
|
||||||
|
} else {
|
||||||
|
PRINT(("new fUtf8String[%ld] allocation failed\n", allocationLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
case 255:
|
||||||
|
{
|
||||||
|
const uint16 *inputString = reinterpret_cast<const uint16*>(&(cs0[1]));
|
||||||
|
int32 maxLength = (length-1) / 2; // Max length of input string in uint16 characters
|
||||||
|
int32 allocationLength = maxLength*3+1; // Need at most 3 utf8 chars per uint16 char
|
||||||
|
fUtf8String = new(nothrow) char[allocationLength];
|
||||||
|
if (fUtf8String) {
|
||||||
|
char *outputString = fUtf8String;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < maxLength && inputString[i]; i++) {
|
||||||
|
unicode_to_utf8(B_BENDIAN_TO_HOST_INT16(inputString[i]), &outputString);
|
||||||
|
}
|
||||||
|
outputString[0] = 0;
|
||||||
|
} else {
|
||||||
|
PRINT(("new fUtf8String[%ld] allocation failed\n", allocationLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
PRINT(("invalid compression id!\n"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
String::_Clear()
|
||||||
|
{
|
||||||
|
DEBUG_INIT("String");
|
||||||
|
|
||||||
|
delete [] fCs0String;
|
||||||
|
fCs0String = NULL;
|
||||||
|
delete [] fUtf8String;
|
||||||
|
fUtf8String = NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef _UDF_STRING_H
|
||||||
|
#define _UDF_STRING_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "kernel_cpp.h"
|
||||||
|
|
||||||
|
#include "Array.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
/*! \brief String class that takes as input either a UTF8 string or a
|
||||||
|
CS0 unicode string and then provides access to said string in both
|
||||||
|
formats.
|
||||||
|
|
||||||
|
For CS0 info, see: ECMA-167 1/7.2.2 (not very helpful), UDF-2.01 2.1.1
|
||||||
|
*/
|
||||||
|
class String {
|
||||||
|
public:
|
||||||
|
String();
|
||||||
|
String(const char *utf8);
|
||||||
|
String(const char *cs0, uint32 length);
|
||||||
|
template <uint32 length>
|
||||||
|
String(const array<char, length> &dString);
|
||||||
|
~String();
|
||||||
|
|
||||||
|
void SetTo(const char *utf8);
|
||||||
|
void SetTo(const char *cs0, uint32 length);
|
||||||
|
template <uint32 length>
|
||||||
|
void SetTo(const array<char, length> &dString);
|
||||||
|
|
||||||
|
template <uint32 length>
|
||||||
|
String& operator=(const array<char, length> &dString);
|
||||||
|
|
||||||
|
const char* Cs0() const { return fCs0String; }
|
||||||
|
const char* Utf8() const { return fUtf8String; }
|
||||||
|
uint32 Cs0Length() const { return fCs0Length; }
|
||||||
|
uint32 Utf8Length() const { return fUtf8String ? strlen(fUtf8String) : 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _Clear();
|
||||||
|
|
||||||
|
char *fCs0String;
|
||||||
|
uint32 fCs0Length;
|
||||||
|
char *fUtf8String;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief Creates a new String object from the given d-string.
|
||||||
|
*/
|
||||||
|
template <uint32 length>
|
||||||
|
String::String(const array<char, length> &dString)
|
||||||
|
: fCs0String(NULL)
|
||||||
|
, fUtf8String(NULL)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("String", ("dString.length(): %ld", dString.length()));
|
||||||
|
|
||||||
|
SetTo(dString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Assignment from a d-string.
|
||||||
|
|
||||||
|
The last byte of a d-string specifies the data length of the
|
||||||
|
enclosed Cs0 string.
|
||||||
|
*/
|
||||||
|
template <uint32 length>
|
||||||
|
void
|
||||||
|
String::SetTo(const array<char, length> &dString)
|
||||||
|
{
|
||||||
|
uint8 dataLength = dString.length() == 0
|
||||||
|
? 0
|
||||||
|
: reinterpret_cast<const uint8*>(dString.data)[dString.length()-1];
|
||||||
|
if (dataLength == 0
|
||||||
|
|| dataLength == 1 /* technically illegal, but... */)
|
||||||
|
{
|
||||||
|
SetTo(NULL);
|
||||||
|
} else {
|
||||||
|
if (dataLength > dString.length()-1)
|
||||||
|
dataLength = dString.length()-1;
|
||||||
|
SetTo(reinterpret_cast<const char*>(dString.data), dataLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Assignment from a d-string.
|
||||||
|
*/
|
||||||
|
template <uint32 length>
|
||||||
|
String&
|
||||||
|
String::operator=(const array<char, length> &dString)
|
||||||
|
{
|
||||||
|
SetTo(dString);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}; // namespace UDF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _UDF_STRING_H
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,173 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*! \file Utils.cpp
|
||||||
|
|
||||||
|
Miscellaneous Udf utility functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#ifndef _IMPEXP_KERNEL
|
||||||
|
# define _IMPEXP_KERNEL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int32 timezone_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
long_address
|
||||||
|
to_long_address(vnode_id id, uint32 length)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC(NULL, ("vnode_id: %Ld (0x%Lx), length: %ld", id, id, length));
|
||||||
|
long_address result;
|
||||||
|
result.set_block((id >> 16) & 0xffffffff);
|
||||||
|
result.set_partition(id & 0xffff);
|
||||||
|
result.set_length(length);
|
||||||
|
DUMP(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
vnode_id
|
||||||
|
to_vnode_id(long_address address)
|
||||||
|
{
|
||||||
|
DEBUG_INIT(NULL);
|
||||||
|
vnode_id result = address.block();
|
||||||
|
result <<= 16;
|
||||||
|
result |= address.partition();
|
||||||
|
PRINT(("block: %ld, 0x%lx\n", address.block(), address.block()));
|
||||||
|
PRINT(("partition: %d, 0x%x\n", address.partition(), address.partition()));
|
||||||
|
PRINT(("length: %ld, 0x%lx\n", address.length(), address.length()));
|
||||||
|
PRINT(("vnode_id: %Ld, 0x%Lx\n", result, result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t
|
||||||
|
make_time(timestamp ×tamp)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC(NULL, ("timestamp: (tnt: 0x%x, type: %d, timezone: %d = 0x%x, year: %d, "
|
||||||
|
"month: %d, day: %d, hour: %d, minute: %d, second: %d)", timestamp.type_and_timezone(),
|
||||||
|
timestamp.type(), timestamp.timezone(),
|
||||||
|
timestamp.timezone(),timestamp.year(),
|
||||||
|
timestamp.month(), timestamp.day(), timestamp.hour(), timestamp.minute(), timestamp.second()));
|
||||||
|
|
||||||
|
time_t result = 0;
|
||||||
|
|
||||||
|
if (timestamp.year() >= 1970) {
|
||||||
|
const int monthLengths[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||||
|
|
||||||
|
int year = timestamp.year();
|
||||||
|
int month = timestamp.month();
|
||||||
|
int day = timestamp.day();
|
||||||
|
int hour = timestamp.hour();
|
||||||
|
int minute = timestamp.minute();
|
||||||
|
int second = timestamp.second();
|
||||||
|
|
||||||
|
// Range check the timezone offset, then round it down
|
||||||
|
// to the nearest hour, since no one I know treats timezones
|
||||||
|
// with a per-minute granularity, and none of the other OSes
|
||||||
|
// I've looked at appear to either.
|
||||||
|
int timezone_offset = timestamp.timezone();
|
||||||
|
if (-1440 > timezone_offset || timezone_offset > 1440)
|
||||||
|
timezone_offset = 0;
|
||||||
|
timezone_offset -= timezone_offset % 60;
|
||||||
|
|
||||||
|
int previousLeapYears = (year - 1968) / 4;
|
||||||
|
bool isLeapYear = (year - 1968) % 4 == 0;
|
||||||
|
if (isLeapYear)
|
||||||
|
--previousLeapYears;
|
||||||
|
|
||||||
|
// Years to days
|
||||||
|
result = (year - 1970) * 365 + previousLeapYears;
|
||||||
|
// Months to days
|
||||||
|
for (int i = 0; i < month-1; i++) {
|
||||||
|
result += monthLengths[i];
|
||||||
|
}
|
||||||
|
if (month > 2 && isLeapYear)
|
||||||
|
++result;
|
||||||
|
// Days to hours
|
||||||
|
result = (result + day - 1) * 24;
|
||||||
|
// Hours to minutes
|
||||||
|
result = (result + hour) * 60 + timezone_offset;
|
||||||
|
// Minutes to seconds
|
||||||
|
result = (result + minute) * 60 + second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Calculates the block shift amount for the given
|
||||||
|
block size, which must be a positive power of 2.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
Udf::get_block_shift(uint32 blockSize, uint32 &blockShift)
|
||||||
|
{
|
||||||
|
if (blockSize == 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
uint32 bitCount = 0;
|
||||||
|
uint32 result = 0;
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
// Zero out all bits except bit i
|
||||||
|
uint32 block = blockSize & (uint32(1) << i);
|
||||||
|
if (block) {
|
||||||
|
if (++bitCount > 1) {
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
} else {
|
||||||
|
result = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockShift = result;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Returns "true" if \a value is true, "false" otherwise.
|
||||||
|
*/
|
||||||
|
const char*
|
||||||
|
Udf::bool_to_string(bool value)
|
||||||
|
{
|
||||||
|
return value ? "true" : "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Takes an overloaded ssize_t return value like those returned
|
||||||
|
by BFile::Read() and friends, as well as an expected number of bytes,
|
||||||
|
and returns B_OK if the byte counts match, or the appropriate error
|
||||||
|
code otherwise.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
Udf::check_size_error(ssize_t bytesReturned, ssize_t bytesExpected)
|
||||||
|
{
|
||||||
|
return bytesReturned == bytesExpected
|
||||||
|
? B_OK
|
||||||
|
: (bytesReturned >= 0 ? B_IO_ERROR : status_t(bytesReturned));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Calculates the UDF crc checksum for the given byte stream.
|
||||||
|
|
||||||
|
Based on crc code from UDF-2.50 6.5, as permitted.
|
||||||
|
|
||||||
|
\param data Pointer to the byte stream.
|
||||||
|
\param length Length of the byte stream in bytes.
|
||||||
|
|
||||||
|
\return The crc checksum, or 0 if an error occurred.
|
||||||
|
*/
|
||||||
|
uint16
|
||||||
|
Udf::calculate_crc(uint8 *data, uint16 length)
|
||||||
|
{
|
||||||
|
uint16 crc = 0;
|
||||||
|
if (data) {
|
||||||
|
for ( ; length > 0; length--, data++)
|
||||||
|
crc = Udf::kCrcTable[(crc >> 8 ^ *data) & 0xff] ^ (crc << 8);
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Udf
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_UTILS_H
|
||||||
|
#define _UDF_UTILS_H
|
||||||
|
|
||||||
|
/*! \file Utils.h
|
||||||
|
|
||||||
|
Miscellaneous Udf utility functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IMPEXP_KERNEL
|
||||||
|
# define _IMPEXP_KERNEL
|
||||||
|
#endif
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include "fsproto.h"
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "UdfStructures.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
long_address to_long_address(vnode_id id, uint32 length = 0);
|
||||||
|
|
||||||
|
vnode_id to_vnode_id(long_address address);
|
||||||
|
|
||||||
|
time_t make_time(timestamp ×tamp);
|
||||||
|
|
||||||
|
status_t get_block_shift(uint32 blockSize, uint32 &blockShift);
|
||||||
|
|
||||||
|
const char* bool_to_string(bool value);
|
||||||
|
|
||||||
|
status_t check_size_error(ssize_t bytesReturned, ssize_t bytesExpected);
|
||||||
|
|
||||||
|
uint16 calculate_crc(uint8 *data, uint16 length);
|
||||||
|
|
||||||
|
} // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_UTILS_H
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#include "VirtualPartition.h"
|
||||||
|
|
||||||
|
#define B_NOT_IMPLEMENTED B_ERROR
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
/*! \brief Creates a new VirtualPartition object.
|
||||||
|
|
||||||
|
VirtualPartition objects require a valid VAT to be found on disc. This involves
|
||||||
|
looking up the last recorded sector on the disc (via the "READ CD RECORDED
|
||||||
|
CAPACITY" SCSI-MMC call (code 0x25)), which should contain the file entry for
|
||||||
|
the VAT. Once found, the VAT can be loaded and accessed like a normal file.
|
||||||
|
*/
|
||||||
|
VirtualPartition::VirtualPartition(PhysicalPartition &physicalPartition)
|
||||||
|
: fPhysicalPartition(physicalPartition)
|
||||||
|
{
|
||||||
|
// Find VAT
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Destroys the VirtualPartition object.
|
||||||
|
*/
|
||||||
|
VirtualPartition::~VirtualPartition()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Maps the given logical block to a physical block on disc.
|
||||||
|
|
||||||
|
The given logical block is indexed into the VAT. If a corresponding
|
||||||
|
mapped block exists, that block is mapped to a physical block via the
|
||||||
|
VirtualPartition object's physical partition.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
VirtualPartition::MapBlock(uint32 logicalBlock, off_t &physicalBlock)
|
||||||
|
{
|
||||||
|
return B_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Returns the initialization status of the object.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
VirtualPartition::InitCheck()
|
||||||
|
{
|
||||||
|
return B_NO_INIT;
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_VIRTUAL_PARTITION_H
|
||||||
|
#define _UDF_VIRTUAL_PARTITION_H
|
||||||
|
|
||||||
|
/*! \file VirtualPartition.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kernel_cpp.h>
|
||||||
|
|
||||||
|
#include "Partition.h"
|
||||||
|
#include "PhysicalPartition.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
/*! \brief Type 2 virtual partition
|
||||||
|
|
||||||
|
VirtualPartitions add an extra layer of indirection between logical
|
||||||
|
block numbers and physical block numbers, allowing the underlying
|
||||||
|
physical block numbers to be changed without changing the original
|
||||||
|
references to (virtual) logical block numbers.
|
||||||
|
|
||||||
|
Note that VirtualPartitions should be found only on sequentially written
|
||||||
|
media such as CD-R, per UDF-2.01 2.2.10.
|
||||||
|
|
||||||
|
See also UDF-2.01 2.2.8, UDF-2.01 2.2.10
|
||||||
|
*/
|
||||||
|
class VirtualPartition : public Partition {
|
||||||
|
public:
|
||||||
|
VirtualPartition(PhysicalPartition &physicalPartition);
|
||||||
|
virtual ~VirtualPartition();
|
||||||
|
virtual status_t MapBlock(uint32 logicalBlock, off_t &physicalBlock);
|
||||||
|
|
||||||
|
status_t InitCheck();
|
||||||
|
private:
|
||||||
|
PhysicalPartition fPhysicalPartition;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_VIRTUAL_PARTITION_H
|
||||||
@@ -0,0 +1,349 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
// Mad props to Axel Dörfler and his BFS implementation, from which
|
||||||
|
// this UDF implementation draws much influence (and a little code :-P).
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
#include "Volume.h"
|
||||||
|
|
||||||
|
#include "Icb.h"
|
||||||
|
#include "MemoryChunk.h"
|
||||||
|
#include "PhysicalPartition.h"
|
||||||
|
#include "Recognition.h"
|
||||||
|
|
||||||
|
using namespace Udf;
|
||||||
|
|
||||||
|
/*! \brief Creates an unmounted volume with the given id.
|
||||||
|
*/
|
||||||
|
Volume::Volume(nspace_id id)
|
||||||
|
: fId(id)
|
||||||
|
, fDevice(-1)
|
||||||
|
, fMounted(false)
|
||||||
|
, fOffset(0)
|
||||||
|
, fLength(0)
|
||||||
|
, fBlockSize(0)
|
||||||
|
, fBlockShift(0)
|
||||||
|
, fRootIcb(NULL)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < UDF_MAX_PARTITION_MAPS; i++)
|
||||||
|
fPartitions[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Volume::~Volume()
|
||||||
|
{
|
||||||
|
_Unset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Attempts to mount the given device.
|
||||||
|
|
||||||
|
\param volumeStart The block on the given device whereat the volume begins.
|
||||||
|
\param volumeLength The block length of the volume on the given device.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
Volume::Mount(const char *deviceName, off_t offset, off_t length,
|
||||||
|
uint32 blockSize, uint32 flags)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("Volume",
|
||||||
|
("deviceName: `%s', offset: %Ld, length: %Ld, blockSize: %ld, "
|
||||||
|
"flags: %ld", deviceName, offset, length, blockSize, flags));
|
||||||
|
if (!deviceName)
|
||||||
|
RETURN(B_BAD_VALUE);
|
||||||
|
if (Mounted()) {
|
||||||
|
// Already mounted, thank you for asking
|
||||||
|
RETURN(B_BUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the device read only
|
||||||
|
int device = open(deviceName, O_RDONLY);
|
||||||
|
if (device < B_OK)
|
||||||
|
RETURN(device);
|
||||||
|
|
||||||
|
status_t error = B_OK;
|
||||||
|
|
||||||
|
// If the device is actually a normal file, try to disable the cache
|
||||||
|
// for the file in the parent filesystem
|
||||||
|
#if _KERNEL_MODE
|
||||||
|
struct stat stat;
|
||||||
|
error = fstat(device, &stat) < 0 ? B_ERROR : B_OK;
|
||||||
|
if (!error) {
|
||||||
|
if (stat.st_mode & S_IFREG && ioctl(device, IOCTL_FILE_UNCACHED_IO, NULL) < 0) {
|
||||||
|
DIE(("Unable to disable cache of underlying file system.\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
logical_volume_descriptor logicalVolumeDescriptor;
|
||||||
|
partition_descriptor partitionDescriptors[Udf::kMaxPartitionDescriptors];
|
||||||
|
uint8 partitionDescriptorCount;
|
||||||
|
uint32 blockShift;
|
||||||
|
|
||||||
|
// Run through the volume recognition and descriptor sequences to
|
||||||
|
// see if we have a potentially valid UDF volume on our hands
|
||||||
|
error = udf_recognize(device, offset, length, blockSize, blockShift,
|
||||||
|
logicalVolumeDescriptor, partitionDescriptors,
|
||||||
|
partitionDescriptorCount);
|
||||||
|
|
||||||
|
// Set up the block cache
|
||||||
|
if (!error)
|
||||||
|
error = init_cache_for_device(device, length);
|
||||||
|
|
||||||
|
int physicalCount = 0;
|
||||||
|
int virtualCount = 0;
|
||||||
|
int sparableCount = 0;
|
||||||
|
int metadataCount = 0;
|
||||||
|
|
||||||
|
// Set up the partitions
|
||||||
|
if (!error) {
|
||||||
|
// Set up physical and sparable partitions first
|
||||||
|
int offset = 0;
|
||||||
|
for (uint8 i = 0; i < logicalVolumeDescriptor.partition_map_count()
|
||||||
|
&& !error; i++)
|
||||||
|
{
|
||||||
|
uint8 *maps = logicalVolumeDescriptor.partition_maps();
|
||||||
|
partition_map_header *header =
|
||||||
|
reinterpret_cast<partition_map_header*>(maps+offset);
|
||||||
|
PRINT(("partition map %d (type %d):\n", i, header->type()));
|
||||||
|
if (header->type() == 1) {
|
||||||
|
PRINT(("map type: physical\n"));
|
||||||
|
physical_partition_map* map =
|
||||||
|
reinterpret_cast<physical_partition_map*>(header);
|
||||||
|
// Find the corresponding partition descriptor
|
||||||
|
partition_descriptor *descriptor = NULL;
|
||||||
|
for (uint8 j = 0; j < partitionDescriptorCount; j++) {
|
||||||
|
if (map->partition_number() ==
|
||||||
|
partitionDescriptors[j].partition_number())
|
||||||
|
{
|
||||||
|
descriptor = &partitionDescriptors[j];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Create and add the partition
|
||||||
|
if (descriptor) {
|
||||||
|
PhysicalPartition *partition = new(nothrow) PhysicalPartition(
|
||||||
|
map->partition_number(),
|
||||||
|
descriptor->start(),
|
||||||
|
descriptor->length());
|
||||||
|
error = partition ? B_OK : B_NO_MEMORY;
|
||||||
|
if (!error) {
|
||||||
|
PRINT(("Adding PhysicalPartition(number: %d, start: %ld, "
|
||||||
|
"length: %ld)\n", map->partition_number(),
|
||||||
|
descriptor->start(), descriptor->length()));
|
||||||
|
error = _SetPartition(i, partition);
|
||||||
|
if (!error)
|
||||||
|
physicalCount++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PRINT(("no matching partition descriptor found!\n"));
|
||||||
|
error = B_ERROR;
|
||||||
|
}
|
||||||
|
} else if (header->type() == 2) {
|
||||||
|
// Figure out what kind of type 2 partition map we have based
|
||||||
|
// on the type identifier
|
||||||
|
const entity_id &typeId = header->partition_type_id();
|
||||||
|
DUMP(typeId);
|
||||||
|
DUMP(kSparablePartitionMapId);
|
||||||
|
if (typeId.matches(kVirtualPartitionMapId)) {
|
||||||
|
PRINT(("map type: virtual\n"));
|
||||||
|
virtual_partition_map* map =
|
||||||
|
reinterpret_cast<virtual_partition_map*>(header);
|
||||||
|
virtualCount++;
|
||||||
|
(void)map; // kill the warning for now
|
||||||
|
} else if (typeId.matches(kSparablePartitionMapId)) {
|
||||||
|
PRINT(("map type: sparable\n"));
|
||||||
|
sparable_partition_map* map =
|
||||||
|
reinterpret_cast<sparable_partition_map*>(header);
|
||||||
|
sparableCount++;
|
||||||
|
(void)map; // kill the warning for now
|
||||||
|
} else if (typeId.matches(kMetadataPartitionMapId)) {
|
||||||
|
PRINT(("map type: metadata\n"));
|
||||||
|
metadata_partition_map* map =
|
||||||
|
reinterpret_cast<metadata_partition_map*>(header);
|
||||||
|
metadataCount++;
|
||||||
|
(void)map; // kill the warning for now
|
||||||
|
} else {
|
||||||
|
PRINT(("map type: unrecognized (`%.23s')\n",
|
||||||
|
typeId.identifier()));
|
||||||
|
error = B_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PRINT(("Invalid partition type %d found!\n", header->type()));
|
||||||
|
error = B_ERROR;
|
||||||
|
}
|
||||||
|
offset += header->length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do some checking as to what sorts of partitions we've actually found.
|
||||||
|
if (!error) {
|
||||||
|
error = (physicalCount == 1 && virtualCount == 0
|
||||||
|
&& sparableCount == 0 && metadataCount == 0)
|
||||||
|
|| (physicalCount == 2 && virtualCount == 0
|
||||||
|
&& sparableCount == 0 && metadataCount == 0)
|
||||||
|
? B_OK : B_ERROR;
|
||||||
|
if (error) {
|
||||||
|
PRINT(("Invalid partition layout found:\n"));
|
||||||
|
PRINT((" physical partitions: %d\n", physicalCount));
|
||||||
|
PRINT((" virtual partitions: %d\n", virtualCount));
|
||||||
|
PRINT((" sparable partitions: %d\n", sparableCount));
|
||||||
|
PRINT((" metadata partitions: %d\n", metadataCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're now going to start creating Icb's, which will expect
|
||||||
|
// certain parts of the volume to be initialized properly. Thus,
|
||||||
|
// we initialize those parts here.
|
||||||
|
if (!error) {
|
||||||
|
fDevice = device;
|
||||||
|
fOffset = offset;
|
||||||
|
fLength = length;
|
||||||
|
fBlockSize = blockSize;
|
||||||
|
fBlockShift = blockShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point we've found a valid set of volume descriptors and
|
||||||
|
// our partitions are all set up. We now need to investigate the file
|
||||||
|
// set descriptor pointed to by the logical volume descriptor.
|
||||||
|
if (!error) {
|
||||||
|
MemoryChunk chunk(logicalVolumeDescriptor.file_set_address().length());
|
||||||
|
|
||||||
|
error = chunk.InitCheck();
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
off_t address;
|
||||||
|
// Read in the file set descriptor
|
||||||
|
error = MapBlock(logicalVolumeDescriptor.file_set_address(),
|
||||||
|
&address);
|
||||||
|
if (!error)
|
||||||
|
address <<= blockShift;
|
||||||
|
if (!error) {
|
||||||
|
ssize_t bytesRead = read_pos(device, address, chunk.Data(),
|
||||||
|
blockSize);
|
||||||
|
if (bytesRead != ssize_t(blockSize)) {
|
||||||
|
error = B_IO_ERROR;
|
||||||
|
PRINT(("read_pos(pos:%Ld, len:%ld) failed with: 0x%lx\n",
|
||||||
|
address, blockSize, bytesRead));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// See if it's valid, and if so, create the root icb
|
||||||
|
if (!error) {
|
||||||
|
file_set_descriptor *fileSet =
|
||||||
|
reinterpret_cast<file_set_descriptor*>(chunk.Data());
|
||||||
|
PDUMP(fileSet);
|
||||||
|
error = fileSet->tag().id() == TAGID_FILE_SET_DESCRIPTOR
|
||||||
|
? B_OK : B_ERROR;
|
||||||
|
if (!error)
|
||||||
|
error = fileSet->tag().init_check(
|
||||||
|
logicalVolumeDescriptor.file_set_address().block());
|
||||||
|
if (!error) {
|
||||||
|
PDUMP(fileSet);
|
||||||
|
fRootIcb = new(nothrow) Icb(this, fileSet->root_directory_icb());
|
||||||
|
error = fRootIcb ? fRootIcb->InitCheck() : B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
if (!error) {
|
||||||
|
error = new_vnode(Id(), RootIcb()->Id(), (void*)RootIcb());
|
||||||
|
if (error) {
|
||||||
|
PRINT(("Error creating vnode for root icb! "
|
||||||
|
"error = 0x%lx, `%s'\n", error,
|
||||||
|
strerror(error)));
|
||||||
|
// Clean up the icb we created, since _Unset()
|
||||||
|
// won't do this for us.
|
||||||
|
delete fRootIcb;
|
||||||
|
fRootIcb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've made it this far, we're good to go; set the volume
|
||||||
|
// name and then flag that we're mounted. On the other hand, if
|
||||||
|
// an error occurred, we need to clean things up.
|
||||||
|
if (!error) {
|
||||||
|
fName.SetTo(logicalVolumeDescriptor.logical_volume_identifier());
|
||||||
|
fMounted = true;
|
||||||
|
} else {
|
||||||
|
_Unset();
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
Volume::Name() const {
|
||||||
|
return fName.Utf8();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Maps the given logical block to a physical block.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
Volume::MapBlock(long_address address, off_t *mappedBlock)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC("Volume",
|
||||||
|
("partition: %d, block: %ld, mappedBlock: %p",
|
||||||
|
address.partition(), address.block(), mappedBlock));
|
||||||
|
status_t error = mappedBlock ? B_OK : B_BAD_VALUE;
|
||||||
|
if (!error) {
|
||||||
|
Partition *partition = _GetPartition(address.partition());
|
||||||
|
error = partition ? B_OK : B_BAD_ADDRESS;
|
||||||
|
if (!error)
|
||||||
|
error = partition->MapBlock(address.block(), *mappedBlock);
|
||||||
|
}
|
||||||
|
RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Unsets the volume and deletes any partitions.
|
||||||
|
|
||||||
|
Does *not* delete the root icb object.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Volume::_Unset()
|
||||||
|
{
|
||||||
|
DEBUG_INIT("Volume");
|
||||||
|
fId = 0;
|
||||||
|
if (fDevice >= 0) {
|
||||||
|
remove_cached_device_blocks(fDevice, NO_WRITES);
|
||||||
|
close(fDevice);
|
||||||
|
}
|
||||||
|
fDevice = -1;
|
||||||
|
fMounted = false;
|
||||||
|
fOffset = 0;
|
||||||
|
fLength = 0;
|
||||||
|
fBlockSize = 0;
|
||||||
|
fBlockShift = 0;
|
||||||
|
fName.SetTo("", 0);
|
||||||
|
// delete our partitions
|
||||||
|
for (int i = 0; i < UDF_MAX_PARTITION_MAPS; i++)
|
||||||
|
_SetPartition(i, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Sets the partition associated with the given number after
|
||||||
|
deleting any previously associated partition.
|
||||||
|
|
||||||
|
\param number The partition number (should be the same as the index
|
||||||
|
into the lvd's partition map array).
|
||||||
|
\param partition The new partition (may be NULL).
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
Volume::_SetPartition(uint number, Partition *partition)
|
||||||
|
{
|
||||||
|
status_t error = number < UDF_MAX_PARTITION_MAPS
|
||||||
|
? B_OK : B_BAD_VALUE;
|
||||||
|
if (!error) {
|
||||||
|
delete fPartitions[number];
|
||||||
|
fPartitions[number] = partition;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Returns the partition associated with the given number, or
|
||||||
|
NULL if no such partition exists or the number is invalid.
|
||||||
|
*/
|
||||||
|
Udf::Partition*
|
||||||
|
Volume::_GetPartition(uint number)
|
||||||
|
{
|
||||||
|
return (number < UDF_MAX_PARTITION_MAPS)
|
||||||
|
? fPartitions[number] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
// Mad props to Axel Dörfler and his BFS implementation, from which
|
||||||
|
// this UDF implementation draws much influence (and a little code :-P).
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
#ifndef _UDF_VOLUME_H
|
||||||
|
#define _UDF_VOLUME_H
|
||||||
|
|
||||||
|
/*! \file Volume.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#ifndef _IMPEXP_KERNEL
|
||||||
|
# define _IMPEXP_KERNEL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include "fsproto.h"
|
||||||
|
#ifdef COMPILE_FOR_R5
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "kernel_cpp.h"
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
|
||||||
|
#include "UdfString.h"
|
||||||
|
#include "UdfStructures.h"
|
||||||
|
#include "Partition.h"
|
||||||
|
|
||||||
|
namespace Udf {
|
||||||
|
|
||||||
|
class Icb;
|
||||||
|
|
||||||
|
class Volume {
|
||||||
|
public:
|
||||||
|
// Construction/destruction
|
||||||
|
Volume(nspace_id id);
|
||||||
|
~Volume();
|
||||||
|
|
||||||
|
// Mounting/unmounting
|
||||||
|
status_t Mount(const char *deviceName, off_t offset, off_t length,
|
||||||
|
uint32 blockSize, uint32 flags);
|
||||||
|
status_t Unmount();
|
||||||
|
|
||||||
|
// Address mapping
|
||||||
|
status_t MapBlock(long_address address, off_t *mappedBlock);
|
||||||
|
status_t MapExtent(long_address logicalExtent, extent_address &physicalExtent);
|
||||||
|
|
||||||
|
// Miscellaneous info
|
||||||
|
const char *Name() const;
|
||||||
|
int Device() const { return fDevice; }
|
||||||
|
nspace_id Id() const { return fId; }
|
||||||
|
off_t Offset() const { return fOffset; }
|
||||||
|
off_t Length() const { return fLength; }
|
||||||
|
uint32 BlockSize() const { return fBlockSize; }
|
||||||
|
uint32 BlockShift() const { return fBlockShift; }
|
||||||
|
bool Mounted() const { return fMounted; }
|
||||||
|
Icb* RootIcb() { return fRootIcb; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Volume(); // unimplemented
|
||||||
|
Volume(const Volume &ref); // unimplemented
|
||||||
|
Volume& operator=(const Volume &ref); // unimplemented
|
||||||
|
|
||||||
|
void _Unset();
|
||||||
|
|
||||||
|
status_t _SetPartition(uint number, Partition *partition);
|
||||||
|
Partition* _GetPartition(uint number);
|
||||||
|
|
||||||
|
private:
|
||||||
|
nspace_id fId;
|
||||||
|
int fDevice;
|
||||||
|
bool fMounted;
|
||||||
|
off_t fOffset;
|
||||||
|
off_t fLength;
|
||||||
|
uint32 fBlockSize;
|
||||||
|
uint32 fBlockShift;
|
||||||
|
Partition *fPartitions[UDF_MAX_PARTITION_MAPS];
|
||||||
|
Icb *fRootIcb; // Destroyed by vfs via callback to release_node()
|
||||||
|
String fName;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Udf
|
||||||
|
|
||||||
|
#endif // _UDF_VOLUME_H
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||||
|
This file may be used under the terms of the Be Sample Code License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CACHE_H_
|
||||||
|
#define _CACHE_H_
|
||||||
|
|
||||||
|
#include <BeBuild.h>
|
||||||
|
|
||||||
|
typedef struct hash_ent {
|
||||||
|
int dev;
|
||||||
|
off_t bnum;
|
||||||
|
off_t hash_val;
|
||||||
|
void *data;
|
||||||
|
struct hash_ent *next;
|
||||||
|
} hash_ent;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct hash_table {
|
||||||
|
hash_ent **table;
|
||||||
|
int max;
|
||||||
|
int mask; /* == max - 1 */
|
||||||
|
int num_elements;
|
||||||
|
} hash_table;
|
||||||
|
|
||||||
|
|
||||||
|
#define HT_DEFAULT_MAX 128
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct cache_ent {
|
||||||
|
int dev;
|
||||||
|
off_t block_num;
|
||||||
|
int bsize;
|
||||||
|
volatile int flags;
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
void *clone; /* copy of data by set_block_info() */
|
||||||
|
int lock;
|
||||||
|
|
||||||
|
void (*func)(off_t bnum, size_t num_blocks, void *arg);
|
||||||
|
off_t logged_bnum;
|
||||||
|
void *arg;
|
||||||
|
|
||||||
|
struct cache_ent *next, /* points toward mru end of list */
|
||||||
|
*prev; /* points toward lru end of list */
|
||||||
|
|
||||||
|
} cache_ent;
|
||||||
|
|
||||||
|
#define CE_NORMAL 0x0000 /* a nice clean pristine page */
|
||||||
|
#define CE_DIRTY 0x0002 /* needs to be written to disk */
|
||||||
|
#define CE_BUSY 0x0004 /* this block has i/o happening, don't touch it */
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct cache_ent_list {
|
||||||
|
cache_ent *lru; /* tail of the list */
|
||||||
|
cache_ent *mru; /* head of the list */
|
||||||
|
} cache_ent_list;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct block_cache {
|
||||||
|
struct lock lock;
|
||||||
|
int flags;
|
||||||
|
int cur_blocks;
|
||||||
|
int max_blocks;
|
||||||
|
hash_table ht;
|
||||||
|
|
||||||
|
cache_ent_list normal, /* list of "normal" blocks (clean & dirty) */
|
||||||
|
locked; /* list of clean and locked blocks */
|
||||||
|
} block_cache;
|
||||||
|
|
||||||
|
#if 0 /* XXXdbg -- need to deal with write through caches */
|
||||||
|
#define DC_WRITE_THROUGH 0x0001 /* cache is write-through (for floppies) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALLOW_WRITES 1
|
||||||
|
#define NO_WRITES 0
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL int init_block_cache(int max_blocks, int flags);
|
||||||
|
extern _IMPEXP_KERNEL void shutdown_block_cache(void);
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL void force_cache_flush(int dev, int prefer_log_blocks);
|
||||||
|
extern _IMPEXP_KERNEL int flush_blocks(int dev, off_t bnum, int nblocks);
|
||||||
|
extern _IMPEXP_KERNEL int flush_device(int dev, int warn_locked);
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL int init_cache_for_device(int fd, off_t max_blocks);
|
||||||
|
extern _IMPEXP_KERNEL int remove_cached_device_blocks(int dev, int allow_write);
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL void *get_block(int dev, off_t bnum, int bsize);
|
||||||
|
extern _IMPEXP_KERNEL void *get_empty_block(int dev, off_t bnum, int bsize);
|
||||||
|
extern _IMPEXP_KERNEL int release_block(int dev, off_t bnum);
|
||||||
|
extern _IMPEXP_KERNEL int mark_blocks_dirty(int dev, off_t bnum, int nblocks);
|
||||||
|
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL int cached_read(int dev, off_t bnum, void *data, off_t num_blocks, int bsize);
|
||||||
|
extern _IMPEXP_KERNEL int cached_write(int dev, off_t bnum, const void *data,
|
||||||
|
off_t num_blocks, int bsize);
|
||||||
|
extern _IMPEXP_KERNEL int cached_write_locked(int dev, off_t bnum, const void *data,
|
||||||
|
off_t num_blocks, int bsize);
|
||||||
|
extern _IMPEXP_KERNEL int set_blocks_info(int dev, off_t *blocks, int nblocks,
|
||||||
|
void (*func)(off_t bnum, size_t nblocks, void *arg),
|
||||||
|
void *arg);
|
||||||
|
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL size_t read_phys_blocks (int fd, off_t bnum, void *data, uint num_blocks, int bsize);
|
||||||
|
extern _IMPEXP_KERNEL size_t write_phys_blocks(int fd, off_t bnum, void *data, uint num_blocks, int bsize);
|
||||||
|
|
||||||
|
#endif /* _CACHE_H_ */
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*! \file crc_table.cpp
|
||||||
|
|
||||||
|
Standalone program to generate the CRC table used for calculating
|
||||||
|
UDF tag id CRC values.
|
||||||
|
|
||||||
|
This code based off of crc code in UDF-2.50 specs, as permitted.
|
||||||
|
See UDF-2.50 6.5 for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[]) {
|
||||||
|
ulong crc, poly;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "USAGE: crc_table <octal polynomial=010041 for UDF>\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sscanf(argv[1], "%lo", &poly);
|
||||||
|
if (poly & 0xffff0000) {
|
||||||
|
fprintf(stderr, "ERROR: polynomial is too large, sucka.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("//! CRC 0%o table, as generated by crc_table.cpp\n", poly);
|
||||||
|
printf("static uint16 crc_table[256] = { \n");
|
||||||
|
for (int n = 0; n < 256; n++) {
|
||||||
|
if (n%8 == 0)
|
||||||
|
printf(" ");
|
||||||
|
crc = n << 8;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (crc & 0x8000)
|
||||||
|
crc = (crc << 1) ^ poly;
|
||||||
|
else
|
||||||
|
crc <<= 1;
|
||||||
|
crc &= 0xffff;
|
||||||
|
}
|
||||||
|
printf("0x%04x%s ", crc, (n != 255 ? "," : ""));
|
||||||
|
if (n%8 == 7)
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
printf("};\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel file_systems udf drive_setup_addon ;
|
||||||
|
|
||||||
|
# save original optimization level
|
||||||
|
oldOPTIM = $(OPTIM) ;
|
||||||
|
|
||||||
|
# set some additional defines
|
||||||
|
{
|
||||||
|
local defines =
|
||||||
|
DRIVE_SETUP_ADDON
|
||||||
|
;
|
||||||
|
|
||||||
|
if $(COMPILE_FOR_R5) {
|
||||||
|
defines += COMPILE_FOR_R5 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if $(DEBUG) {
|
||||||
|
#defines += DEBUG ;
|
||||||
|
} else {
|
||||||
|
# the gcc on BeOS doesn't compile BFS correctly with -O2 or more
|
||||||
|
OPTIM = -O1 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
defines = [ FDefines $(defines) ] ;
|
||||||
|
SubDirCcFlags $(defines) -Wall -Wno-multichar ;
|
||||||
|
SubDirC++Flags $(defines) -Wall -Wno-multichar ;
|
||||||
|
}
|
||||||
|
|
||||||
|
UsePrivateHeaders [ FDirName kernel util ] ;
|
||||||
|
SubDirHdrs [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems udf ] ;
|
||||||
|
|
||||||
|
# Note that the add-on is named "i-udf-ds" to put it alphabetically
|
||||||
|
# before the standard iso9660 add-on, thus giving it first dibs at
|
||||||
|
# iso9660/UDF hybrid discs.
|
||||||
|
Addon i-udf-ds : [ FDirName drive_setup fs ] :
|
||||||
|
udf-ds.cpp
|
||||||
|
Recognition.cpp
|
||||||
|
UdfDebug.cpp
|
||||||
|
UdfString.cpp
|
||||||
|
UdfStructures.cpp
|
||||||
|
Utils.cpp
|
||||||
|
|
||||||
|
: false
|
||||||
|
:
|
||||||
|
;
|
||||||
|
|
||||||
|
SEARCH on [ FGristFiles
|
||||||
|
Recognition.cpp UdfDebug.cpp UdfString.cpp UdfStructures.cpp Utils.cpp
|
||||||
|
] = [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems udf ] ;
|
||||||
|
|
||||||
|
rule InstallUDFDS
|
||||||
|
{
|
||||||
|
Depends $(<) : $(>) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
actions ignore InstallUDFDS
|
||||||
|
{
|
||||||
|
cp $(>) /boot/beos/system/add-ons/drive_setup/fs/
|
||||||
|
}
|
||||||
|
|
||||||
|
InstallUDFDS install : i-udf-ds ;
|
||||||
|
|
||||||
|
# restore original optimization level
|
||||||
|
OPTIM = $(oldOPTIM) ;
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
//----------------------------------------------------------------------
|
||||||
|
// This software is part of the OpenBeOS distribution and is covered
|
||||||
|
// by the OpenBeOS license.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2003 Tyler Dauwalder, [email protected]
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
/*! \file DriveSetupAddon.cpp
|
||||||
|
|
||||||
|
\brief UDF DriveSetup add-on for R5.
|
||||||
|
|
||||||
|
The interface implemented here is detailed in the Be Newsletter,
|
||||||
|
Volume II, Issue 23, "Getting Mounted". Thanks to Ingo Weinhold
|
||||||
|
for digging that up. :-)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UdfDebug.h"
|
||||||
|
#include "Recognition.h"
|
||||||
|
|
||||||
|
struct partition_data {
|
||||||
|
char partition_name[B_FILE_NAME_LENGTH];
|
||||||
|
char partition_type[B_FILE_NAME_LENGTH];
|
||||||
|
char file_system_short_name[B_FILE_NAME_LENGTH];
|
||||||
|
char file_system_long_name[B_FILE_NAME_LENGTH];
|
||||||
|
char volume_name[B_FILE_NAME_LENGTH];
|
||||||
|
char mounted_at[B_FILE_NAME_LENGTH];
|
||||||
|
uint32 logical_block_size;
|
||||||
|
uint64 offset; // in logical blocks from start of session
|
||||||
|
uint64 blocks;
|
||||||
|
bool hidden; //"non-file system" partition
|
||||||
|
bool reserved1;
|
||||||
|
uint32 reserved2;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" bool ds_fs_id(partition_data*, int32, uint64, int32);
|
||||||
|
|
||||||
|
bool
|
||||||
|
ds_fs_id(partition_data *data, int32 device, uint64 sessionOffset,
|
||||||
|
int32 blockSize)
|
||||||
|
{
|
||||||
|
DEBUG_INIT_ETC(NULL, ("%p, %ld, %Lu, %ld", data,
|
||||||
|
device, sessionOffset, blockSize));
|
||||||
|
|
||||||
|
if (!data || device < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
char name[256];
|
||||||
|
// Udf volume names are at most 63 2-byte unicode chars, so 256 UTF-8
|
||||||
|
// chars should cover us.
|
||||||
|
|
||||||
|
status_t error = Udf::udf_recognize(device, (data->offset + sessionOffset), data->blocks, blockSize, name);
|
||||||
|
if (!error) {
|
||||||
|
strcpy(data->file_system_short_name, "udf");
|
||||||
|
strcpy(data->file_system_long_name, "Universal Disk Format");
|
||||||
|
strcpy(data->volume_name, name);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
/*
|
||||||
|
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||||
|
This file may be used under the terms of the Be Sample Code License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FSPROTO_H
|
||||||
|
#define _FSPROTO_H
|
||||||
|
|
||||||
|
#include <sys/dirent.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <iovec.h>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
#include <fs_attr.h>
|
||||||
|
#include <fs_info.h>
|
||||||
|
#include <BeBuild.h>
|
||||||
|
#include <Drivers.h>
|
||||||
|
|
||||||
|
typedef dev_t nspace_id;
|
||||||
|
typedef ino_t vnode_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PUBLIC PART OF THE FILE SYSTEM PROTOCOL
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WSTAT_MODE 0x0001
|
||||||
|
#define WSTAT_UID 0x0002
|
||||||
|
#define WSTAT_GID 0x0004
|
||||||
|
#define WSTAT_SIZE 0x0008
|
||||||
|
#define WSTAT_ATIME 0x0010
|
||||||
|
#define WSTAT_MTIME 0x0020
|
||||||
|
#define WSTAT_CRTIME 0x0040
|
||||||
|
|
||||||
|
#define WFSSTAT_NAME 0x0001
|
||||||
|
|
||||||
|
#define B_ENTRY_CREATED 1
|
||||||
|
#define B_ENTRY_REMOVED 2
|
||||||
|
#define B_ENTRY_MOVED 3
|
||||||
|
#define B_STAT_CHANGED 4
|
||||||
|
#define B_ATTR_CHANGED 5
|
||||||
|
#define B_DEVICE_MOUNTED 6
|
||||||
|
#define B_DEVICE_UNMOUNTED 7
|
||||||
|
|
||||||
|
#define B_STOP_WATCHING 0x0000
|
||||||
|
#define B_WATCH_NAME 0x0001
|
||||||
|
#define B_WATCH_STAT 0x0002
|
||||||
|
#define B_WATCH_ATTR 0x0004
|
||||||
|
#define B_WATCH_DIRECTORY 0x0008
|
||||||
|
|
||||||
|
#define SELECT_READ 1
|
||||||
|
#define SELECT_WRITE 2
|
||||||
|
#define SELECT_EXCEPTION 3
|
||||||
|
|
||||||
|
#define B_CUR_FS_API_VERSION 2
|
||||||
|
|
||||||
|
#define IOCTL_FILE_UNCACHED_IO 10000
|
||||||
|
#define IOCTL_CREATE_TIME 10002
|
||||||
|
#define IOCTL_MODIFIED_TIME 10003
|
||||||
|
|
||||||
|
struct attr_info;
|
||||||
|
struct index_info;
|
||||||
|
|
||||||
|
typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node);
|
||||||
|
typedef int op_write_vnode(void *ns, void *node, char r);
|
||||||
|
typedef int op_remove_vnode(void *ns, void *node, char r);
|
||||||
|
typedef int op_secure_vnode(void *ns, void *node);
|
||||||
|
typedef int op_wake_vnode(void *ns, void *node);
|
||||||
|
typedef int op_suspend_vnode(void *ns, void *node);
|
||||||
|
|
||||||
|
typedef int op_walk(void *ns, void *base, const char *file, char **newpath,
|
||||||
|
vnode_id *vnid);
|
||||||
|
|
||||||
|
typedef int op_access(void *ns, void *node, int mode);
|
||||||
|
|
||||||
|
typedef int op_create(void *ns, void *dir, const char *name,
|
||||||
|
int omode, int perms, vnode_id *vnid, void **cookie);
|
||||||
|
typedef int op_mkdir(void *ns, void *dir, const char *name, int perms);
|
||||||
|
typedef int op_symlink(void *ns, void *dir, const char *name,
|
||||||
|
const char *path);
|
||||||
|
typedef int op_link(void *ns, void *dir, const char *name, void *node);
|
||||||
|
|
||||||
|
typedef int op_rename(void *ns, void *olddir, const char *oldname,
|
||||||
|
void *newdir, const char *newname);
|
||||||
|
typedef int op_unlink(void *ns, void *dir, const char *name);
|
||||||
|
typedef int op_rmdir(void *ns, void *dir, const char *name);
|
||||||
|
|
||||||
|
typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize);
|
||||||
|
|
||||||
|
typedef int op_opendir(void *ns, void *node, void **cookie);
|
||||||
|
typedef int op_closedir(void *ns, void *node, void *cookie);
|
||||||
|
typedef int op_rewinddir(void *ns, void *node, void *cookie);
|
||||||
|
typedef int op_readdir(void *ns, void *node, void *cookie, long *num,
|
||||||
|
struct dirent *buf, size_t bufsize);
|
||||||
|
|
||||||
|
typedef int op_open(void *ns, void *node, int omode, void **cookie);
|
||||||
|
typedef int op_close(void *ns, void *node, void *cookie);
|
||||||
|
typedef int op_free_cookie(void *ns, void *node, void *cookie);
|
||||||
|
typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf,
|
||||||
|
size_t *len);
|
||||||
|
typedef int op_write(void *ns, void *node, void *cookie, off_t pos,
|
||||||
|
const void *buf, size_t *len);
|
||||||
|
typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
|
||||||
|
size_t count, size_t *len);
|
||||||
|
typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
|
||||||
|
size_t count, size_t *len);
|
||||||
|
typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf,
|
||||||
|
size_t len);
|
||||||
|
typedef int op_setflags(void *ns, void *node, void *cookie, int flags);
|
||||||
|
|
||||||
|
typedef int op_rstat(void *ns, void *node, struct stat *);
|
||||||
|
typedef int op_wstat(void *ns, void *node, struct stat *, long mask);
|
||||||
|
typedef int op_fsync(void *ns, void *node);
|
||||||
|
|
||||||
|
typedef int op_select(void *ns, void *node, void *cookie, uint8 event,
|
||||||
|
uint32 ref, selectsync *sync);
|
||||||
|
typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event,
|
||||||
|
selectsync *sync);
|
||||||
|
|
||||||
|
typedef int op_initialize(const char *devname, void *parms, size_t len);
|
||||||
|
typedef int op_mount(nspace_id nsid, const char *devname, ulong flags,
|
||||||
|
void *parms, size_t len, void **data, vnode_id *vnid);
|
||||||
|
typedef int op_unmount(void *ns);
|
||||||
|
typedef int op_sync(void *ns);
|
||||||
|
typedef int op_rfsstat(void *ns, struct fs_info *);
|
||||||
|
typedef int op_wfsstat(void *ns, struct fs_info *, long mask);
|
||||||
|
|
||||||
|
|
||||||
|
typedef int op_open_attrdir(void *ns, void *node, void **cookie);
|
||||||
|
typedef int op_close_attrdir(void *ns, void *node, void *cookie);
|
||||||
|
typedef int op_rewind_attrdir(void *ns, void *node, void *cookie);
|
||||||
|
typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num,
|
||||||
|
struct dirent *buf, size_t bufsize);
|
||||||
|
typedef int op_remove_attr(void *ns, void *node, const char *name);
|
||||||
|
typedef int op_rename_attr(void *ns, void *node, const char *oldname,
|
||||||
|
const char *newname);
|
||||||
|
typedef int op_stat_attr(void *ns, void *node, const char *name,
|
||||||
|
struct attr_info *buf);
|
||||||
|
|
||||||
|
typedef int op_write_attr(void *ns, void *node, const char *name, int type,
|
||||||
|
const void *buf, size_t *len, off_t pos);
|
||||||
|
typedef int op_read_attr(void *ns, void *node, const char *name, int type,
|
||||||
|
void *buf, size_t *len, off_t pos);
|
||||||
|
|
||||||
|
typedef int op_open_indexdir(void *ns, void **cookie);
|
||||||
|
typedef int op_close_indexdir(void *ns, void *cookie);
|
||||||
|
typedef int op_rewind_indexdir(void *ns, void *cookie);
|
||||||
|
typedef int op_read_indexdir(void *ns, void *cookie, long *num,
|
||||||
|
struct dirent *buf, size_t bufsize);
|
||||||
|
typedef int op_create_index(void *ns, const char *name, int type, int flags);
|
||||||
|
typedef int op_remove_index(void *ns, const char *name);
|
||||||
|
typedef int op_rename_index(void *ns, const char *oldname,
|
||||||
|
const char *newname);
|
||||||
|
typedef int op_stat_index(void *ns, const char *name, struct index_info *buf);
|
||||||
|
|
||||||
|
typedef int op_open_query(void *ns, const char *query, ulong flags,
|
||||||
|
port_id port, long token, void **cookie);
|
||||||
|
typedef int op_close_query(void *ns, void *cookie);
|
||||||
|
typedef int op_read_query(void *ns, void *cookie, long *num,
|
||||||
|
struct dirent *buf, size_t bufsize);
|
||||||
|
|
||||||
|
typedef struct vnode_ops {
|
||||||
|
op_read_vnode (*read_vnode);
|
||||||
|
op_write_vnode (*write_vnode);
|
||||||
|
op_remove_vnode (*remove_vnode);
|
||||||
|
op_secure_vnode (*secure_vnode);
|
||||||
|
op_walk (*walk);
|
||||||
|
op_access (*access);
|
||||||
|
op_create (*create);
|
||||||
|
op_mkdir (*mkdir);
|
||||||
|
op_symlink (*symlink);
|
||||||
|
op_link (*link);
|
||||||
|
op_rename (*rename);
|
||||||
|
op_unlink (*unlink);
|
||||||
|
op_rmdir (*rmdir);
|
||||||
|
op_readlink (*readlink);
|
||||||
|
op_opendir (*opendir);
|
||||||
|
op_closedir (*closedir);
|
||||||
|
op_free_cookie (*free_dircookie);
|
||||||
|
op_rewinddir (*rewinddir);
|
||||||
|
op_readdir (*readdir);
|
||||||
|
op_open (*open);
|
||||||
|
op_close (*close);
|
||||||
|
op_free_cookie (*free_cookie);
|
||||||
|
op_read (*read);
|
||||||
|
op_write (*write);
|
||||||
|
op_readv (*readv);
|
||||||
|
op_writev (*writev);
|
||||||
|
op_ioctl (*ioctl);
|
||||||
|
op_setflags (*setflags);
|
||||||
|
op_rstat (*rstat);
|
||||||
|
op_wstat (*wstat);
|
||||||
|
op_fsync (*fsync);
|
||||||
|
op_initialize (*initialize);
|
||||||
|
op_mount (*mount);
|
||||||
|
op_unmount (*unmount);
|
||||||
|
op_sync (*sync);
|
||||||
|
op_rfsstat (*rfsstat);
|
||||||
|
op_wfsstat (*wfsstat);
|
||||||
|
op_select (*select);
|
||||||
|
op_deselect (*deselect);
|
||||||
|
op_open_indexdir (*open_indexdir);
|
||||||
|
op_close_indexdir (*close_indexdir);
|
||||||
|
op_free_cookie (*free_indexdircookie);
|
||||||
|
op_rewind_indexdir (*rewind_indexdir);
|
||||||
|
op_read_indexdir (*read_indexdir);
|
||||||
|
op_create_index (*create_index);
|
||||||
|
op_remove_index (*remove_index);
|
||||||
|
op_rename_index (*rename_index);
|
||||||
|
op_stat_index (*stat_index);
|
||||||
|
op_open_attrdir (*open_attrdir);
|
||||||
|
op_close_attrdir (*close_attrdir);
|
||||||
|
op_free_cookie (*free_attrdircookie);
|
||||||
|
op_rewind_attrdir (*rewind_attrdir);
|
||||||
|
op_read_attrdir (*read_attrdir);
|
||||||
|
op_write_attr (*write_attr);
|
||||||
|
op_read_attr (*read_attr);
|
||||||
|
op_remove_attr (*remove_attr);
|
||||||
|
op_rename_attr (*rename_attr);
|
||||||
|
op_stat_attr (*stat_attr);
|
||||||
|
op_open_query (*open_query);
|
||||||
|
op_close_query (*close_query);
|
||||||
|
op_free_cookie (*free_querycookie);
|
||||||
|
op_read_query (*read_query);
|
||||||
|
// for Dano compatibility only
|
||||||
|
op_wake_vnode (*wake_vnode);
|
||||||
|
op_suspend_vnode (*suspend_vnode);
|
||||||
|
} vnode_ops;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL int new_path(const char *path, char **copy);
|
||||||
|
extern _IMPEXP_KERNEL void free_path(char *p);
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL int notify_listener(int op, nspace_id nsid,
|
||||||
|
vnode_id vnida, vnode_id vnidb,
|
||||||
|
vnode_id vnidc, const char *name);
|
||||||
|
extern _IMPEXP_KERNEL int send_notification(port_id port, long token,
|
||||||
|
ulong what, long op, nspace_id nsida,
|
||||||
|
nspace_id nsidb, vnode_id vnida,
|
||||||
|
vnode_id vnidb, vnode_id vnidc,
|
||||||
|
const char *name);
|
||||||
|
extern _IMPEXP_KERNEL int get_vnode(nspace_id nsid, vnode_id vnid, void **data);
|
||||||
|
extern _IMPEXP_KERNEL int put_vnode(nspace_id nsid, vnode_id vnid);
|
||||||
|
extern _IMPEXP_KERNEL int new_vnode(nspace_id nsid, vnode_id vnid, void *data);
|
||||||
|
extern _IMPEXP_KERNEL int remove_vnode(nspace_id nsid, vnode_id vnid);
|
||||||
|
extern _IMPEXP_KERNEL int unremove_vnode(nspace_id nsid, vnode_id vnid);
|
||||||
|
extern _IMPEXP_KERNEL int is_vnode_removed(nspace_id nsid, vnode_id vnid);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern _EXPORT vnode_ops fs_entry;
|
||||||
|
extern _EXPORT int32 api_version;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||||
|
This file may be used under the terms of the Be Sample Code License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LOCK_H
|
||||||
|
#define _LOCK_H
|
||||||
|
|
||||||
|
#include <BeBuild.h>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#else
|
||||||
|
typedef struct lock lock;
|
||||||
|
typedef struct mlock mlock;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct lock {
|
||||||
|
sem_id s;
|
||||||
|
long c;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mlock {
|
||||||
|
sem_id s;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL int new_lock(lock *l, const char *name);
|
||||||
|
extern _IMPEXP_KERNEL int free_lock(lock *l);
|
||||||
|
|
||||||
|
#define LOCK(l) if (atomic_add(&l.c, -1) <= 0) acquire_sem(l.s);
|
||||||
|
#define UNLOCK(l) if (atomic_add(&l.c, 1) < 0) release_sem(l.s);
|
||||||
|
|
||||||
|
extern _IMPEXP_KERNEL int new_mlock(mlock *l, long c, const char *name);
|
||||||
|
extern _IMPEXP_KERNEL int free_mlock(mlock *l);
|
||||||
|
|
||||||
|
#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0)
|
||||||
|
#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user