tests/udf: Remove the "R5" version.

Largely untouched since 2006.
This commit is contained in:
Augustin Cavalier 2018-08-12 22:47:27 -04:00
parent e24a254f55
commit 87b501a119
40 changed files with 0 additions and 9134 deletions

View File

@ -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 ;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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 ;

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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 &timestamp)
{
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

View File

@ -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 &timestamp);
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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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) ;

View File

@ -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;
}

View File

@ -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

View File

@ -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