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:
Tyler Dauwalder
2003-11-11 09:11:43 +00:00
parent 3d8229dc67
commit d4e8b936cc
2 changed files with 210 additions and 686 deletions
+193 -600
View File
@@ -10,58 +10,30 @@
#include "Icb.h"
#include "MemoryChunk.h"
#include "PhysicalPartition.h"
#include "Recognition.h"
using namespace Udf;
//----------------------------------------------------------------------
// Volume
//----------------------------------------------------------------------
/*! \brief Creates an unmounted volume with the given id.
*/
Volume::Volume(nspace_id id)
: fId(id)
, fDevice(0)
, fReadOnly(false)
, fMounted(false)
, fOffset(0)
, fLength(0)
, fBlockSize(0)
, fBlockShift(0)
, fInitStatus(B_UNINITIALIZED)
#if (!DRIVE_SETUP_ADDON)
, fRootIcb(NULL)
#endif
{
for (int i = 0; i < UDF_MAX_PARTITION_MAPS; i++)
fPartitions[i] = NULL;
}
status_t
Volume::Identify(int device, off_t offset, off_t length, uint32 blockSize, char *volumeName)
Volume::~Volume()
{
DEBUG_INIT_ETC(CF_PUBLIC | CF_VOLUME_OPS, "static Volume",
("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);
_Unset();
}
/*! \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.
*/
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)
{
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)
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(); i++) {
for (uint8 i = 0; i < logicalVolumeDescriptor.partition_map_count()
&& !error; i++)
{
uint8 *maps = logicalVolumeDescriptor.partition_maps();
udf_generic_partition_map *header =
reinterpret_cast<udf_generic_partition_map*>(maps+offset);
// logicalVolumeDescriptor.partition_maps() + offset);
udf_partition_map_header *header =
reinterpret_cast<udf_partition_map_header*>(maps+offset);
PRINT(("partition map %d (type %d):\n", i, header->type()));
if (header->type() == 1) {
// udf_physical_partition_map* map =
// reinterpret_cast<udf_physical_partition_map*>(header);
// PDUMP(map);
PDUMP(reinterpret_cast<udf_physical_partition_map*>(header));
PRINT(("map type: physical\n"));
udf_physical_partition_map* map =
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 {
udf_sparable_partition_map* map =
reinterpret_cast<udf_sparable_partition_map*>(header);
DUMP(map->partition_type_id());
}
PRINT(("Invalid partition type %d found!\n", header->type()));
error = B_ERROR;
}
offset += header->length();
}
}
RETURN(B_ERROR);
// 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
// Do some checking as to what sorts of partitions we've actually found.
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();
if (!error) {
error = Read(fLogicalVolumeDescriptor.file_set_address(),
fLogicalVolumeDescriptor.file_set_address().length(),
chunk.Data());
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) {
udf_file_set_descriptor *fileSet =
reinterpret_cast<udf_file_set_descriptor*>(chunk.Data());
@@ -160,580 +230,103 @@ Volume::Mount2(const char *deviceName, off_t offset, off_t length,
PDUMP(fileSet);
fRootIcb = new 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) {
// Success, create a vnode for the root
error = new_vnode(Id(), RootIcb()->Id(), (void*)RootIcb());
if (error) {
PRINT(("Error create vnode for root icb! error = 0x%lx, `%s'\n",
error, strerror(error)));
}
fName.SetTo(logicalVolumeDescriptor.logical_volume_identifier());
fMounted = true;
} else {
_Unset();
}
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);
/* 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*
Volume::Name() const {
return fName.String();
}
off_t
Volume::MapAddress(udf_extent_address address)
{
return address.location() * BlockSize();
}
/*! \brief Maps the given \c udf_long_address to an absolute block address.
/*! \brief Maps the given logical block to a physical block.
*/
status_t
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",
address.block(), address.partition(), mappedBlock));
status_t err = mappedBlock ? B_OK : B_BAD_VALUE;
if (!err)
err = _InitStatus() >= B_IDENTIFIED ? B_OK : B_NO_INIT;
if (!err) {
const udf_partition_descriptor* partition = fPartitionMap.Find(address.partition());
err = partition ? B_OK : B_BAD_ADDRESS;
if (!err) {
*mappedBlock = partition->start() + address.block();
}
if (!err) {
PRINT(("mapped to block %Ld\n", *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(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
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",
address.block(), address.partition(), mappedAddress));
status_t err = MapBlock(address, mappedAddress);
if (!err)
*mappedAddress = *mappedAddress * BlockSize();
if (!err) {
PRINT(("mapped to address %Ld\n", *mappedAddress));
status_t error = number < UDF_MAX_PARTITION_MAPS
? B_OK : B_BAD_VALUE;
if (!error) {
delete fPartitions[number];
fPartitions[number] = partition;
}
RETURN_ERROR(err);
return error;
}
off_t
Volume::MapAddress(udf_short_address address)
{
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);
}
/*! \brief Returns the partition associated with the given number, or
NULL if no such partition exists or the number is invalid.
*/
/*template <class AddressType>
status_t
Volume::_Read(AddressType address, ssize_t length, void *data)
Partition*
Volume::_GetPartition(uint number)
{
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);
return (number < UDF_MAX_PARTITION_MAPS)
? fPartitions[number] : NULL;
}
*/
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);
}
+17 -86
View File
@@ -26,7 +26,6 @@ extern "C" {
#include "CS0String.h"
#include "DiskStructures.h"
#include "PartitionMap.h"
#include "Partition.h"
namespace Udf {
@@ -35,121 +34,53 @@ class Icb;
class Volume {
public:
static status_t Identify(int device, off_t offset, off_t length, uint32 blockSize, char *volumeName);
Volume(nspace_id id);
// Construction/destruction
Volume(nspace_id id);
~Volume();
status_t Mount(const char *deviceName, off_t volumeStart, off_t volumeLength, uint32 flags,
uint32 blockSize = 2048);
status_t Mount2(const char *deviceName, off_t offset, off_t length,
uint32 blockSize, uint32 flags);
// 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(udf_long_address address, off_t *mappedBlock);
status_t MapExtent(udf_long_address logicalExtent, udf_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; }
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; }
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; }
#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:
Volume(); // unimplemented
Volume(const Volume &ref); // unimplemented
Volume& operator=(const Volume &ref); // unimplemented
status_t _InitStatus() const { return fInitStatus; }
// 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,
};
// 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();
void _Unset();
status_t _SetPartition(uint number, Partition *partition);
Partition* _GetPartition(uint number);
private:
nspace_id fId;
int fDevice;
bool fReadOnly;
bool fMounted;
off_t fOffset;
off_t fLength;
uint32 fBlockSize;
uint32 fBlockShift;
status_t fInitStatus;
udf_logical_descriptor fLogicalVolumeDescriptor;
Partition *fPartitions[UDF_MAX_PARTITION_MAPS];
PartitionMap fPartitionMap;
#if (!DRIVE_SETUP_ADDON)
Icb *fRootIcb; // Destroyed by vfs via callback to udf_release_node()
#endif
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
#endif // _UDF_VOLUME_H