bbc6a89
From 435fa75e01ef40917239c7f775e505e86f70d202 Mon Sep 17 00:00:00 2001
bbc6a89
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali.rohar@gmail.com>
bbc6a89
Date: Thu, 22 Jun 2017 14:42:16 +0200
78e1a10
Subject: [PATCH 053/216] * grub-core/fs/udf.c: Add support for UUID
bbc6a89
bbc6a89
Use same algorithm as in libblkid from util-linux v2.30.
bbc6a89
bbc6a89
1. Take first 16 bytes from UTF-8 encoded string of VolumeSetIdentifier
bbc6a89
2. If all bytes are hexadecimal digits, convert to lowercase and use as UUID
bbc6a89
3. If first 8 bytes are not all hexadecimal digits, convert those 8 bytes
bbc6a89
   to their hexadecimal representation, resulting in 16 bytes for UUID
bbc6a89
4. Otherwise, compose UUID from two parts:
bbc6a89
   1. part: converted first 8 bytes (which are hexadecimal digits) to lowercase
bbc6a89
   2. part: encoded following 4 bytes to their hexadecimal representation (16 bytes)
bbc6a89
bbc6a89
So UUID would always have 16 hexadecimal digits in lowercase variant.
bbc6a89
bbc6a89
According to UDF specification, first 16 Unicode characters of
bbc6a89
VolumeSetIdentifier should be unique value and first 8 should be
bbc6a89
hexadecimal characters.
bbc6a89
bbc6a89
In most cases all 16 characters are hexadecimal, but e.g. MS Windows
bbc6a89
format.exe set only first 8 as hexadecimal and remaining as fixed
bbc6a89
(non-unique) which violates specification.
bbc6a89
---
bbc6a89
 grub-core/fs/udf.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
bbc6a89
 1 file changed, 120 insertions(+), 1 deletion(-)
bbc6a89
bbc6a89
diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
ec4acbb
index 2587456336e..00a16098b47 100644
bbc6a89
--- a/grub-core/fs/udf.c
bbc6a89
+++ b/grub-core/fs/udf.c
bbc6a89
@@ -321,6 +321,32 @@ struct grub_udf_partmap
bbc6a89
   };
bbc6a89
 } GRUB_PACKED;
bbc6a89
 
bbc6a89
+struct grub_udf_pvd
bbc6a89
+{
bbc6a89
+  struct grub_udf_tag tag;
bbc6a89
+  grub_uint32_t seq_num;
bbc6a89
+  grub_uint32_t pvd_num;
bbc6a89
+  grub_uint8_t ident[32];
bbc6a89
+  grub_uint16_t vol_seq_num;
bbc6a89
+  grub_uint16_t max_vol_seq_num;
bbc6a89
+  grub_uint16_t interchange_level;
bbc6a89
+  grub_uint16_t max_interchange_level;
bbc6a89
+  grub_uint32_t charset_list;
bbc6a89
+  grub_uint32_t max_charset_list;
bbc6a89
+  grub_uint8_t volset_ident[128];
bbc6a89
+  struct grub_udf_charspec desc_charset;
bbc6a89
+  struct grub_udf_charspec expl_charset;
bbc6a89
+  struct grub_udf_extent_ad vol_abstract;
bbc6a89
+  struct grub_udf_extent_ad vol_copyright;
bbc6a89
+  struct grub_udf_regid app_ident;
bbc6a89
+  struct grub_udf_timestamp recording_time;
bbc6a89
+  struct grub_udf_regid imp_ident;
bbc6a89
+  grub_uint8_t imp_use[64];
bbc6a89
+  grub_uint32_t pred_vds_loc;
bbc6a89
+  grub_uint16_t flags;
bbc6a89
+  grub_uint8_t reserved[22];
bbc6a89
+} GRUB_PACKED;
bbc6a89
+
bbc6a89
 struct grub_udf_lvd
bbc6a89
 {
bbc6a89
   struct grub_udf_tag tag;
bbc6a89
@@ -348,6 +374,7 @@ struct grub_udf_aed
bbc6a89
 struct grub_udf_data
bbc6a89
 {
bbc6a89
   grub_disk_t disk;
bbc6a89
+  struct grub_udf_pvd pvd;
bbc6a89
   struct grub_udf_lvd lvd;
bbc6a89
   struct grub_udf_pd pds[GRUB_UDF_MAX_PDS];
bbc6a89
   struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS];
bbc6a89
@@ -692,7 +719,17 @@ grub_udf_mount (grub_disk_t disk)
bbc6a89
 	}
bbc6a89
 
bbc6a89
       tag.tag_ident = U16 (tag.tag_ident);
bbc6a89
-      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
bbc6a89
+      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PVD)
bbc6a89
+	{
bbc6a89
+	  if (grub_disk_read (disk, block << lbshift, 0,
bbc6a89
+			      sizeof (struct grub_udf_pvd),
bbc6a89
+			      &data->pvd))
bbc6a89
+	    {
bbc6a89
+	      grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
bbc6a89
+	      goto fail;
bbc6a89
+	    }
bbc6a89
+	}
bbc6a89
+      else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
bbc6a89
 	{
bbc6a89
 	  if (data->npd >= GRUB_UDF_MAX_PDS)
bbc6a89
 	    {
bbc6a89
@@ -1225,6 +1262,87 @@ grub_udf_label (grub_device_t device, char **label)
bbc6a89
   return grub_errno;
bbc6a89
 }
bbc6a89
 
bbc6a89
+static char *
bbc6a89
+gen_uuid_from_volset (char *volset_ident)
bbc6a89
+{
bbc6a89
+  grub_size_t i;
bbc6a89
+  grub_size_t len;
bbc6a89
+  grub_size_t nonhexpos;
bbc6a89
+  grub_uint8_t buf[17];
bbc6a89
+  char *uuid;
bbc6a89
+
bbc6a89
+  len = grub_strlen (volset_ident);
bbc6a89
+  if (len < 8)
bbc6a89
+    return NULL;
bbc6a89
+
bbc6a89
+  uuid = grub_malloc (17);
bbc6a89
+  if (!uuid)
bbc6a89
+    return NULL;
bbc6a89
+
bbc6a89
+  if (len > 16)
bbc6a89
+    len = 16;
bbc6a89
+
bbc6a89
+  grub_memset (buf, 0, sizeof (buf));
bbc6a89
+  grub_memcpy (buf, volset_ident, len);
bbc6a89
+
bbc6a89
+  nonhexpos = 16;
bbc6a89
+  for (i = 0; i < 16; ++i)
bbc6a89
+    {
bbc6a89
+      if (!grub_isxdigit (buf[i]))
bbc6a89
+        {
bbc6a89
+          nonhexpos = i;
bbc6a89
+          break;
bbc6a89
+        }
bbc6a89
+    }
bbc6a89
+
bbc6a89
+  if (nonhexpos < 8)
bbc6a89
+    {
bbc6a89
+      grub_snprintf (uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
bbc6a89
+                    buf[0], buf[1], buf[2], buf[3],
bbc6a89
+                    buf[4], buf[5], buf[6], buf[7]);
bbc6a89
+    }
bbc6a89
+  else if (nonhexpos < 16)
bbc6a89
+    {
bbc6a89
+      for (i = 0; i < 8; ++i)
bbc6a89
+        uuid[i] = grub_tolower (buf[i]);
bbc6a89
+      grub_snprintf (uuid+8, 9, "%02x%02x%02x%02x",
bbc6a89
+                    buf[8], buf[9], buf[10], buf[11]);
bbc6a89
+    }
bbc6a89
+  else
bbc6a89
+    {
bbc6a89
+      for (i = 0; i < 16; ++i)
bbc6a89
+        uuid[i] = grub_tolower (buf[i]);
bbc6a89
+      uuid[16] = 0;
bbc6a89
+    }
bbc6a89
+
bbc6a89
+  return uuid;
bbc6a89
+}
bbc6a89
+
bbc6a89
+static grub_err_t
bbc6a89
+grub_udf_uuid (grub_device_t device, char **uuid)
bbc6a89
+{
bbc6a89
+  char *volset_ident;
bbc6a89
+  struct grub_udf_data *data;
bbc6a89
+  data = grub_udf_mount (device->disk);
bbc6a89
+
bbc6a89
+  if (data)
bbc6a89
+    {
bbc6a89
+      volset_ident = read_dstring (data->pvd.volset_ident, sizeof (data->pvd.volset_ident));
bbc6a89
+      if (volset_ident)
bbc6a89
+        {
bbc6a89
+          *uuid = gen_uuid_from_volset (volset_ident);
bbc6a89
+          grub_free (volset_ident);
bbc6a89
+        }
bbc6a89
+      else
bbc6a89
+        *uuid = 0;
bbc6a89
+      grub_free (data);
bbc6a89
+    }
bbc6a89
+  else
bbc6a89
+    *uuid = 0;
bbc6a89
+
bbc6a89
+  return grub_errno;
bbc6a89
+}
bbc6a89
+
bbc6a89
 static struct grub_fs grub_udf_fs = {
bbc6a89
   .name = "udf",
bbc6a89
   .dir = grub_udf_dir,
bbc6a89
@@ -1232,6 +1350,7 @@ static struct grub_fs grub_udf_fs = {
bbc6a89
   .read = grub_udf_read,
bbc6a89
   .close = grub_udf_close,
bbc6a89
   .label = grub_udf_label,
bbc6a89
+  .uuid = grub_udf_uuid,
bbc6a89
 #ifdef GRUB_UTIL
bbc6a89
   .reserved_first_sector = 1,
bbc6a89
   .blocklist_install = 1,
bbc6a89
-- 
ec4acbb
2.15.0
bbc6a89