tests/udf: Remove the "R5" version.
Largely untouched since 2006.
This commit is contained in:
parent
e24a254f55
commit
87b501a119
@ -1,4 +1,3 @@
|
||||
SubDir HAIKU_TOP src tests add-ons kernel file_systems udf ;
|
||||
|
||||
SubInclude HAIKU_TOP src tests add-ons kernel file_systems udf r5 ;
|
||||
SubInclude HAIKU_TOP src tests add-ons kernel file_systems udf udf_shell ;
|
||||
|
@ -1,261 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#ifndef _UDF_ALLOCATION_DESCRIPTOR_LIST_H
|
||||
#define _UDF_ALLOCATION_DESCRIPTOR_LIST_H
|
||||
|
||||
/*! \file AllocationDescriptorList.h
|
||||
*/
|
||||
|
||||
#include "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
|
@ -1,93 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#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
|
@ -1,159 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
// Based on the CachedBlock class from OpenBFS,
|
||||
// Copyright (c) 2002 Axel Dörfler, axeld@pinc-software.de
|
||||
//---------------------------------------------------------------------
|
||||
#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, axeld@pinc-software.de
|
||||
*/
|
||||
|
||||
#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
|
||||
|
@ -1,114 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#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
|
@ -1,105 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/*! \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;
|
||||
}
|
||||
|
||||
|
@ -1,54 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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
|
@ -1,171 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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);
|
||||
}
|
@ -1,321 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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
|
@ -1,69 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests add-ons kernel file_systems udf r5 ;
|
||||
|
||||
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) ;
|
||||
SubDirC++Flags $(defines) ;
|
||||
}
|
||||
|
||||
UsePrivateHeaders kernel ; # For kernel_cpp.cpp
|
||||
UsePrivateHeaders [ FDirName kernel util ] ; # For all the UDF source files
|
||||
|
||||
KernelAddon <r5>udf :
|
||||
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 tests add-ons kernel file_systems udf r5 drive_setup_addon ;
|
@ -1,72 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#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
|
@ -1,44 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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
|
@ -1,29 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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
|
@ -1,39 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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
|
@ -1,549 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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
|
@ -1,67 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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
|
@ -1,344 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// This version copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
// Initial version copyright (c) 2002 Axel Dörfler, axeld@pinc-software.de
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/*! \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);
|
||||
}
|
||||
|
@ -1,240 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// This version copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
// Initial version copyright (c) 2002 Axel Dörfler, axeld@pinc-software.de
|
||||
// dbg_printf() function copyright (c) 2003 Ingo Weinhold, bonefish@cs.tu-berlin.edu
|
||||
//----------------------------------------------------------------------
|
||||
#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
|
@ -1,312 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
#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
@ -1,173 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/*! \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
|
||||
|
@ -1,47 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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
|
||||
|
@ -1,44 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
#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
|
@ -1,349 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
// 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;
|
||||
}
|
||||
|
@ -1,90 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
// 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
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
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_ */
|
@ -1,53 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/*! \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;
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests add-ons kernel file_systems udf r5 drive_setup_addon ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
# 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) ;
|
||||
SubDirC++Flags $(defines) ;
|
||||
}
|
||||
|
||||
UsePrivateHeaders [ FDirName kernel util ] ;
|
||||
SubDirHdrs [ FDirName $(SUBDIR) .. ] ;
|
||||
|
||||
# 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 <r5>i-udf-ds :
|
||||
udf-ds.cpp
|
||||
Recognition.cpp
|
||||
UdfDebug.cpp
|
||||
UdfString.cpp
|
||||
UdfStructures.cpp
|
||||
Utils.cpp
|
||||
;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
Recognition.cpp UdfDebug.cpp UdfString.cpp UdfStructures.cpp Utils.cpp
|
||||
] = [ FDirName $(SUBDIR) .. ] ;
|
||||
|
||||
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) ;
|
||||
|
@ -1,63 +0,0 @@
|
||||
//----------------------------------------------------------------------
|
||||
// This software is part of the OpenBeOS distribution and is covered
|
||||
// by the MIT License.
|
||||
//
|
||||
// Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
/*! \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;
|
||||
}
|
||||
|
@ -1,261 +0,0 @@
|
||||
/*
|
||||
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
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
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
Loading…
Reference in New Issue
Block a user