From 22aef14b9343a612612eac40523e93aa19cbebfd Mon Sep 17 00:00:00 2001 From: Tyler Dauwalder Date: Tue, 31 Dec 2002 07:22:12 +0000 Subject: [PATCH] Initial working iso9660 disk scanner fs module git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2325 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/disk_scanner/fs/iso9660.c | 264 +++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 src/add-ons/kernel/disk_scanner/fs/iso9660.c diff --git a/src/add-ons/kernel/disk_scanner/fs/iso9660.c b/src/add-ons/kernel/disk_scanner/fs/iso9660.c new file mode 100644 index 0000000000..7869fc4b76 --- /dev/null +++ b/src/add-ons/kernel/disk_scanner/fs/iso9660.c @@ -0,0 +1,264 @@ +// iso9660.c + +#include +#include +#include +#include + +#include +#include +#include + +#define TRACE(x) +//#define TRACE(x) dprintf x + +// misc constants +#define ISO9660_FS_MODULE_NAME "disk_scanner/fs/iso9660/v1" +static const char *kModuleDebugName = "fs/iso9660"; +static const char *kISO9660Signature = "CD001"; +static const uint32 kVolumeDescriptorLength = 2048; +#define ISO9660_VOLUME_IDENTIFIER_LENGTH 32 + +typedef struct iso9660_common_volume_descriptor { + uchar volume_descriptor_type; + uchar standard_identifier[5]; // should be 'CD001' + uchar volume_descriptor_version; + // Remaining bytes are unused +} iso9660_common_volume_descriptor; + +typedef struct iso9660_primary_volume_descriptor { + iso9660_common_volume_descriptor info; + uchar volume_flags; + uchar system_identifier[32]; + uchar volume_identifier[ISO9660_VOLUME_IDENTIFIER_LENGTH]; + // Remaining bytes are disinteresting to us +} iso9660_primary_volume_descriptor; + +// volume descriptor types +typedef enum { + ISO9660VD_BOOT, + ISO9660VD_PRIMARY, + ISO9660VD_SUPPLEMENTARY, + ISO9660VD_PARTITION, + ISO9660VD_TERMINATOR = 255 +} iso9660_volume_descriptor_type; + +static +const char* +volume_descriptor_type_to_string(iso9660_volume_descriptor_type type) +{ + switch (type) { + case ISO9660VD_BOOT: return "boot"; + case ISO9660VD_PRIMARY: return "primary"; + case ISO9660VD_SUPPLEMENTARY: return "supplementary"; + case ISO9660VD_PARTITION: return "partiton"; + case ISO9660VD_TERMINATOR: return "terminator"; + default: return "invalid"; + } +} + +static +void +dump_common_volume_descriptor(iso9660_common_volume_descriptor *common, const char *indent, + bool print_header) +{ + if (print_header) + TRACE(("%siso9660_common_volume_descriptor:\n", indent)); + + TRACE(("%s volume_descriptor_type == %d (%s)\n", indent, + common->volume_descriptor_type, + volume_descriptor_type_to_string(common->volume_descriptor_type))); + TRACE(("%s standard_identifier == %.5s (%s)\n", indent, common->standard_identifier, + strncmp(common->standard_identifier, kISO9660Signature, 5) == 0 ? "valid" : "INVALID")); + TRACE(("%s volume_descriptor_version == %d\n", indent, common->volume_descriptor_version)); +} + +static +void +dump_primary_volume_descriptor(iso9660_primary_volume_descriptor *primary, const char *indent, + bool print_header) +{ + if (print_header) + TRACE(("%siso9660_primary_volume_descriptor:\n", indent)); + + dump_common_volume_descriptor(&(primary->info), indent, false); + TRACE(("%s volume_identifier == %.32s\n", indent, + primary->volume_identifier)); +} + +static +status_t +check_common_volume_descriptor(iso9660_common_volume_descriptor *common) +{ + status_t error = common ? B_OK : B_BAD_VALUE; + if (!error) + error = strncmp(common->standard_identifier, kISO9660Signature, + 5) == 0 ? B_OK : B_BAD_DATA; + return error; +} + +// std_ops +static +status_t +std_ops(int32 op, ...) +{ + TRACE(("%s: std_ops(0x%lx)\n", kModuleDebugName, op)); + switch(op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + } + return B_ERROR; +} + +// read_block +static +status_t +read_block(int fd, off_t offset, size_t size, uchar **block) +{ + status_t error = (block && size > 0 ? B_OK : B_BAD_VALUE); + if (error == B_OK) { + *block = malloc(size); + if (*block) { + if (read_pos(fd, offset, *block, size) != (ssize_t)size) { + error = errno; + if (error == B_OK) + error = B_ERROR; + free(*block); + *block = NULL; + } + } else + error = B_NO_MEMORY; + } + return error; +} + +// iso9660_fs_identify +/*! \brief Returns true if the given partition is a valid iso9660 partition. + + See fs_identify_hook() for more information. + + \todo Fill in partitionInfo->mounted_at with something useful. +*/ +static +bool +iso9660_fs_identify(int deviceFD, struct extended_partition_info *partitionInfo, + float *priority) +{ + bool result = false; + uchar *buffer = NULL; + uint32 blockSize = partitionInfo->info.logical_block_size; + bool exit = false; + off_t offset = partitionInfo->info.offset + 16*blockSize; + status_t error = B_OK; + + TRACE(("%s: identify(%d, %p)\n", kModuleDebugName, deviceFD, + partitionInfo)); + + // Read through the volume descriptors looking for a primary descriptor. + // If for some reason there are more than one primary descriptor, the + // volume name from the last encountered descriptor will be used. + while (!error && !exit) { + iso9660_common_volume_descriptor *common = NULL; + + // Read the block containing the current descriptor + error = read_block(deviceFD, offset, blockSize, &buffer); + offset += blockSize; + if (!error) { + common = (iso9660_common_volume_descriptor*)buffer; + error = check_common_volume_descriptor(common); + } + + // Handle each type of descriptor appropriately + if (!error) { + TRACE(("%s: found %s descriptor\n", kModuleDebugName, + volume_descriptor_type_to_string(common->volume_descriptor_type))); + + switch (common->volume_descriptor_type) { + case ISO9660VD_BOOT: + break; + + case ISO9660VD_PRIMARY: + { + int i; + iso9660_primary_volume_descriptor *primary = (iso9660_primary_volume_descriptor*)buffer; + + dump_primary_volume_descriptor(primary, " ", true); + + if (partitionInfo->file_system_short_name) + strcpy(partitionInfo->file_system_short_name, "iso9660"); + if (partitionInfo->file_system_long_name) + strcpy(partitionInfo->file_system_long_name, "iso9660 CD-ROM File System"); + + // Cut off any trailing spaces from the volume id. Note + // that this allows for spaces INSIDE the volume id, even + // though that's not technically allowed by the standard; + // this was necessary to support certain RedHat 6.2 CD-ROMs + // from a certain Linux company who shall remain unnamed. ;-) + for (i = ISO9660_VOLUME_IDENTIFIER_LENGTH-1; i >= 0; i--) { + if (primary->volume_identifier[i] != 0x20) + break; + } + if (partitionInfo->volume_name) + strncpy(partitionInfo->volume_name, primary->volume_identifier, i+1); + + if (priority) + *priority = 0; + result = true; + break; + } + + case ISO9660VD_SUPPLEMENTARY: + break; + + case ISO9660VD_PARTITION: + break; + + case ISO9660VD_TERMINATOR: + exit = true; + break; + + default: + break; + } + } + if (buffer) { + free(buffer); + buffer = NULL; + } + } + + switch (error) { + case B_OK: + break; + + case B_BAD_DATA: + TRACE(("%s: identify: bad signature\n", kModuleDebugName)); + break; + + default: + TRACE(("%s: identify error: 0x%lx\n", kModuleDebugName, + error)); + break; + } + + return result; +} + +static fs_module_info iso9660_fs_module = +{ + // module_info + { + ISO9660_FS_MODULE_NAME, + 0, // better B_KEEP_LOADED? + std_ops + }, + iso9660_fs_identify, +}; + +_EXPORT fs_module_info *modules[] = +{ + &iso9660_fs_module, + NULL +}; +