diff --git a/src/add-ons/kernel/file_systems/udf/DiskStructures.cpp b/src/add-ons/kernel/file_systems/udf/DiskStructures.cpp index 47922dbff3..091a05547f 100644 --- a/src/add-ons/kernel/file_systems/udf/DiskStructures.cpp +++ b/src/add-ons/kernel/file_systems/udf/DiskStructures.cpp @@ -28,17 +28,26 @@ const charspec kCS0Charspec = { character_set_type: 0, // udf_tag //---------------------------------------------------------------------- -/*! \brief Calculates the tag's CRC and verifies the tag's location on - the medium. +/*! \brief Calculates the tag's CRC, verifies the tag's checksum, and + verifies the tag's location on the medium. \todo Calc the CRC. */ status_t descriptor_tag::init_check(off_t diskLocation) { - if (diskLocation == (off_t)location) - return B_OK; - else - return B_NO_INIT; + status_t err = (diskLocation == (off_t)location) ? B_OK : B_NO_INIT; + // checksum + if (!err) { + uint32 sum = 0; + for (int i = 0; i <= 3; i++) + sum += ((uint8*)this)[i]; + for (int i = 5; i <= 15; i++) + sum += ((uint8*)this)[i]; + err = sum % 256 == checksum ? B_OK : B_NO_INIT; + } + + return err; + } diff --git a/src/add-ons/kernel/file_systems/udf/DiskStructures.h b/src/add-ons/kernel/file_systems/udf/DiskStructures.h index 5fb0656cb5..b1c86c10a5 100644 --- a/src/add-ons/kernel/file_systems/udf/DiskStructures.h +++ b/src/add-ons/kernel/file_systems/udf/DiskStructures.h @@ -13,50 +13,25 @@ /*! \file DiskStructures.h - UDF on-disk data structure declarations + \brief UDF on-disk data structure declarations + + UDF is a specialization of the ECMA-167 standard. For the most part, + ECMA-167 structures are used by UDF with special restrictions. In a + few instances, UDF introduces its own structures to augment those + supplied by ECMA-167; those structures are clearly marked. + + For UDF info: http://www.osta.org + For ECMA info: http://www.ecma-international.org + + \todo Add in comments about max struct sizes from UDF-2.01 + */ namespace UDF { -/*! \brief Header for volume structure descriptors - - Each descriptor consumes an entire block. All unused trailing - bytes in the descriptor should be set to 0. - - The following descriptors contain no more information than - that contained in the header: - - - BEA01: - - type: 0 - - id: "BEA01" - - version: 1 - - - TEA01: - - type: 0 - - id: "TEA01" - - version: 1 - - - NSR03: - - type: 0 - - id: "NSR03" - - version: 1 -*/ -struct vsd_header { - uint8 type; - char id[4]; - uint8 version; -} __attribute__((packed)); - - -// Volume structure descriptor ids -const char* kVSDID_BEA = "BEA01"; -const char* kVSDID_TEA = "TEA01"; -const char* kVSDID_BOOT = "BOOT2"; -const char* kVSDID_ISO = "CD001"; -const char* kVSDID_ECMA167_2 = "NSR02"; -const char* kVSDID_ECMA167_3 = "NSR03"; -const char* kVSDID_ECMA168 = "CDW02"; - +//---------------------------------------------------------------------- +// ECMA-167 Part 1 +//---------------------------------------------------------------------- /*! \brief Character set specifications @@ -96,16 +71,6 @@ struct timestamp { } __attribute__((packed)); -/*! \brief Location and length of a contiguous chunk of data - - See also: ECMA 167 3/7.1 -*/ -struct extent_address { - uint32 length; - uint32 location; -} __attribute__((packed)); - - /*! \brief Identifier used to designate the implementation responsible for writing associated data structures on the medium. @@ -118,17 +83,100 @@ struct entity_id { } __attribute__((packed)); -/*! \brief Common tag found at the beginning of most udf descriptor structures +//---------------------------------------------------------------------- +// ECMA-167 Part 2 +//---------------------------------------------------------------------- + + +/*! \brief Header for volume structure descriptors + + Each descriptor consumes an entire block. All unused trailing + bytes in the descriptor should be set to 0. + + The following descriptors contain no more information than + that contained in the header: + + - BEA01: + - type: 0 + - id: "BEA01" + - version: 1 + + - TEA01: + - type: 0 + - id: "TEA01" + - version: 1 + + - NSR03: + - type: 0 + - id: "NSR03" + - version: 1 + + See also: ECMA 167 2/9.1 +*/ +struct vsd_header { + uint8 type; + char id[4]; + uint8 version; +} __attribute__((packed)); + + +// Volume structure descriptor ids +const char* kVSDID_BEA = "BEA01"; +const char* kVSDID_TEA = "TEA01"; +const char* kVSDID_BOOT = "BOOT2"; +const char* kVSDID_ISO = "CD001"; +const char* kVSDID_ECMA167_2 = "NSR02"; +const char* kVSDID_ECMA167_3 = "NSR03"; +const char* kVSDID_ECMA168 = "CDW02"; + + +//---------------------------------------------------------------------- +// ECMA-167 Part 3 +//---------------------------------------------------------------------- + + +/*! \brief Location and length of a contiguous chunk of data + + See also: ECMA 167 3/7.1 +*/ +struct extent_address { + uint32 length; + uint32 location; +} __attribute__((packed)); + + +/*! \brief Common tag found at the beginning of most udf descriptor structures. + + For error checking, \c descriptor_tag structures have: + - The disk location of the tag redundantly stored in the tag itself + - A checksum value for the tag + - A CRC value and length + + See also: ECMA 167 1/7.2, UDF 2.01 2.2.1, UDF 2.01 2.3.1 */ struct descriptor_tag { uint16 id; uint16 version; - uint8 checksum; - uint8 reserved; // #00 + uint8 checksum; //!< Sum modulo 256 of bytes 0-3 and 5-15 of this struct. + uint8 reserved; //!< Set to #00. uint16 serial_number; - uint16 crc; + uint16 crc; //!< May be 0 if \c crc_length field is 0. + /*! \brief Length of the data chunk used to calculate CRC. + + If 0, no CRC was calculated, and the \c crc field must be 0. + + According to UDF-2.01 2.3.1.2, the CRC shall be calculated for all descriptors + unless otherwise noted, and this field shall be set to: + + (descriptor length) - (descriptor tag length) + */ uint16 crc_length; - uint32 location; // address of udf_tag struct for error checking + /*! \brief Address of this tag within its partition (for error checking). + + For virtually addressed structures (i.e. those accessed thru a VAT), this + shall be the virtual address, not the physical or logical address. + */ + uint32 location; status_t init_check(off_t diskLocation); } __attribute__((packed)); @@ -165,7 +213,7 @@ enum { TAGID_SPACE_BITMAP_DESCRIPTOR, TAGID_PARTITION_INTEGRITY_ENTRY, TAGID_EXTENDED_FILE_ENTRY, -} udf_tag_id; +} tag_id; /*! \brief Primary volume descriptor @@ -326,10 +374,14 @@ struct logical_vd { */ entity_id domain_id; - /*! \brief For UDF, shall contain a \c long_address which identifies - the location of the logical volume's first file set. - */ - uint8 logical_volume_contents_use[16]; + union { + /*! \brief For UDF, shall contain a \c long_allocation_descriptor which identifies + the location of the logical volume's first file set. + */ + uint8 logical_volume_contents_use[16]; + extent_address file_set_address; + }; + uint32 map_table_length; uint32 partition_map_count; entity_id implementation_id; @@ -345,13 +397,13 @@ struct logical_vd { extent_address integrity_sequence_extent; /*! \brief Restricted to maps of type 1 for normal maps and - type 2 for virtual maps or maps on systems not supporting + UDF type 2 for virtual maps or maps on systems not supporting defect management. See UDF-2.01 2.2.8, 2.2.9 */ uint8 partition_maps[0]; -}; +} __attribute__((packed)); /*! \brief Generic partition map @@ -362,7 +414,8 @@ struct generic_partition_map { uint8 type; uint8 length; uint8 map_data[0]; -}; +} __attribute__((packed)); + /*! \brief Physical partition map (i.e. ECMA-167 Type 1 partition map) @@ -373,8 +426,10 @@ struct physical_partition_map { uint8 length; uint16 volume_sequence_number; uint16 partition_number; -}; +} __attribute__((packed)); + +/* ----UDF Specific---- */ /*! \brief Virtual partition map (i.e. UDF Type 2 partition map) Note that this differs from the ECMA-167 type 2 partition map, @@ -400,7 +455,8 @@ struct virtual_partition_map { */ uint16 partition_number; uint8 reserved2[24]; -}; +} __attribute__((packed)); + /*! \brief Unallocated space descriptor @@ -451,6 +507,339 @@ enum { LVIT_CLOSED, }; +//---------------------------------------------------------------------- +// ECMA-167 Part 4 +//---------------------------------------------------------------------- + + +/*! \brief Location of a logical block within a logical volume. + + See also: ECMA 167 4/7.1 +*/ +struct logical_block_address { + uint32 location; //!< Block location relative to start of corresponding partition + uint16 partition; //!< Numeric partition id within logical volume +} __attribute__((packed)); + + +/*! \brief Allocation descriptor. + + See also: ECMA 167 4/14.14.1 +*/ +struct short_allocation_descriptor { + uint32 length; + logical_block_address location; +} __attribute__((packed)); + + +/*! \brief Allocation descriptor w/ 6 byte implementation use field. + + See also: ECMA 167 4/14.14.2 +*/ +struct long_allocation_descriptor { + uint32 length; + logical_block_address location; + uchar implementation_use[6]; +} __attribute__((packed)); + + +/*! \brief File set descriptor + + Contains all the pertinent info about a file set (i.e. a hierarchy of files) + + According to UDF-2.01, only one file set descriptor shall be recorded, + except on WORM media, where the following rules apply: + - Multiple file sets are allowed only on WORM media + - The default file set shall be the one with highest value \c file_set_number field. + - Only the default file set may be flagged as writeable. All others shall be + flagged as "hard write protect". + - No writeable file set may reference metadata structures which are referenced + (directly or indirectly) by any other file set. Writeable file sets may, however, + reference actual file data extents that are also referenced by other file sets. +*/ +struct file_set_descriptor { + descriptor_tag tag; + timestamp recording_date_and_time; + uint16 interchange_level; //!< To be set to 3 (see UDF-2.01 2.3.2.1) + uint16 max_interchange_level; //!< To be set to 3 (see UDF-2.01 2.3.2.2) + uint32 character_set_list; + uint32 max_character_set_list; + uint32 file_set_number; + uint32 file_set_descriptor_number; + charspec logical_volume_id_character_set; //!< To be set to kCSOCharspec + char logical_volume_id[128]; + charspec file_set_charspec; + char file_set_id[32]; + char copyright_file_id[32]; + char abstract_file_id[32]; + long_allocation_descriptor root_directory_icb; + entity_id domain_id; + long_allocation_descriptor next_extent; + long_allocation_descriptor system_stream_directory_icb; + uint8 reserved[32]; +} __attribute__((packed)); + + +/*! \brief Partition header descriptor + + Contains references to unallocated and freed space data structures. + + Note that unallocated space is space ready to be written with no + preprocessing. Freed space is space needing preprocessing (i.e. + a special write pass) before use. + + Per UDF-2.01 2.3.3, the use of tables or bitmaps shall be consistent, + i.e. only one type or the other shall be used, not both. + + To indicate disuse of a certain field, the fields of the allocation + descriptor shall all be set to 0. + + See also: ECMA-167 4/14.3, UDF-2.01 2.2.3 +*/ +struct partition_header_descriptor { + short_allocation_descriptor unallocated_space_table; + short_allocation_descriptor unallocated_space_bitmap; + /*! Unused, per UDF-2.01 2.2.3 */ + short_allocation_descriptor partition_integrity_table; + short_allocation_descriptor freed_space_table; + short_allocation_descriptor freed_space_bitmap; + uint8 reserved[88]; +} __attribute__((packed)); + + +/*! \brief File identifier descriptor + + Identifies the name of a file entry, and the location of its corresponding + ICB. + + See also: ECMA-167 4/14.4, UDF-2.01 2.3.4 + + \todo Check pointer arithmetic +*/ +struct file_id_descriptor { + descriptor_tag tag; + /*! According to ECMA-167: 1 <= valid version_number <= 32767, 32768 <= reserved <= 65535. + + However, according to UDF-2.01, there shall be exactly one version of + a file, and it shall be 1. + */ + uint16 version_number; + /*! \todo Check UDF-2.01 2.3.4.2 for some more restrictions. */ + union { + uint8 characteristics; + uint8 may_be_hidden:1, + is_directory:1, + is_deleted:1, + is_parent:1, + is_metadata_stream:1, + reserved_characteristics:3; + }; + uint8 id_length; + long_allocation_descriptor icb; + uint8 implementation_use_length; + + /*! If implementation_use_length is greater than 0, the first 32 + bytes of implementation_use() shall be an entity_id identifying + the implementation that generated the rest of the data in the + implementation_use() field. + */ + uint8* implementation_use() { return (uint8*)(this+38); } + char* id() { return (char*)(this+38+implementation_use_length); } + +} __attribute__((packed)); + + +/*! \brief Allocation extent descriptor + + See also: ECMA-167 4/14.5 +*/ +struct allocation_extent_descriptor { + descriptor_tag tag; + uint32 previous_allocation_extent_location; + uint32 length_of_allocation_descriptors; + + /*! \todo Check that this is really how things work: */ + uint8* allocation_descriptors() { return (uint8*)(this+sizeof(allocation_extent_descriptor)); } +} __attribute__((packed)); + + +/*! \brief icb_tag::file_type values + + See also ECMA-167 4/14.6.6 +*/ +enum icb_file_types { + ICB_TYPE_UNSPECIFIED = 0, + ICB_TYPE_UNALLOCATED_SPACE_ENTRY, + ICB_TYPE_PARTITION_INTEGRITY_ENTRY, + ICB_TYPE_INDIRECT_ENTRY, + ICB_TYPE_DIRECTORY, + ICB_TYPE_REGULAR_FILE, + ICB_TYPE_BLOCK_SPECIAL_DEVICE, + ICB_TYPE_CHARACTER_SPECIAL_DEVICE, + ICB_TYPE_EXTENDED_ATTRIBUTES_FILE, + ICB_TYPE_FIFO, + ICB_TYPE_ISSOCK, + ICB_TYPE_TERMINAL, + ICB_TYPE_SYMLINK, + ICB_TYPE_STREAM_DIRECTORY, + + ICB_TYPE_RESERVED_START = 14, + ICB_TYPE_RESERVED_END = 247, + + ICB_TYPE_CUSTOM_START = 248, + ICB_TYPE_CUSTOM_END = 255, +}; + + +/*! \brief ICB entry tag + + Common tag found in all ICB entries (in addition to, and immediately following, + the descriptor tag). + + See also: ECMA-167 4/14.6, UDF-2.01 2.3.5 +*/ +struct icb_entry_tag { + uint32 prior_recorded_number_of_direct_entries; + /*! Per UDF-2.01 2.3.5.1, only strategy types 4 and 4096 shall be supported. + + \todo Describe strategy types here. + */ + uint16 strategy_type; + uint8 strategy_parameters[2]; + uint16 entry_count; + uint8 reserved; + /*! \brief icb_file_type value identifying the type of this icb entry */ + uint8 file_type; + logical_block_address parent_icb_location; + union { + uint16 flags; + uint16 descriptor_flags:3, + if_directory_then_sort:1, //!< To be set to 0 per UDF-2.01 2.3.5.4 + non_relocatable:1, + archive:1, + setuid:1, + setgid:1, + sticky:1, + contiguous:1, + system:1, + transformed:1, + multi_version:1, //!< To be set to 0 per UDF-2.01 2.3.5.4 + is_stream:1, + reserved_icb_entry_flags:2; + }; +} __attribute__((packed)); + + +/*! \brief Indirect ICB entry +*/ +struct indirect_icb_entry { + descriptor_tag tag; + icb_entry_tag icb_tag; + long_allocation_descriptor indirect_icb; +} __attribute__((packed)); + + +/*! \brief Terminal ICB entry +*/ +struct terminal_icb_entry { + descriptor_tag tag; + icb_entry_tag icb_tag; +} __attribute__((packed)); + + +/*! \brief File ICB entry + + See also: ECMA-167 4/14.9 + + \todo Check pointer math. +*/ +struct file_icb_entry { + descriptor_tag tag; + icb_entry_tag icb_tag; + uint32 uid; + uint32 gid; + /*! \todo List perms in comment and add handy union thingy */ + uint32 permissions; + /*! Identifies the number of file identifier descriptors referencing + this icb. + */ + uint16 file_link_count; + uint8 record_format; //!< To be set to 0 per UDF-2.01 2.3.6.1 + uint8 record_display_attributes; //!< To be set to 0 per UDF-2.01 2.3.6.2 + uint8 record_length; //!< To be set to 0 per UDF-2.01 2.3.6.3 + uint64 information_length; + uint64 logical_blocks_recorded; //!< To be 0 for files and dirs with embedded data + timestamp access_date_and_time; + timestamp modification_date_and_time; + timestamp attribute_date_and_time; + /*! \brief Initially 1, may be incremented upon user request. */ + uint32 checkpoint; + long_allocation_descriptor extended_attribute_icb; + entity_id implementation_id; + /*! \brief The unique id identifying this file entry + + The id of the root directory of a file set shall be 0. + + \todo Detail the system specific requirements for unique ids from UDF-2.01 + */ + uint64 unique_id; + uint32 extended_attributes_length; + uint32 allocation_descriptors_length; + + uint8* extended_attributes() { return (uint8*)(this+sizeof(file_icb_entry)); } + uint8* allocation_descriptors() { return (uint8*)(this+sizeof(file_icb_entry)+extended_attributes_length); } + +} __attribute__((packed)); + + +/*! \brief Extended file ICB entry + + See also: ECMA-167 4/14.17 + + \todo Check pointer math. +*/ +struct extended_file_icb_entry { + descriptor_tag tag; + icb_entry_tag icb_tag; + uint32 uid; + uint32 gid; + /*! \todo List perms in comment and add handy union thingy */ + uint32 permissions; + /*! Identifies the number of file identifier descriptors referencing + this icb. + */ + uint16 file_link_count; + uint8 record_format; //!< To be set to 0 per UDF-2.01 2.3.6.1 + uint8 record_display_attributes; //!< To be set to 0 per UDF-2.01 2.3.6.2 + uint8 record_length; //!< To be set to 0 per UDF-2.01 2.3.6.3 + uint64 information_length; + uint64 logical_blocks_recorded; //!< To be 0 for files and dirs with embedded data + timestamp access_date_and_time; + timestamp modification_date_and_time; + timestamp creation_date_and_time; + timestamp attribute_date_and_time; + /*! \brief Initially 1, may be incremented upon user request. */ + uint32 checkpoint; + uint32 reserved; + long_allocation_descriptor extended_attribute_icb; + long_allocation_descriptor stream_directory_icb; + entity_id implementation_id; + /*! \brief The unique id identifying this file entry + + The id of the root directory of a file set shall be 0. + + \todo Detail the system specific requirements for unique ids from UDF-2.01 + */ + uint64 unique_id; + uint32 extended_attributes_length; + uint32 allocation_descriptors_length; + + uint8* extended_attributes() { return (uint8*)(this+sizeof(file_icb_entry)); } + uint8* allocation_descriptors() { return (uint8*)(this+sizeof(file_icb_entry)+extended_attributes_length); } + +} __attribute__((packed)); + + }; // namespace UDF #endif // _UDF_DISK_STRUCTURES_H