From: Pali Rohár Date: Mon, 15 Dec 2014 17:28:42 +0000 (+0100) Subject: libblkid: udf: Fix reading LABEL, add support for UUID and other udf identifiers X-Git-Tag: v2.26-rc1~63^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2f2730bc77c972d613cfec421468c84f15749708;p=thirdparty%2Futil-linux.git libblkid: udf: Fix reading LABEL, add support for UUID and other udf identifiers --- diff --git a/libblkid/src/superblocks/udf.c b/libblkid/src/superblocks/udf.c index 5cde3cc2af..2a2c9e60c9 100644 --- a/libblkid/src/superblocks/udf.c +++ b/libblkid/src/superblocks/udf.c @@ -19,6 +19,16 @@ #include "superblocks.h" #include "iso9660.h" +struct dstring128 { + uint8_t clen; + uint8_t c[127]; +} __attribute__((packed)); + +struct dstring32 { + uint8_t clen; + uint8_t c[31]; +} __attribute__((packed)); + struct volume_descriptor { struct descriptor_tag { uint16_t id; @@ -40,12 +50,21 @@ struct volume_descriptor { struct primary_descriptor { uint32_t seq_num; uint32_t desc_num; - struct dstring { - uint8_t clen; - uint8_t c[31]; - } __attribute__((packed)) ident; + struct dstring32 ident; + uint16_t vds_num; + uint16_t max_vol_seq; + uint16_t ichg_lvl; + uint16_t max_ichg_lvl; + uint32_t charset_list; + uint32_t max_charset_list; + struct dstring128 volset_id; } __attribute__((packed)) primary; + struct logical_descriptor { + uint32_t seq_num; + uint8_t desc_charset[64]; + struct dstring128 logvol_id; + } __attribute__((packed)) logical; } __attribute__((packed)) type; } __attribute__((packed)); @@ -58,6 +77,52 @@ struct volume_structure_descriptor { #define UDF_VSD_OFFSET 0x8000LL +static inline int gen_uuid_from_volset_id(unsigned char uuid[17], struct dstring128 *volset_id) +{ + size_t i; + size_t len; + size_t binpos; + unsigned char buf[128]; + + if (volset_id->clen == 8) + memcpy(buf, volset_id->c, 16); + else if (volset_id->clen == 16) + blkid_encode_to_utf8(BLKID_ENC_UTF16BE, buf, sizeof(buf), volset_id->c, 127); + else + return -1; + + buf[16] = 0; + len = strlen(buf); + + if (len < 8) + return -1; + + for (i = len; i < 16; ++i) + buf[i] = 0; + + binpos = 16; + for (i = 0; i < len; ++i) { + if (!isalnum(buf[i])) { + binpos = i; + break; + } + } + + if (binpos < 8) { + for (i = 0; i < 8; ++i) + snprintf(uuid+2*i, 3, "%02x", buf[i]); + } else if (binpos < 16) { + memcpy(uuid, buf, 8); + for (i = 0; i < 4; ++i) + snprintf(uuid+8+2*i, 3, "%02x", buf[8+i]); + } else { + memcpy(uuid, buf, 16); + uuid[16] = 0; + } + + return 0; +} + static int probe_udf(blkid_probe pr, const struct blkid_idmag *mag __attribute__((__unused__))) { @@ -70,6 +135,11 @@ static int probe_udf(blkid_probe pr, unsigned int count; unsigned int loc; unsigned int i; + int have_label = 0; + int have_uuid = 0; + int have_logvolid = 0; + int have_volid = 0; + int have_volsetid = 0; /* The block size of a UDF filesystem is that of the underlying * storage; we check later on for the special case of image files, @@ -142,13 +212,16 @@ real_blksz: } /* Try extract all possible ISO9660 information -- if there is - * usable LABEL in ISO header then use it, otherwise read UDF - * specific LABEL */ - if (probe_iso9660(pr, mag) == 0 && - __blkid_probe_lookup_value(pr, "LABEL") != NULL) - return 0; + * usable LABEL and UUID in ISO header then use it, otherwise + * read UDF specific LABEL and UUID */ + if (probe_iso9660(pr, mag) == 0) { + if (__blkid_probe_lookup_value(pr, "LABEL") != NULL) + have_label = 1; + if (__blkid_probe_lookup_value(pr, "UUID") != NULL) + have_uuid = 1; + } - /* Read UDF label */ + /* Read UDF identifiers */ for (b = 0; b < count; b++) { vd = (struct volume_descriptor *) blkid_probe_get_buffer(pr, @@ -162,19 +235,109 @@ real_blksz: if (le32_to_cpu(vd->tag.location) != loc + b) break; if (type == 1) { /* TAG_ID_PVD */ - uint8_t clen = vd->type.primary.ident.clen; - - if (clen == 8) - blkid_probe_set_label(pr, - vd->type.primary.ident.c, 31); - else if (clen == 16) - blkid_probe_set_utf8label(pr, - vd->type.primary.ident.c, - 31, BLKID_ENC_UTF16BE); - - if (clen == 8 || clen == 16) - break; + if (!have_volid) { + uint8_t clen = vd->type.primary.ident.clen; + if (clen == 8) + have_volid = !blkid_probe_set_id_label(pr, "VOLUME_ID", + vd->type.primary.ident.c, 31); + else if (clen == 16) + have_volid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_ID", + vd->type.primary.ident.c, 31, + BLKID_ENC_UTF16BE); + } + if (!have_uuid) { + /* VolumeSetIdentifier in UDF 2.01 specification: + * ================================================================================= + * 2.2.2.5 dstring VolumeSetIdentifier + * + * Interpreted as specifying the identifier for the volume set. + * + * The first 16 characters of this field should be set to a unique value. The + * remainder of the field may be set to any allowed value. Specifically, software + * generating volumes conforming to this specification shall not set this field to a + * fixed or trivial value. Duplicate disks which are intended to be identical may + * contain the same value in this field. + * + * NOTE: The intended purpose of this is to guarantee Volume Sets with unique + * identifiers. The first 8 characters of the unique part should come from a CS0 + * hexadecimal representation of a 32-bit time value. The remaining 8 characters + * are free for implementation use. + * ================================================================================= + * + * Implementation in libblkid: + * The first 16 characters of VolumeSetIdentifier are used to generate UUID. + * If all 16 characters are alphanumeric then they are used unchanged as UUID. + * If one of first 8 characters (time value) is not alphanumeric then first + * 8 characters are encoded to their hexadecimal values in 16 characters and + * set as UUID. If all first 8 characters (time value) are alphanumeric but + * some other remaining character is not then first 8 characters are unchanged + * (set as first part of UUID string), next 4 characters are encoded to their + * hexadecimal values (in 8 characters) and set as second part of UUID string. + */ + unsigned char uuid[17]; + if (gen_uuid_from_volset_id(uuid, &vd->type.primary.volset_id) == 0) + have_uuid = !blkid_probe_strncpy_uuid(pr, uuid, sizeof(uuid)); + } + if (!have_volsetid) { + uint8_t clen = vd->type.primary.volset_id.clen; + if (clen == 8) + have_volsetid = !blkid_probe_set_id_label(pr, "VOLUME_SET_ID", + vd->type.primary.volset_id.c, 127); + else if (clen == 16) + have_volsetid = !blkid_probe_set_utf8_id_label(pr, "VOLUME_SET_ID", + vd->type.primary.volset_id.c, 127, + BLKID_ENC_UTF16BE); + } + } else if (type == 6) { /* TAG_ID_LVD */ + if (!have_logvolid || !have_label) { + /* LogicalVolumeIdentifier in UDF 2.01 specification: + * =============================================================== + * 2. Basic Restrictions & Requirements + * + * Logical Volume Descriptor + * + * There shall be exactly one prevailing Logical Volume + * Descriptor recorded per Volume Set. + * + * The LogicalVolumeIdentifier field shall not be null and + * should contain an identifier that aids in the identification of + * the logical volume. Specifically, software generating + * volumes conforming to this specification shall not set this + * field to a fixed or trivial value. Duplicate disks, which are + * intended to be identical, may contain the same value in this + * field. This field is extremely important in logical volume + * identification when multiple media are present within a + * jukebox. This name is typically what is displayed to the user. + * =============================================================== + * + * Implementation in libblkid: + * The LogicalVolumeIdentifier field is used for LABEL. MS Windows + * read Volume Label also from LogicalVolumeIdentifier. Grub2 read + * LABEL also from this field. Program newfs_udf (from UDFclient) + * when formatting disk set this field from user option Disc Name. + */ + uint8_t clen = vd->type.logical.logvol_id.clen; + if (clen == 8) { + if (!have_label) + have_label = !blkid_probe_set_label(pr, + vd->type.logical.logvol_id.c, 127); + if (!have_logvolid) + have_logvolid = !blkid_probe_set_id_label(pr, "LOGICAL_VOLUME_ID", + vd->type.logical.logvol_id.c, 127); + } else if (clen == 16) { + if (!have_label) + have_label = !blkid_probe_set_utf8label(pr, + vd->type.logical.logvol_id.c, + 127, BLKID_ENC_UTF16BE); + if (!have_logvolid) + have_logvolid = !blkid_probe_set_utf8_id_label(pr, "LOGICAL_VOLUME_ID", + vd->type.logical.logvol_id.c, 127, + BLKID_ENC_UTF16BE); + } + } } + if (have_logvolid && have_volid && have_volsetid) + break; } return 0;