129008bcfSTyler Dauwalder //---------------------------------------------------------------------- 229008bcfSTyler Dauwalder // This software is part of the OpenBeOS distribution and is covered 329008bcfSTyler Dauwalder // by the OpenBeOS license. 429008bcfSTyler Dauwalder // 529008bcfSTyler Dauwalder // Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net 629008bcfSTyler Dauwalder // Mad props to Axel Dörfler and his BFS implementation, from which 729008bcfSTyler Dauwalder // this UDF implementation draws much influence (and a little code :-P). 829008bcfSTyler Dauwalder //---------------------------------------------------------------------- 929008bcfSTyler Dauwalder #include "Volume.h" 1029008bcfSTyler Dauwalder 113f4628f1STyler Dauwalder #include "Icb.h" 120d383564STyler Dauwalder #include "MemoryChunk.h" 13d4e8b936STyler Dauwalder #include "PhysicalPartition.h" 1421c162a3STyler Dauwalder #include "Recognition.h" 1529008bcfSTyler Dauwalder 163f4628f1STyler Dauwalder using namespace Udf; 1729008bcfSTyler Dauwalder 1829008bcfSTyler Dauwalder /*! \brief Creates an unmounted volume with the given id. 1929008bcfSTyler Dauwalder */ 2029008bcfSTyler Dauwalder Volume::Volume(nspace_id id) 213f4628f1STyler Dauwalder : fId(id) 2229008bcfSTyler Dauwalder , fDevice(0) 2321c162a3STyler Dauwalder , fMounted(false) 24bb182cf3STyler Dauwalder , fOffset(0) 25d4e8b936STyler Dauwalder , fLength(0) 264ac73018STyler Dauwalder , fBlockSize(0) 27a71fd512STyler Dauwalder , fBlockShift(0) 283f4628f1STyler Dauwalder , fRootIcb(NULL) 2929008bcfSTyler Dauwalder { 3021c162a3STyler Dauwalder for (int i = 0; i < UDF_MAX_PARTITION_MAPS; i++) 3121c162a3STyler Dauwalder fPartitions[i] = NULL; 3229008bcfSTyler Dauwalder } 3329008bcfSTyler Dauwalder 34d4e8b936STyler Dauwalder Volume::~Volume() 3529008bcfSTyler Dauwalder { 36d4e8b936STyler Dauwalder _Unset(); 3729008bcfSTyler Dauwalder } 3829008bcfSTyler Dauwalder 3929008bcfSTyler Dauwalder /*! \brief Attempts to mount the given device. 403f4628f1STyler Dauwalder 413f4628f1STyler Dauwalder \param volumeStart The block on the given device whereat the volume begins. 423f4628f1STyler Dauwalder \param volumeLength The block length of the volume on the given device. 4329008bcfSTyler Dauwalder */ 4429008bcfSTyler Dauwalder status_t 45d4e8b936STyler Dauwalder Volume::Mount(const char *deviceName, off_t offset, off_t length, 4621c162a3STyler Dauwalder uint32 blockSize, uint32 flags) 4721c162a3STyler Dauwalder { 4821ea9aeaSTyler Dauwalder DEBUG_INIT_ETC("Volume", 4921c162a3STyler Dauwalder ("deviceName: `%s', offset: %Ld, length: %Ld, blockSize: %ld, " 5021c162a3STyler Dauwalder "flags: %ld", deviceName, offset, length, blockSize, flags)); 5121c162a3STyler Dauwalder if (!deviceName) 5221c162a3STyler Dauwalder RETURN(B_BAD_VALUE); 5321c162a3STyler Dauwalder if (Mounted()) { 5421c162a3STyler Dauwalder // Already mounted, thank you for asking 5521c162a3STyler Dauwalder RETURN(B_BUSY); 5621c162a3STyler Dauwalder } 5721c162a3STyler Dauwalder 5821c162a3STyler Dauwalder // Open the device read only 5921c162a3STyler Dauwalder int device = open(deviceName, O_RDONLY); 6021c162a3STyler Dauwalder if (device < B_OK) 6121c162a3STyler Dauwalder RETURN(device); 6221c162a3STyler Dauwalder 6321c162a3STyler Dauwalder status_t error = B_OK; 6421c162a3STyler Dauwalder 6521c162a3STyler Dauwalder // If the device is actually a normal file, try to disable the cache 6621c162a3STyler Dauwalder // for the file in the parent filesystem 6721c162a3STyler Dauwalder struct stat stat; 6821c162a3STyler Dauwalder error = fstat(device, &stat) < 0 ? B_ERROR : B_OK; 6921c162a3STyler Dauwalder if (!error) { 7021c162a3STyler Dauwalder if (stat.st_mode & S_IFREG && ioctl(device, IOCTL_FILE_UNCACHED_IO, NULL) < 0) { 7121c162a3STyler Dauwalder DIE(("Unable to disable cache of underlying file system.\n")); 7221c162a3STyler Dauwalder } 7321c162a3STyler Dauwalder } 7421c162a3STyler Dauwalder 759b8775eaSTyler Dauwalder logical_volume_descriptor logicalVolumeDescriptor; 761379cacaSTyler Dauwalder partition_descriptor partitionDescriptors[Udf::kMaxPartitionDescriptors]; 7721c162a3STyler Dauwalder uint8 partitionDescriptorCount; 7821c162a3STyler Dauwalder uint32 blockShift; 7921c162a3STyler Dauwalder 801379cacaSTyler Dauwalder // Run through the volume recognition and descriptor sequences to 811379cacaSTyler Dauwalder // see if we have a potentially valid UDF volume on our hands 8221c162a3STyler Dauwalder error = udf_recognize(device, offset, length, blockSize, blockShift, 8321c162a3STyler Dauwalder logicalVolumeDescriptor, partitionDescriptors, 8421c162a3STyler Dauwalder partitionDescriptorCount); 8521c162a3STyler Dauwalder 8621c162a3STyler Dauwalder // Set up the block cache 8721c162a3STyler Dauwalder if (!error) 8821c162a3STyler Dauwalder error = init_cache_for_device(device, length); 8921c162a3STyler Dauwalder 90d4e8b936STyler Dauwalder int physicalCount = 0; 91d4e8b936STyler Dauwalder int virtualCount = 0; 92d4e8b936STyler Dauwalder int sparableCount = 0; 93d4e8b936STyler Dauwalder int metadataCount = 0; 94d4e8b936STyler Dauwalder 9521c162a3STyler Dauwalder // Set up the partitions 9621c162a3STyler Dauwalder if (!error) { 9721c162a3STyler Dauwalder // Set up physical and sparable partitions first 9821c162a3STyler Dauwalder int offset = 0; 99d4e8b936STyler Dauwalder for (uint8 i = 0; i < logicalVolumeDescriptor.partition_map_count() 100d4e8b936STyler Dauwalder && !error; i++) 101d4e8b936STyler Dauwalder { 10221c162a3STyler Dauwalder uint8 *maps = logicalVolumeDescriptor.partition_maps(); 1031379cacaSTyler Dauwalder partition_map_header *header = 1041379cacaSTyler Dauwalder reinterpret_cast<partition_map_header*>(maps+offset); 10521c162a3STyler Dauwalder PRINT(("partition map %d (type %d):\n", i, header->type())); 10621c162a3STyler Dauwalder if (header->type() == 1) { 107d4e8b936STyler Dauwalder PRINT(("map type: physical\n")); 1081379cacaSTyler Dauwalder physical_partition_map* map = 1091379cacaSTyler Dauwalder reinterpret_cast<physical_partition_map*>(header); 110d4e8b936STyler Dauwalder // Find the corresponding partition descriptor 1111379cacaSTyler Dauwalder partition_descriptor *descriptor = NULL; 112d4e8b936STyler Dauwalder for (uint8 j = 0; j < partitionDescriptorCount; j++) { 113d4e8b936STyler Dauwalder if (map->partition_number() == 114d4e8b936STyler Dauwalder partitionDescriptors[j].partition_number()) 115d4e8b936STyler Dauwalder { 116d4e8b936STyler Dauwalder descriptor = &partitionDescriptors[j]; 117d4e8b936STyler Dauwalder break; 118d4e8b936STyler Dauwalder } 119d4e8b936STyler Dauwalder } 120d4e8b936STyler Dauwalder // Create and add the partition 121d4e8b936STyler Dauwalder if (descriptor) { 122d4e8b936STyler Dauwalder PhysicalPartition *partition = new PhysicalPartition( 123d4e8b936STyler Dauwalder map->partition_number(), 124d4e8b936STyler Dauwalder descriptor->start(), 125d4e8b936STyler Dauwalder descriptor->length()); 126d4e8b936STyler Dauwalder error = partition ? B_OK : B_NO_MEMORY; 127d4e8b936STyler Dauwalder if (!error) { 128d4e8b936STyler Dauwalder PRINT(("Adding PhysicalPartition(number: %d, start: %ld, " 129d4e8b936STyler Dauwalder "length: %ld)\n", map->partition_number(), 130d4e8b936STyler Dauwalder descriptor->start(), descriptor->length())); 131d4e8b936STyler Dauwalder error = _SetPartition(i, partition); 132d4e8b936STyler Dauwalder if (!error) 133d4e8b936STyler Dauwalder physicalCount++; 134d4e8b936STyler Dauwalder } 13521c162a3STyler Dauwalder } else { 136d4e8b936STyler Dauwalder PRINT(("no matching partition descriptor found!\n")); 137d4e8b936STyler Dauwalder error = B_ERROR; 138d4e8b936STyler Dauwalder } 139d4e8b936STyler Dauwalder } else if (header->type() == 2) { 1401379cacaSTyler Dauwalder // Figure out what kind of type 2 partition map we have based 141d4e8b936STyler Dauwalder // on the type identifier 1421379cacaSTyler Dauwalder const entity_id &typeId = header->partition_type_id(); 143d4e8b936STyler Dauwalder DUMP(typeId); 144d4e8b936STyler Dauwalder DUMP(kSparablePartitionMapId); 145d4e8b936STyler Dauwalder if (typeId.matches(kVirtualPartitionMapId)) { 146d4e8b936STyler Dauwalder PRINT(("map type: virtual\n")); 1471379cacaSTyler Dauwalder virtual_partition_map* map = 1481379cacaSTyler Dauwalder reinterpret_cast<virtual_partition_map*>(header); 149d4e8b936STyler Dauwalder virtualCount++; 150d4e8b936STyler Dauwalder (void)map; // kill the warning for now 151d4e8b936STyler Dauwalder } else if (typeId.matches(kSparablePartitionMapId)) { 152d4e8b936STyler Dauwalder PRINT(("map type: sparable\n")); 1531379cacaSTyler Dauwalder sparable_partition_map* map = 1541379cacaSTyler Dauwalder reinterpret_cast<sparable_partition_map*>(header); 155d4e8b936STyler Dauwalder sparableCount++; 156d4e8b936STyler Dauwalder (void)map; // kill the warning for now 157d4e8b936STyler Dauwalder } else if (typeId.matches(kMetadataPartitionMapId)) { 158d4e8b936STyler Dauwalder PRINT(("map type: metadata\n")); 1591379cacaSTyler Dauwalder metadata_partition_map* map = 1601379cacaSTyler Dauwalder reinterpret_cast<metadata_partition_map*>(header); 161d4e8b936STyler Dauwalder metadataCount++; 162d4e8b936STyler Dauwalder (void)map; // kill the warning for now 163d4e8b936STyler Dauwalder } else { 164d4e8b936STyler Dauwalder PRINT(("map type: unrecognized (`%.23s')\n", 165d4e8b936STyler Dauwalder typeId.identifier())); 166d4e8b936STyler Dauwalder error = B_ERROR; 16721c162a3STyler Dauwalder } 168d4e8b936STyler Dauwalder } else { 169d4e8b936STyler Dauwalder PRINT(("Invalid partition type %d found!\n", header->type())); 170d4e8b936STyler Dauwalder error = B_ERROR; 171d4e8b936STyler Dauwalder } 17221c162a3STyler Dauwalder offset += header->length(); 17321c162a3STyler Dauwalder } 17421c162a3STyler Dauwalder } 17521c162a3STyler Dauwalder 176d4e8b936STyler Dauwalder // Do some checking as to what sorts of partitions we've actually found. 17721c162a3STyler Dauwalder if (!error) { 178d4e8b936STyler Dauwalder error = (physicalCount == 1 && virtualCount == 0 179d4e8b936STyler Dauwalder && sparableCount == 0 && metadataCount == 0) 180d4e8b936STyler Dauwalder || (physicalCount == 2 && virtualCount == 0 181d4e8b936STyler Dauwalder && sparableCount == 0 && metadataCount == 0) 182d4e8b936STyler Dauwalder ? B_OK : B_ERROR; 183d4e8b936STyler Dauwalder if (error) { 184d4e8b936STyler Dauwalder PRINT(("Invalid partition layout found:\n")); 185d4e8b936STyler Dauwalder PRINT((" physical partitions: %d\n", physicalCount)); 186d4e8b936STyler Dauwalder PRINT((" virtual partitions: %d\n", virtualCount)); 187d4e8b936STyler Dauwalder PRINT((" sparable partitions: %d\n", sparableCount)); 188d4e8b936STyler Dauwalder PRINT((" metadata partitions: %d\n", metadataCount)); 189d4e8b936STyler Dauwalder } 190d4e8b936STyler Dauwalder } 191d4e8b936STyler Dauwalder 192d4e8b936STyler Dauwalder // We're now going to start creating Icb's, which will expect 193d4e8b936STyler Dauwalder // certain parts of the volume to be initialized properly. Thus, 194d4e8b936STyler Dauwalder // we initialize those parts here. 195d4e8b936STyler Dauwalder if (!error) { 196d4e8b936STyler Dauwalder fDevice = device; 197d4e8b936STyler Dauwalder fOffset = offset; 198d4e8b936STyler Dauwalder fLength = length; 199d4e8b936STyler Dauwalder fBlockSize = blockSize; 200d4e8b936STyler Dauwalder fBlockShift = blockShift; 201d4e8b936STyler Dauwalder } 202d4e8b936STyler Dauwalder 203d4e8b936STyler Dauwalder // At this point we've found a valid set of volume descriptors and 204d4e8b936STyler Dauwalder // our partitions are all set up. We now need to investigate the file 205d4e8b936STyler Dauwalder // set descriptor pointed to by the logical volume descriptor. 206d4e8b936STyler Dauwalder if (!error) { 207d4e8b936STyler Dauwalder MemoryChunk chunk(logicalVolumeDescriptor.file_set_address().length()); 20821c162a3STyler Dauwalder 209d8b4553aSTyler Dauwalder error = chunk.InitCheck(); 21021c162a3STyler Dauwalder 21121c162a3STyler Dauwalder if (!error) { 212d4e8b936STyler Dauwalder off_t address; 213d4e8b936STyler Dauwalder // Read in the file set descriptor 214d4e8b936STyler Dauwalder error = MapBlock(logicalVolumeDescriptor.file_set_address(), 215d4e8b936STyler Dauwalder &address); 216d4e8b936STyler Dauwalder if (!error) 217d4e8b936STyler Dauwalder address <<= blockShift; 218d4e8b936STyler Dauwalder if (!error) { 219d4e8b936STyler Dauwalder ssize_t bytesRead = read_pos(device, address, chunk.Data(), 220d4e8b936STyler Dauwalder blockSize); 221d8b4553aSTyler Dauwalder if (bytesRead != ssize_t(blockSize)) { 222d4e8b936STyler Dauwalder error = B_IO_ERROR; 223d4e8b936STyler Dauwalder PRINT(("read_pos(pos:%Ld, len:%ld) failed with: 0x%lx\n", 224d4e8b936STyler Dauwalder address, blockSize, bytesRead)); 225d4e8b936STyler Dauwalder } 226d4e8b936STyler Dauwalder } 227d4e8b936STyler Dauwalder // See if it's valid, and if so, create the root icb 22821c162a3STyler Dauwalder if (!error) { 2291379cacaSTyler Dauwalder file_set_descriptor *fileSet = 2301379cacaSTyler Dauwalder reinterpret_cast<file_set_descriptor*>(chunk.Data()); 231*17b66e62STyler Dauwalder PDUMP(fileSet); 232d8b4553aSTyler Dauwalder error = fileSet->tag().id() == TAGID_FILE_SET_DESCRIPTOR 233d8b4553aSTyler Dauwalder ? B_OK : B_ERROR; 234d8b4553aSTyler Dauwalder if (!error) 235*17b66e62STyler Dauwalder error = fileSet->tag().init_check( 236*17b66e62STyler Dauwalder logicalVolumeDescriptor.file_set_address().block()); 237d8b4553aSTyler Dauwalder if (!error) { 23821c162a3STyler Dauwalder PDUMP(fileSet); 23921c162a3STyler Dauwalder fRootIcb = new Icb(this, fileSet->root_directory_icb()); 24021c162a3STyler Dauwalder error = fRootIcb ? fRootIcb->InitCheck() : B_NO_MEMORY; 241d8b4553aSTyler Dauwalder } 24221c162a3STyler Dauwalder if (!error) { 24321c162a3STyler Dauwalder error = new_vnode(Id(), RootIcb()->Id(), (void*)RootIcb()); 24421c162a3STyler Dauwalder if (error) { 245d4e8b936STyler Dauwalder PRINT(("Error creating vnode for root icb! " 246d4e8b936STyler Dauwalder "error = 0x%lx, `%s'\n", error, 247d4e8b936STyler Dauwalder strerror(error))); 248d4e8b936STyler Dauwalder // Clean up the icb we created, since _Unset() 249d4e8b936STyler Dauwalder // won't do this for us. 250d4e8b936STyler Dauwalder delete fRootIcb; 251d4e8b936STyler Dauwalder fRootIcb = NULL; 252d4e8b936STyler Dauwalder } 253d4e8b936STyler Dauwalder } 254d4e8b936STyler Dauwalder } 25521c162a3STyler Dauwalder } 25621c162a3STyler Dauwalder } 25721c162a3STyler Dauwalder 258d4e8b936STyler Dauwalder // If we've made it this far, we're good to go; set the volume 259d4e8b936STyler Dauwalder // name and then flag that we're mounted. On the other hand, if 260d4e8b936STyler Dauwalder // an error occurred, we need to clean things up. 26121c162a3STyler Dauwalder if (!error) { 262d4e8b936STyler Dauwalder fName.SetTo(logicalVolumeDescriptor.logical_volume_identifier()); 263d4e8b936STyler Dauwalder fMounted = true; 264d4e8b936STyler Dauwalder } else { 265d4e8b936STyler Dauwalder _Unset(); 26621c162a3STyler Dauwalder } 26721c162a3STyler Dauwalder 26821c162a3STyler Dauwalder RETURN(error); 2694ac73018STyler Dauwalder } 2704ac73018STyler Dauwalder 271a71fd512STyler Dauwalder const char* 272a71fd512STyler Dauwalder Volume::Name() const { 273dce2dc5cSTyler Dauwalder return fName.Utf8(); 274a71fd512STyler Dauwalder } 2753f4628f1STyler Dauwalder 276d4e8b936STyler Dauwalder /*! \brief Maps the given logical block to a physical block. 2773f4628f1STyler Dauwalder */ 2783f4628f1STyler Dauwalder status_t 2791379cacaSTyler Dauwalder Volume::MapBlock(long_address address, off_t *mappedBlock) 2800d383564STyler Dauwalder { 28121ea9aeaSTyler Dauwalder DEBUG_INIT_ETC("Volume", 2821379cacaSTyler Dauwalder ("partition: %d, block: %ld, mappedBlock: %p", 2831379cacaSTyler Dauwalder address.partition(), address.block(), mappedBlock)); 284d4e8b936STyler Dauwalder status_t error = mappedBlock ? B_OK : B_BAD_VALUE; 285d4e8b936STyler Dauwalder if (!error) { 286d4e8b936STyler Dauwalder Partition *partition = _GetPartition(address.partition()); 287d4e8b936STyler Dauwalder error = partition ? B_OK : B_BAD_ADDRESS; 288d4e8b936STyler Dauwalder if (!error) 289d4e8b936STyler Dauwalder error = partition->MapBlock(address.block(), *mappedBlock); 2903f4628f1STyler Dauwalder } 291d4e8b936STyler Dauwalder RETURN(error); 2923f4628f1STyler Dauwalder } 2933f4628f1STyler Dauwalder 294d4e8b936STyler Dauwalder /*! \brief Unsets the volume and deletes any partitions. 295d4e8b936STyler Dauwalder 296d4e8b936STyler Dauwalder Does *not* delete the root icb object. 297d4e8b936STyler Dauwalder */ 298d4e8b936STyler Dauwalder void 299d4e8b936STyler Dauwalder Volume::_Unset() 300d4e8b936STyler Dauwalder { 301d8b4553aSTyler Dauwalder DEBUG_INIT("Volume"); 302d4e8b936STyler Dauwalder fId = 0; 303d4e8b936STyler Dauwalder fDevice = 0; 304d4e8b936STyler Dauwalder fMounted = false; 305d4e8b936STyler Dauwalder fOffset = 0; 306d4e8b936STyler Dauwalder fLength = 0; 307d4e8b936STyler Dauwalder fBlockSize = 0; 308d4e8b936STyler Dauwalder fBlockShift = 0; 309dce2dc5cSTyler Dauwalder fName.SetTo("", 0); 310d4e8b936STyler Dauwalder // delete our partitions 311d4e8b936STyler Dauwalder for (int i = 0; i < UDF_MAX_PARTITION_MAPS; i++) 312d4e8b936STyler Dauwalder _SetPartition(i, NULL); 313d4e8b936STyler Dauwalder } 314d4e8b936STyler Dauwalder 315d4e8b936STyler Dauwalder /*! \brief Sets the partition associated with the given number after 316d4e8b936STyler Dauwalder deleting any previously associated partition. 317d4e8b936STyler Dauwalder 318d4e8b936STyler Dauwalder \param number The partition number (should be the same as the index 319d4e8b936STyler Dauwalder into the lvd's partition map array). 320d4e8b936STyler Dauwalder \param partition The new partition (may be NULL). 3213f4628f1STyler Dauwalder */ 3223f4628f1STyler Dauwalder status_t 323d4e8b936STyler Dauwalder Volume::_SetPartition(uint number, Partition *partition) 3243f4628f1STyler Dauwalder { 325d4e8b936STyler Dauwalder status_t error = number < UDF_MAX_PARTITION_MAPS 326d4e8b936STyler Dauwalder ? B_OK : B_BAD_VALUE; 327d4e8b936STyler Dauwalder if (!error) { 328d4e8b936STyler Dauwalder delete fPartitions[number]; 329d4e8b936STyler Dauwalder fPartitions[number] = partition; 3303f4628f1STyler Dauwalder } 331d4e8b936STyler Dauwalder return error; 3320d383564STyler Dauwalder } 3330d383564STyler Dauwalder 334d4e8b936STyler Dauwalder /*! \brief Returns the partition associated with the given number, or 335d4e8b936STyler Dauwalder NULL if no such partition exists or the number is invalid. 3363f4628f1STyler Dauwalder */ 337d4e8b936STyler Dauwalder Partition* 338d4e8b936STyler Dauwalder Volume::_GetPartition(uint number) 3393f4628f1STyler Dauwalder { 340d4e8b936STyler Dauwalder return (number < UDF_MAX_PARTITION_MAPS) 341d4e8b936STyler Dauwalder ? fPartitions[number] : NULL; 3423f4628f1STyler Dauwalder } 3433f4628f1STyler Dauwalder 344