#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;
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));
#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__)))
{
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,
}
/* 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,
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;