Enormous cleanup.
- Finished migration of current capabilities (i.e. vanilla physical partition support) to new partition mapping system. - Eliminated a lot of unnecesary cruft. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5316 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -10,58 +10,30 @@
|
|||||||
|
|
||||||
#include "Icb.h"
|
#include "Icb.h"
|
||||||
#include "MemoryChunk.h"
|
#include "MemoryChunk.h"
|
||||||
|
#include "PhysicalPartition.h"
|
||||||
#include "Recognition.h"
|
#include "Recognition.h"
|
||||||
|
|
||||||
using namespace Udf;
|
using namespace Udf;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
// Volume
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/*! \brief Creates an unmounted volume with the given id.
|
/*! \brief Creates an unmounted volume with the given id.
|
||||||
*/
|
*/
|
||||||
Volume::Volume(nspace_id id)
|
Volume::Volume(nspace_id id)
|
||||||
: fId(id)
|
: fId(id)
|
||||||
, fDevice(0)
|
, fDevice(0)
|
||||||
, fReadOnly(false)
|
|
||||||
, fMounted(false)
|
, fMounted(false)
|
||||||
, fOffset(0)
|
, fOffset(0)
|
||||||
|
, fLength(0)
|
||||||
, fBlockSize(0)
|
, fBlockSize(0)
|
||||||
, fBlockShift(0)
|
, fBlockShift(0)
|
||||||
, fInitStatus(B_UNINITIALIZED)
|
|
||||||
#if (!DRIVE_SETUP_ADDON)
|
|
||||||
, fRootIcb(NULL)
|
, fRootIcb(NULL)
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < UDF_MAX_PARTITION_MAPS; i++)
|
for (int i = 0; i < UDF_MAX_PARTITION_MAPS; i++)
|
||||||
fPartitions[i] = NULL;
|
fPartitions[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t
|
Volume::~Volume()
|
||||||
Volume::Identify(int device, off_t offset, off_t length, uint32 blockSize, char *volumeName)
|
|
||||||
{
|
{
|
||||||
DEBUG_INIT_ETC(CF_PUBLIC | CF_VOLUME_OPS, "static Volume",
|
_Unset();
|
||||||
("device: %d, offset: %Ld, volumeName: %p", device, offset, volumeName));
|
|
||||||
if (!volumeName)
|
|
||||||
RETURN(B_BAD_VALUE);
|
|
||||||
|
|
||||||
// FILE *file = fopen("/boot/home/Desktop/outputIdentify.txt", "w+");
|
|
||||||
|
|
||||||
Volume volume(0);
|
|
||||||
status_t err = volume._Init(device, offset, length, blockSize);
|
|
||||||
// fprintf(file, "error = 0x%lx, `%s'\n", err, strerror(err));
|
|
||||||
// fflush(file);
|
|
||||||
if (!err)
|
|
||||||
err = volume._Identify();
|
|
||||||
// fprintf(file, "error = 0x%lx, `%s'\n", err, strerror(err));
|
|
||||||
// fflush(file);
|
|
||||||
if (!err)
|
|
||||||
strcpy(volumeName, volume.Name());
|
|
||||||
// fprintf(file, "error = 0x%lx, `%s'\n", err, strerror(err));
|
|
||||||
// fflush(file);
|
|
||||||
|
|
||||||
// fclose(file);
|
|
||||||
RETURN(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Attempts to mount the given device.
|
/*! \brief Attempts to mount the given device.
|
||||||
@@ -70,7 +42,7 @@ Volume::Identify(int device, off_t offset, off_t length, uint32 blockSize, char
|
|||||||
\param volumeLength The block length of the volume on the given device.
|
\param volumeLength The block length of the volume on the given device.
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
Volume::Mount2(const char *deviceName, off_t offset, off_t length,
|
Volume::Mount(const char *deviceName, off_t offset, off_t length,
|
||||||
uint32 blockSize, uint32 flags)
|
uint32 blockSize, uint32 flags)
|
||||||
{
|
{
|
||||||
DEBUG_INIT_ETC(CF_PUBLIC | CF_VOLUME_OPS, "Volume",
|
DEBUG_INIT_ETC(CF_PUBLIC | CF_VOLUME_OPS, "Volume",
|
||||||
@@ -113,46 +85,144 @@ Volume::Mount2(const char *deviceName, off_t offset, off_t length,
|
|||||||
if (!error)
|
if (!error)
|
||||||
error = init_cache_for_device(device, length);
|
error = init_cache_for_device(device, length);
|
||||||
|
|
||||||
|
int physicalCount = 0;
|
||||||
|
int virtualCount = 0;
|
||||||
|
int sparableCount = 0;
|
||||||
|
int metadataCount = 0;
|
||||||
|
|
||||||
// Set up the partitions
|
// Set up the partitions
|
||||||
if (!error) {
|
if (!error) {
|
||||||
// Set up physical and sparable partitions first
|
// Set up physical and sparable partitions first
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (uint8 i = 0; i < logicalVolumeDescriptor.partition_map_count(); i++) {
|
for (uint8 i = 0; i < logicalVolumeDescriptor.partition_map_count()
|
||||||
|
&& !error; i++)
|
||||||
|
{
|
||||||
uint8 *maps = logicalVolumeDescriptor.partition_maps();
|
uint8 *maps = logicalVolumeDescriptor.partition_maps();
|
||||||
udf_generic_partition_map *header =
|
udf_partition_map_header *header =
|
||||||
reinterpret_cast<udf_generic_partition_map*>(maps+offset);
|
reinterpret_cast<udf_partition_map_header*>(maps+offset);
|
||||||
// logicalVolumeDescriptor.partition_maps() + offset);
|
|
||||||
PRINT(("partition map %d (type %d):\n", i, header->type()));
|
PRINT(("partition map %d (type %d):\n", i, header->type()));
|
||||||
if (header->type() == 1) {
|
if (header->type() == 1) {
|
||||||
// udf_physical_partition_map* map =
|
PRINT(("map type: physical\n"));
|
||||||
// reinterpret_cast<udf_physical_partition_map*>(header);
|
udf_physical_partition_map* map =
|
||||||
// PDUMP(map);
|
reinterpret_cast<udf_physical_partition_map*>(header);
|
||||||
PDUMP(reinterpret_cast<udf_physical_partition_map*>(header));
|
// Find the corresponding partition descriptor
|
||||||
|
udf_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 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 partition map we have based
|
||||||
|
// on the type identifier
|
||||||
|
const udf_entity_id &typeId = header->partition_type_id();
|
||||||
|
DUMP(typeId);
|
||||||
|
DUMP(kSparablePartitionMapId);
|
||||||
|
if (typeId.matches(kVirtualPartitionMapId)) {
|
||||||
|
PRINT(("map type: virtual\n"));
|
||||||
|
udf_virtual_partition_map* map =
|
||||||
|
reinterpret_cast<udf_virtual_partition_map*>(header);
|
||||||
|
virtualCount++;
|
||||||
|
(void)map; // kill the warning for now
|
||||||
|
} else if (typeId.matches(kSparablePartitionMapId)) {
|
||||||
|
PRINT(("map type: sparable\n"));
|
||||||
|
udf_sparable_partition_map* map =
|
||||||
|
reinterpret_cast<udf_sparable_partition_map*>(header);
|
||||||
|
sparableCount++;
|
||||||
|
(void)map; // kill the warning for now
|
||||||
|
} else if (typeId.matches(kMetadataPartitionMapId)) {
|
||||||
|
PRINT(("map type: metadata\n"));
|
||||||
|
udf_metadata_partition_map* map =
|
||||||
|
reinterpret_cast<udf_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 {
|
} else {
|
||||||
udf_sparable_partition_map* map =
|
PRINT(("Invalid partition type %d found!\n", header->type()));
|
||||||
reinterpret_cast<udf_sparable_partition_map*>(header);
|
error = B_ERROR;
|
||||||
DUMP(map->partition_type_id());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += header->length();
|
offset += header->length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN(B_ERROR);
|
// Do some checking as to what sorts of partitions we've actually found.
|
||||||
|
|
||||||
// At this point we've found a valid set of volume descriptors, and we
|
|
||||||
// have our partitions set up. We
|
|
||||||
// now need to investigate the file set descriptor pointed to by
|
|
||||||
// the logical volume descriptor
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
MemoryChunk chunk(fLogicalVolumeDescriptor.file_set_address().length());
|
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());
|
||||||
|
|
||||||
status_t error = chunk.InitCheck();
|
status_t error = chunk.InitCheck();
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = Read(fLogicalVolumeDescriptor.file_set_address(),
|
off_t address;
|
||||||
fLogicalVolumeDescriptor.file_set_address().length(),
|
// Read in the file set descriptor
|
||||||
chunk.Data());
|
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) {
|
if (!error) {
|
||||||
udf_file_set_descriptor *fileSet =
|
udf_file_set_descriptor *fileSet =
|
||||||
reinterpret_cast<udf_file_set_descriptor*>(chunk.Data());
|
reinterpret_cast<udf_file_set_descriptor*>(chunk.Data());
|
||||||
@@ -160,87 +230,33 @@ Volume::Mount2(const char *deviceName, off_t offset, off_t length,
|
|||||||
PDUMP(fileSet);
|
PDUMP(fileSet);
|
||||||
fRootIcb = new Icb(this, fileSet->root_directory_icb());
|
fRootIcb = new Icb(this, fileSet->root_directory_icb());
|
||||||
error = fRootIcb ? fRootIcb->InitCheck() : B_NO_MEMORY;
|
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) {
|
if (!error) {
|
||||||
// Success, create a vnode for the root
|
fName.SetTo(logicalVolumeDescriptor.logical_volume_identifier());
|
||||||
error = new_vnode(Id(), RootIcb()->Id(), (void*)RootIcb());
|
fMounted = true;
|
||||||
if (error) {
|
} else {
|
||||||
PRINT(("Error create vnode for root icb! error = 0x%lx, `%s'\n",
|
_Unset();
|
||||||
error, strerror(error)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fInitStatus = error < B_OK ? B_UNINITIALIZED : B_LOGICAL_VOLUME_INITIALIZED;
|
|
||||||
|
|
||||||
// set name and other member variables
|
|
||||||
if (!error) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fDevice = device;
|
|
||||||
fReadOnly = true;
|
|
||||||
fOffset = offset;
|
|
||||||
fLength = length;
|
|
||||||
fBlockSize = blockSize;
|
|
||||||
|
|
||||||
RETURN(error);
|
RETURN(error);
|
||||||
|
|
||||||
/* if (!error && volumeName) {
|
|
||||||
CS0String name(logicalVolumeDescriptor.logical_volume_identifier());
|
|
||||||
strcpy(volumeName, name.String());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
status_t error = _Init(device, volumeStart, volumeLength, blockSize);
|
|
||||||
if (!error)
|
|
||||||
error = _Identify();
|
|
||||||
if (!error)
|
|
||||||
error = _Mount();
|
|
||||||
|
|
||||||
if (error)
|
|
||||||
fInitStatus = B_UNINITIALIZED;
|
|
||||||
|
|
||||||
RETURN(error);
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! \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 volumeStart, off_t volumeLength,
|
|
||||||
uint32 flags, uint32 blockSize)
|
|
||||||
{
|
|
||||||
DEBUG_INIT_ETC(CF_PUBLIC | CF_VOLUME_OPS, "Volume",
|
|
||||||
("deviceName: `%s', offset: %Ld, length %Ld", deviceName, volumeStart, volumeLength));
|
|
||||||
if (!deviceName)
|
|
||||||
RETURN(B_BAD_VALUE);
|
|
||||||
if (_InitStatus() == B_INITIALIZED)
|
|
||||||
RETURN(B_BUSY);
|
|
||||||
// Already mounted, thank you for asking
|
|
||||||
|
|
||||||
// Open the device read only
|
|
||||||
int device = open(deviceName, O_RDONLY);
|
|
||||||
if (device < B_OK)
|
|
||||||
RETURN(device);
|
|
||||||
|
|
||||||
status_t err = _Init(device, volumeStart, volumeLength, blockSize);
|
|
||||||
if (!err)
|
|
||||||
err = _Identify();
|
|
||||||
if (!err)
|
|
||||||
err = _Mount();
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
fInitStatus = B_UNINITIALIZED;
|
|
||||||
|
|
||||||
RETURN(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
@@ -248,492 +264,69 @@ Volume::Name() const {
|
|||||||
return fName.String();
|
return fName.String();
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t
|
/*! \brief Maps the given logical block to a physical block.
|
||||||
Volume::MapAddress(udf_extent_address address)
|
|
||||||
{
|
|
||||||
return address.location() * BlockSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! \brief Maps the given \c udf_long_address to an absolute block address.
|
|
||||||
*/
|
*/
|
||||||
status_t
|
status_t
|
||||||
Volume::MapBlock(udf_long_address address, off_t *mappedBlock)
|
Volume::MapBlock(udf_long_address address, off_t *mappedBlock)
|
||||||
{
|
{
|
||||||
DEBUG_INIT_ETC(CF_PRIVATE | CF_HIGH_VOLUME, "Volume", ("long_address(block: %ld, partition: %d), %p",
|
DEBUG_INIT_ETC(CF_PRIVATE | CF_HIGH_VOLUME, "Volume", ("long_address(block: %ld, partition: %d), %p",
|
||||||
address.block(), address.partition(), mappedBlock));
|
address.block(), address.partition(), mappedBlock));
|
||||||
status_t err = mappedBlock ? B_OK : B_BAD_VALUE;
|
status_t error = mappedBlock ? B_OK : B_BAD_VALUE;
|
||||||
if (!err)
|
if (!error) {
|
||||||
err = _InitStatus() >= B_IDENTIFIED ? B_OK : B_NO_INIT;
|
Partition *partition = _GetPartition(address.partition());
|
||||||
if (!err) {
|
error = partition ? B_OK : B_BAD_ADDRESS;
|
||||||
const udf_partition_descriptor* partition = fPartitionMap.Find(address.partition());
|
if (!error)
|
||||||
err = partition ? B_OK : B_BAD_ADDRESS;
|
error = partition->MapBlock(address.block(), *mappedBlock);
|
||||||
if (!err) {
|
|
||||||
*mappedBlock = partition->start() + address.block();
|
|
||||||
}
|
|
||||||
if (!err) {
|
|
||||||
PRINT(("mapped to block %Ld\n", *mappedBlock));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
RETURN(err);
|
RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Maps the given \c udf_long_address to an absolute byte address.
|
/*! \brief Unsets the volume and deletes any partitions.
|
||||||
|
|
||||||
|
Does *not* delete the root icb object.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Volume::_Unset()
|
||||||
|
{
|
||||||
|
fId = 0;
|
||||||
|
fDevice = 0;
|
||||||
|
fMounted = false;
|
||||||
|
fOffset = 0;
|
||||||
|
fLength = 0;
|
||||||
|
fBlockSize = 0;
|
||||||
|
fBlockShift = 0;
|
||||||
|
fName.SetTo("");
|
||||||
|
// 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
|
status_t
|
||||||
Volume::MapAddress(udf_long_address address, off_t *mappedAddress)
|
Volume::_SetPartition(uint number, Partition *partition)
|
||||||
{
|
{
|
||||||
DEBUG_INIT_ETC(CF_PRIVATE | CF_HIGH_VOLUME, "Volume", ("long_address(block: %ld, partition: %d), %p",
|
status_t error = number < UDF_MAX_PARTITION_MAPS
|
||||||
address.block(), address.partition(), mappedAddress));
|
? B_OK : B_BAD_VALUE;
|
||||||
status_t err = MapBlock(address, mappedAddress);
|
if (!error) {
|
||||||
if (!err)
|
delete fPartitions[number];
|
||||||
*mappedAddress = *mappedAddress * BlockSize();
|
fPartitions[number] = partition;
|
||||||
if (!err) {
|
|
||||||
PRINT(("mapped to address %Ld\n", *mappedAddress));
|
|
||||||
}
|
}
|
||||||
RETURN_ERROR(err);
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t
|
/*! \brief Returns the partition associated with the given number, or
|
||||||
Volume::MapAddress(udf_short_address address)
|
NULL if no such partition exists or the number is invalid.
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*status_t
|
|
||||||
Volume::_Read(udf_extent_address address, ssize_t length, void *data)
|
|
||||||
{
|
|
||||||
DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "Volume");
|
|
||||||
off_t mappedAddress = MapAddress(address);
|
|
||||||
status_t err = data ? B_OK : B_BAD_VALUE;
|
|
||||||
if (!err) {
|
|
||||||
ssize_t bytesRead = read_pos(fDevice, mappedAddress, data, BlockSize());
|
|
||||||
if (bytesRead != (ssize_t)BlockSize()) {
|
|
||||||
err = B_IO_ERROR;
|
|
||||||
PRINT(("read_pos(pos:%Ld, len:%ld) failed with: 0x%lx\n", mappedAddress,
|
|
||||||
length, bytesRead));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RETURN(err);
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
Partition*
|
||||||
/*template <class AddressType>
|
Volume::_GetPartition(uint number)
|
||||||
status_t
|
|
||||||
Volume::_Read(AddressType address, ssize_t length, void *data)
|
|
||||||
{
|
{
|
||||||
DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "Volume");
|
return (number < UDF_MAX_PARTITION_MAPS)
|
||||||
off_t mappedAddress;
|
? fPartitions[number] : NULL;
|
||||||
status_t err = data ? B_OK : B_BAD_VALUE;
|
|
||||||
if (!err)
|
|
||||||
err = MapAddress(address, &mappedAddress);
|
|
||||||
if (!err) {
|
|
||||||
ssize_t bytesRead = read_pos(fDevice, mappedAddress, data, BlockSize());
|
|
||||||
if (bytesRead != (ssize_t)BlockSize()) {
|
|
||||||
err = B_IO_ERROR;
|
|
||||||
PRINT(("read_pos(pos:%Ld, len:%ld) failed with: 0x%lx\n", mappedAddress,
|
|
||||||
length, bytesRead));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RETURN(err);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
status_t
|
|
||||||
Volume::_Init(int device, off_t offset, off_t length, int blockSize)
|
|
||||||
{
|
|
||||||
DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "Volume");
|
|
||||||
if (_InitStatus() == B_INITIALIZED)
|
|
||||||
RETURN_ERROR(B_BUSY);
|
|
||||||
|
|
||||||
// Check the block size
|
|
||||||
uint32 bitCount = 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) {
|
|
||||||
PRINT(("Block size must be a power of two! (blockSize = %d)\n", blockSize));
|
|
||||||
RETURN(B_BAD_VALUE);
|
|
||||||
} else {
|
|
||||||
fBlockShift = i;
|
|
||||||
PRINT(("BlockShift() = %ld\n", BlockShift()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fDevice = device;
|
|
||||||
fReadOnly = true;
|
|
||||||
fOffset = offset;
|
|
||||||
fLength = length;
|
|
||||||
fBlockSize = blockSize;
|
|
||||||
|
|
||||||
status_t err = B_OK;
|
|
||||||
|
|
||||||
#if (!DRIVE_SETUP_ADDON)
|
|
||||||
// If the device is actually a normal file, try to disable the cache
|
|
||||||
// for the file in the parent filesystem
|
|
||||||
struct stat stat;
|
|
||||||
err = fstat(fDevice, &stat) < 0 ? B_ERROR : B_OK;
|
|
||||||
if (!err) {
|
|
||||||
if (stat.st_mode & S_IFREG && ioctl(fDevice, IOCTL_FILE_UNCACHED_IO, NULL) < 0) {
|
|
||||||
// Apparently it's a bad thing if you can't disable the file
|
|
||||||
// cache for a non-device disk image you're trying to mount...
|
|
||||||
DIE(("Unable to disable cache of underlying file system. "
|
|
||||||
"I hear that's bad. :-(\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fInitStatus = err < B_OK ? B_UNINITIALIZED : B_DEVICE_INITIALIZED;
|
|
||||||
|
|
||||||
RETURN(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \brief Walks through the volume recognition and descriptor sequences,
|
|
||||||
gathering volume description info as it goes.
|
|
||||||
|
|
||||||
Note that the 512 avdp location is, technically speaking, only valid on
|
|
||||||
unlosed CD-R media in the absense of an avdp at 256. For now I'm not
|
|
||||||
bothering with such silly details, and instead am just checking for it
|
|
||||||
last.
|
|
||||||
*/
|
|
||||||
status_t
|
|
||||||
Volume::_Identify()
|
|
||||||
{
|
|
||||||
DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
|
|
||||||
|
|
||||||
status_t err = _InitStatus() == B_DEVICE_INITIALIZED ? B_OK : B_BAD_VALUE;
|
|
||||||
|
|
||||||
// Check for a valid volume recognition sequence
|
|
||||||
if (!err)
|
|
||||||
err = _WalkVolumeRecognitionSequence();
|
|
||||||
|
|
||||||
// Now hunt down a volume descriptor sequence from one of
|
|
||||||
// the anchor volume pointers (if there are any).
|
|
||||||
if (!err)
|
|
||||||
err = _WalkAnchorVolumeDescriptorSequences();
|
|
||||||
|
|
||||||
// Set the volume name
|
|
||||||
if (!err) {
|
|
||||||
// FILE *file = fopen("/boot/home/Desktop/vdoutput.txt", "w+");
|
|
||||||
// fprint
|
|
||||||
|
|
||||||
fName.SetTo(fLogicalVolumeDescriptor.logical_volume_identifier());
|
|
||||||
}
|
|
||||||
|
|
||||||
fInitStatus = err < B_OK ? B_UNINITIALIZED : B_IDENTIFIED;
|
|
||||||
|
|
||||||
RETURN(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t
|
|
||||||
Volume::_Mount()
|
|
||||||
{
|
|
||||||
DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
|
|
||||||
|
|
||||||
status_t err = _InitStatus() == B_IDENTIFIED ? B_OK : B_BAD_VALUE;
|
|
||||||
|
|
||||||
#if (!DRIVE_SETUP_ADDON)
|
|
||||||
if (!err)
|
|
||||||
err = init_cache_for_device(Device(), Length());
|
|
||||||
|
|
||||||
// At this point we've found a valid set of volume descriptors. We
|
|
||||||
// now need to investigate the file set descriptor pointed to by
|
|
||||||
// the logical volume descriptor
|
|
||||||
if (!err)
|
|
||||||
err = _InitFileSetDescriptor();
|
|
||||||
|
|
||||||
if (!err) {
|
|
||||||
// Success, create a vnode for the root
|
|
||||||
err = new_vnode(Id(), RootIcb()->Id(), (void*)RootIcb());
|
|
||||||
if (err) {
|
|
||||||
PRINT(("Error create vnode for root icb! error = 0x%lx, `%s'\n",
|
|
||||||
err, strerror(err)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fInitStatus = err < B_OK ? B_UNINITIALIZED : B_LOGICAL_VOLUME_INITIALIZED;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RETURN(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \brief Walks the iso9660/ecma-167 volume recognition sequence, returning
|
|
||||||
\c B_OK if the presence of a UDF filesystem on this volume is likely.
|
|
||||||
|
|
||||||
\return \c B_OK: An ECMA-167 vsd was found, or at least one extended area
|
|
||||||
vsd was found and no ECMA-168 vsds were found.
|
|
||||||
\return "error code": Only iso9660 vsds were found, an ECMA-168 vsd was
|
|
||||||
found (but no ECMA-167 vsd), or an error occurred.
|
|
||||||
*/
|
|
||||||
status_t
|
|
||||||
Volume::_WalkVolumeRecognitionSequence()
|
|
||||||
{
|
|
||||||
DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
|
|
||||||
// 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 err = chunk.InitCheck();
|
|
||||||
if (!err) {
|
|
||||||
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 = AddressForRelativeBlock(block);
|
|
||||||
ssize_t bytesRead = read_pos(fDevice, address, chunk.Data(), BlockSize());
|
|
||||||
if (bytesRead == (ssize_t)BlockSize())
|
|
||||||
{
|
|
||||||
udf_volume_structure_descriptor_header* descriptor =
|
|
||||||
reinterpret_cast<udf_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.
|
|
||||||
err = foundECMA167 || (foundExtended && !foundECMA168) ? B_OK : B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t
|
|
||||||
Volume::_WalkAnchorVolumeDescriptorSequences()
|
|
||||||
{
|
|
||||||
DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
|
|
||||||
const uint8 avds_location_count = 4;
|
|
||||||
const off_t avds_locations[avds_location_count] = {
|
|
||||||
256,
|
|
||||||
Length()-256,
|
|
||||||
Length(),
|
|
||||||
512,
|
|
||||||
};
|
|
||||||
bool found_vds = false;
|
|
||||||
|
|
||||||
for (int32 i = 0; i < avds_location_count; i++) {
|
|
||||||
off_t block = avds_locations[i];
|
|
||||||
off_t address = AddressForRelativeBlock(block);
|
|
||||||
MemoryChunk chunk(BlockSize());
|
|
||||||
udf_anchor_descriptor *anchor = NULL;
|
|
||||||
|
|
||||||
status_t anchorErr = chunk.InitCheck();
|
|
||||||
if (!anchorErr) {
|
|
||||||
ssize_t bytesRead = read_pos(fDevice, 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<udf_anchor_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 = _WalkVolumeDescriptorSequence(anchor->main_vds());
|
|
||||||
if (anchorErr)
|
|
||||||
anchorErr = _WalkVolumeDescriptorSequence(anchor->reserve_vds());
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
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 err = found_vds ? B_OK : B_ERROR;
|
|
||||||
RETURN(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t
|
|
||||||
Volume::_WalkVolumeDescriptorSequence(udf_extent_address extent)
|
|
||||||
{
|
|
||||||
DEBUG_INIT_ETC(CF_PRIVATE | CF_VOLUME_OPS, "Volume", ("loc:%ld, len:%ld",
|
|
||||||
extent.location(), extent.length()));
|
|
||||||
uint32 count = extent.length()/BlockSize();
|
|
||||||
|
|
||||||
bool foundLogicalVD = false;
|
|
||||||
|
|
||||||
for (uint32 i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
off_t block = extent.location()+i;
|
|
||||||
off_t address = block << BlockShift(); //AddressForRelativeBlock(block);
|
|
||||||
MemoryChunk chunk(BlockSize());
|
|
||||||
udf_tag *tag = NULL;
|
|
||||||
|
|
||||||
PRINT(("descriptor #%ld (block %Ld):\n", i, block));
|
|
||||||
|
|
||||||
status_t err = chunk.InitCheck();
|
|
||||||
if (!err) {
|
|
||||||
ssize_t bytesRead = read_pos(fDevice, address, chunk.Data(), BlockSize());
|
|
||||||
err = bytesRead == (ssize_t)BlockSize() ? B_OK : B_IO_ERROR;
|
|
||||||
if (err) {
|
|
||||||
PRINT(("block %Ld: read_pos(pos:%Ld, len:%ld) failed with error 0x%lx\n",
|
|
||||||
block, address, BlockSize(), bytesRead));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!err) {
|
|
||||||
tag = reinterpret_cast<udf_tag*>(chunk.Data());
|
|
||||||
err = tag->init_check(block);
|
|
||||||
}
|
|
||||||
if (!err) {
|
|
||||||
// Now decide what type of descriptor we have
|
|
||||||
switch (tag->id()) {
|
|
||||||
case TAGID_UNDEFINED:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TAGID_PRIMARY_VOLUME_DESCRIPTOR:
|
|
||||||
{
|
|
||||||
udf_primary_descriptor *primary = reinterpret_cast<udf_primary_descriptor*>(tag);
|
|
||||||
PDUMP(primary);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TAGID_ANCHOR_VOLUME_DESCRIPTOR_POINTER:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TAGID_VOLUME_DESCRIPTOR_POINTER:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TAGID_IMPLEMENTATION_USE_VOLUME_DESCRIPTOR:
|
|
||||||
{
|
|
||||||
udf_implementation_use_descriptor *imp_use = reinterpret_cast<udf_implementation_use_descriptor*>(tag);
|
|
||||||
PDUMP(imp_use);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TAGID_PARTITION_DESCRIPTOR:
|
|
||||||
{
|
|
||||||
udf_partition_descriptor *partition = reinterpret_cast<udf_partition_descriptor*>(tag);
|
|
||||||
PDUMP(partition);
|
|
||||||
if (partition->tag().init_check(block) == B_OK) {
|
|
||||||
const udf_partition_descriptor *current = fPartitionMap.Find(partition->partition_number());
|
|
||||||
if (!current || current->vds_number() < partition->vds_number()) {
|
|
||||||
PRINT(("adding partition #%d with vds_number %ld to partition map\n",
|
|
||||||
partition->partition_number(), partition->vds_number()));
|
|
||||||
fPartitionMap.Add(partition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TAGID_LOGICAL_VOLUME_DESCRIPTOR:
|
|
||||||
{
|
|
||||||
udf_logical_descriptor *logical = reinterpret_cast<udf_logical_descriptor*>(tag);
|
|
||||||
PDUMP(logical);
|
|
||||||
if (foundLogicalVD) {
|
|
||||||
// Keep the vd with the highest vds_number
|
|
||||||
if (logical->vds_number() > fLogicalVolumeDescriptor.vds_number())
|
|
||||||
fLogicalVolumeDescriptor = *(logical);
|
|
||||||
} else {
|
|
||||||
fLogicalVolumeDescriptor = *(logical);
|
|
||||||
foundLogicalVD = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TAGID_UNALLOCATED_SPACE_DESCRIPTOR:
|
|
||||||
{
|
|
||||||
udf_unallocated_space_descriptor *unallocated = reinterpret_cast<udf_unallocated_space_descriptor*>(tag);
|
|
||||||
PDUMP(unallocated);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TAGID_TERMINATING_DESCRIPTOR:
|
|
||||||
{
|
|
||||||
udf_terminating_descriptor *terminating = reinterpret_cast<udf_terminating_descriptor*>(tag);
|
|
||||||
PDUMP(terminating);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TAGID_LOGICAL_VOLUME_INTEGRITY_DESCRIPTOR:
|
|
||||||
// Not found in this descriptor sequence
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t err = foundLogicalVD ? B_OK : B_ERROR;
|
|
||||||
if (!err) {
|
|
||||||
PRINT(("partition map:\n"));
|
|
||||||
DUMP(fPartitionMap);
|
|
||||||
}
|
|
||||||
RETURN(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t
|
|
||||||
Volume::_InitFileSetDescriptor()
|
|
||||||
{
|
|
||||||
DEBUG_INIT(CF_PRIVATE | CF_VOLUME_OPS, "Volume");
|
|
||||||
MemoryChunk chunk(fLogicalVolumeDescriptor.file_set_address().length());
|
|
||||||
|
|
||||||
status_t err = chunk.InitCheck();
|
|
||||||
|
|
||||||
#if (!DRIVE_SETUP_ADDON)
|
|
||||||
if (!err) {
|
|
||||||
// err = Read(ad, fLogicalVolumeDescriptor.file_set_address().length(), chunk.Data());
|
|
||||||
err = Read(fLogicalVolumeDescriptor.file_set_address(), fLogicalVolumeDescriptor.file_set_address().length(), chunk.Data());
|
|
||||||
if (!err) {
|
|
||||||
udf_file_set_descriptor *fileSet = reinterpret_cast<udf_file_set_descriptor*>(chunk.Data());
|
|
||||||
fileSet->tag().init_check(0);
|
|
||||||
PDUMP(fileSet);
|
|
||||||
fRootIcb = new Icb(this, fileSet->root_directory_icb());
|
|
||||||
err = fRootIcb ? fRootIcb->InitCheck() : B_NO_MEMORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RETURN(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ extern "C" {
|
|||||||
|
|
||||||
#include "CS0String.h"
|
#include "CS0String.h"
|
||||||
#include "DiskStructures.h"
|
#include "DiskStructures.h"
|
||||||
#include "PartitionMap.h"
|
|
||||||
#include "Partition.h"
|
#include "Partition.h"
|
||||||
|
|
||||||
namespace Udf {
|
namespace Udf {
|
||||||
@@ -35,121 +34,53 @@ class Icb;
|
|||||||
|
|
||||||
class Volume {
|
class Volume {
|
||||||
public:
|
public:
|
||||||
static status_t Identify(int device, off_t offset, off_t length, uint32 blockSize, char *volumeName);
|
// Construction/destruction
|
||||||
|
|
||||||
Volume(nspace_id id);
|
Volume(nspace_id id);
|
||||||
|
~Volume();
|
||||||
|
|
||||||
status_t Mount(const char *deviceName, off_t volumeStart, off_t volumeLength, uint32 flags,
|
// Mounting/unmounting
|
||||||
uint32 blockSize = 2048);
|
status_t Mount(const char *deviceName, off_t offset, off_t length,
|
||||||
status_t Mount2(const char *deviceName, off_t offset, off_t length,
|
uint32 blockSize, uint32 flags);
|
||||||
uint32 blockSize, uint32 flags);
|
|
||||||
status_t Unmount();
|
status_t Unmount();
|
||||||
|
|
||||||
|
// Address mapping
|
||||||
|
status_t MapBlock(udf_long_address address, off_t *mappedBlock);
|
||||||
|
status_t MapExtent(udf_long_address logicalExtent, udf_extent_address &physicalExtent);
|
||||||
|
|
||||||
|
// Miscellaneous info
|
||||||
const char *Name() const;
|
const char *Name() const;
|
||||||
int Device() const { return fDevice; }
|
int Device() const { return fDevice; }
|
||||||
nspace_id Id() const { return fId; }
|
nspace_id Id() const { return fId; }
|
||||||
|
|
||||||
off_t Offset() const { return fOffset; }
|
off_t Offset() const { return fOffset; }
|
||||||
off_t Length() const { return fLength; }
|
off_t Length() const { return fLength; }
|
||||||
|
|
||||||
uint32 BlockSize() const { return fBlockSize; }
|
uint32 BlockSize() const { return fBlockSize; }
|
||||||
uint32 BlockShift() const { return fBlockShift; }
|
uint32 BlockShift() const { return fBlockShift; }
|
||||||
|
|
||||||
off_t AddressForRelativeBlock(off_t block) { return (Offset() + block) * BlockSize(); }
|
|
||||||
off_t RelativeAddress(off_t address) { return Offset() * BlockSize() + address; }
|
|
||||||
|
|
||||||
bool IsReadOnly() const { return fReadOnly; }
|
|
||||||
bool Mounted() const { return fMounted; }
|
bool Mounted() const { return fMounted; }
|
||||||
|
|
||||||
vnode_id ToVnodeId(off_t block) const { return (vnode_id)block; }
|
|
||||||
|
|
||||||
template <class AddressType>
|
|
||||||
ssize_t Read(AddressType address, ssize_t length, void *data);
|
|
||||||
|
|
||||||
#if (!DRIVE_SETUP_ADDON)
|
|
||||||
Icb* RootIcb() { return fRootIcb; }
|
Icb* RootIcb() { return fRootIcb; }
|
||||||
#endif
|
|
||||||
|
|
||||||
status_t MapAddress(udf_long_address address, off_t *mappedAddress);
|
|
||||||
off_t MapAddress(udf_extent_address address);
|
|
||||||
status_t MapBlock(udf_long_address address, off_t *mappedBlock);
|
|
||||||
off_t MapAddress(udf_short_address address);
|
|
||||||
status_t MapExtent(udf_long_address logicalExtent, udf_extent_address &physicalExtent);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Volume(); // unimplemented
|
Volume(); // unimplemented
|
||||||
Volume(const Volume &ref); // unimplemented
|
Volume(const Volume &ref); // unimplemented
|
||||||
Volume& operator=(const Volume &ref); // unimplemented
|
Volume& operator=(const Volume &ref); // unimplemented
|
||||||
|
|
||||||
status_t _InitStatus() const { return fInitStatus; }
|
void _Unset();
|
||||||
// Private _InitStatus() status_t values
|
|
||||||
enum {
|
|
||||||
B_UNINITIALIZED = B_ERRORS_END+1, //!< Completely uninitialized
|
|
||||||
B_DEVICE_INITIALIZED, //!< Initialized enough to access underlying device safely
|
|
||||||
B_IDENTIFIED, //!< Verified to be a UDF volume on disc
|
|
||||||
B_LOGICAL_VOLUME_INITIALIZED, //!< Initialized enough to map addresses
|
|
||||||
|
|
||||||
B_INITIALIZED = B_OK,
|
status_t _SetPartition(uint number, Partition *partition);
|
||||||
};
|
Partition* _GetPartition(uint number);
|
||||||
|
|
||||||
|
|
||||||
// Called by Mount(), either directly or indirectly
|
|
||||||
status_t _Init(int device, off_t offset, off_t length, int blockSize);
|
|
||||||
status_t _Identify();
|
|
||||||
status_t _Mount();
|
|
||||||
status_t _WalkVolumeRecognitionSequence();
|
|
||||||
status_t _WalkAnchorVolumeDescriptorSequences();
|
|
||||||
status_t _WalkVolumeDescriptorSequence(udf_extent_address extent);
|
|
||||||
status_t _InitFileSetDescriptor();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nspace_id fId;
|
nspace_id fId;
|
||||||
int fDevice;
|
int fDevice;
|
||||||
bool fReadOnly;
|
|
||||||
bool fMounted;
|
bool fMounted;
|
||||||
|
|
||||||
off_t fOffset;
|
off_t fOffset;
|
||||||
off_t fLength;
|
off_t fLength;
|
||||||
uint32 fBlockSize;
|
uint32 fBlockSize;
|
||||||
uint32 fBlockShift;
|
uint32 fBlockShift;
|
||||||
|
|
||||||
status_t fInitStatus;
|
|
||||||
|
|
||||||
udf_logical_descriptor fLogicalVolumeDescriptor;
|
|
||||||
Partition *fPartitions[UDF_MAX_PARTITION_MAPS];
|
Partition *fPartitions[UDF_MAX_PARTITION_MAPS];
|
||||||
PartitionMap fPartitionMap;
|
|
||||||
#if (!DRIVE_SETUP_ADDON)
|
|
||||||
Icb *fRootIcb; // Destroyed by vfs via callback to udf_release_node()
|
Icb *fRootIcb; // Destroyed by vfs via callback to udf_release_node()
|
||||||
#endif
|
|
||||||
CS0String fName;
|
CS0String fName;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
// Template functions
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
template <class AddressType>
|
|
||||||
status_t
|
|
||||||
Volume::Read(AddressType address, ssize_t length, void *data)
|
|
||||||
{
|
|
||||||
DEBUG_INIT(CF_PRIVATE | CF_HIGH_VOLUME, "Volume");
|
|
||||||
off_t mappedAddress;
|
|
||||||
status_t err = data ? B_OK : B_BAD_VALUE;
|
|
||||||
if (!err)
|
|
||||||
err = MapAddress(address, &mappedAddress);
|
|
||||||
if (!err) {
|
|
||||||
ssize_t bytesRead = read_pos(fDevice, mappedAddress, data, BlockSize());
|
|
||||||
if (bytesRead != (ssize_t)BlockSize()) {
|
|
||||||
err = B_IO_ERROR;
|
|
||||||
PRINT(("read_pos(pos:%Ld, len:%ld) failed with: 0x%lx\n", mappedAddress,
|
|
||||||
length, bytesRead));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RETURN(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}; // namespace Udf
|
}; // namespace Udf
|
||||||
|
|
||||||
#endif // _UDF_VOLUME_H
|
#endif // _UDF_VOLUME_H
|
||||||
|
|||||||
Reference in New Issue
Block a user