grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] * grub-core/fs/udf.c: Add support for UUID
@ 2017-04-10 18:35 Pali Rohár
  2017-04-19 17:48 ` Pali Rohár
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Pali Rohár @ 2017-04-10 18:35 UTC (permalink / raw)
  To: grub-devel; +Cc: Pali Rohár

Use same algorithm as in libblkid from util-linux.
---
 grub-core/fs/udf.c |  136 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 131 insertions(+), 5 deletions(-)

diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
index 839bff8..a4baa4c 100644
--- a/grub-core/fs/udf.c
+++ b/grub-core/fs/udf.c
@@ -321,6 +321,32 @@ struct grub_udf_partmap
   };
 } GRUB_PACKED;
 
+struct grub_udf_pvd
+{
+  struct grub_udf_tag tag;
+  grub_uint32_t seq_num;
+  grub_uint32_t pvd_num;
+  grub_uint8_t ident[32];
+  grub_uint16_t vol_seq_num;
+  grub_uint16_t max_vol_seq_num;
+  grub_uint16_t interchange_level;
+  grub_uint16_t max_interchange_level;
+  grub_uint32_t charset_list;
+  grub_uint32_t max_charset_list;
+  grub_uint8_t volset_ident[128];
+  struct grub_udf_charspec desc_charset;
+  struct grub_udf_charspec expl_charset;
+  struct grub_udf_extent_ad vol_abstract;
+  struct grub_udf_extent_ad vol_copyright;
+  struct grub_udf_regid app_ident;
+  struct grub_udf_timestamp recording_time;
+  struct grub_udf_regid imp_ident;
+  grub_uint8_t imp_use[64];
+  grub_uint32_t pred_vds_loc;
+  grub_uint16_t flags;
+  grub_uint8_t reserved[22];
+} GRUB_PACKED;
+
 struct grub_udf_lvd
 {
   struct grub_udf_tag tag;
@@ -348,6 +374,7 @@ struct grub_udf_aed
 struct grub_udf_data
 {
   grub_disk_t disk;
+  struct grub_udf_pvd pvd;
   struct grub_udf_lvd lvd;
   struct grub_udf_pd pds[GRUB_UDF_MAX_PDS];
   struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS];
@@ -692,7 +719,17 @@ grub_udf_mount (grub_disk_t disk)
 	}
 
       tag.tag_ident = U16 (tag.tag_ident);
-      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
+      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PVD)
+	{
+	  if (grub_disk_read (disk, block << lbshift, 0,
+			      sizeof (struct grub_udf_pvd),
+			      &data->pvd))
+	    {
+	      grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
+	      goto fail;
+	    }
+	}
+      else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
 	{
 	  if (data->npd >= GRUB_UDF_MAX_PDS)
 	    {
@@ -821,7 +858,7 @@ grub_udf_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn)
 #endif
 
 static char *
-read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
+read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf, int normalize_utf8)
 {
   grub_uint16_t *utf16 = NULL;
   grub_size_t utf16len = 0;
@@ -832,6 +869,15 @@ read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
   if (raw[0] != 8 && raw[0] != 16)
     return NULL;
 
+  if (raw[0] == 8 && !normalize_utf8)
+    {
+      if (!outbuf)
+        outbuf = grub_strndup ((char *)raw + 1, sz - 1);
+      else
+        grub_memcpy (outbuf, raw + 1, sz - 1);
+      return outbuf;
+    }
+
   if (raw[0] == 8)
     {
       unsigned i;
@@ -923,7 +969,7 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
 		  != dirent.file_ident_length)
 		return 0;
 
-	      filename = read_string (raw, dirent.file_ident_length, 0);
+	      filename = read_string (raw, dirent.file_ident_length, 0, 1);
 	      if (!filename)
 		grub_print_error ();
 
@@ -1009,7 +1055,7 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
 	  /* in 4 + n bytes. out, at most: 1 + 2 * n bytes.  */
 	  if (optr != out)
 	    *optr++ = '/';
-	  if (!read_string (ptr + 4, s - 4, optr))
+	  if (!read_string (ptr + 4, s - 4, optr, 1))
 	    goto fail;
 	  optr += grub_strlen (optr);
 	  break;
@@ -1197,7 +1243,7 @@ grub_udf_label (grub_device_t device, char **label)
 
   if (data)
     {
-      *label = read_string (data->lvd.ident, sizeof (data->lvd.ident), 0);
+      *label = read_string (data->lvd.ident, sizeof (data->lvd.ident), 0, 1);
       grub_free (data);
     }
   else
@@ -1206,6 +1252,85 @@ grub_udf_label (grub_device_t device, char **label)
   return grub_errno;
 }
 
+static char *
+gen_uuid_from_volset (char *volset_ident)
+{
+  grub_size_t i;
+  grub_size_t len;
+  grub_size_t binpos;
+  grub_uint8_t buf[17];
+  char *uuid;
+
+  len = grub_strlen (volset_ident);
+  if (len < 8)
+    return NULL;
+
+  uuid = grub_malloc (17);
+  if (!uuid)
+    return NULL;
+
+  if (len > 16)
+    len = 16;
+
+  grub_memset (buf, 0, sizeof (buf));
+  grub_memcpy (buf, volset_ident, len);
+
+  binpos = 16;
+  for (i = 0; i < len; ++i)
+    {
+      if (!grub_isalnum (buf[i]))
+        {
+          binpos = i;
+          break;
+        }
+    }
+
+  if (binpos < 8)
+    {
+      grub_snprintf (uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
+                    buf[0], buf[1], buf[2], buf[3],
+                    buf[4], buf[5], buf[6], buf[7]);
+    }
+  else if (binpos < 16)
+    {
+      grub_memcpy (uuid, buf, 8);
+      grub_snprintf (uuid+8, 9, "%02x%02x%02x%02x",
+                    buf[8], buf[9], buf[10], buf[11]);
+    }
+  else
+    {
+      grub_memcpy (uuid, buf, 16);
+      uuid[16] = 0;
+    }
+
+  return uuid;
+}
+
+static grub_err_t
+grub_udf_uuid (grub_device_t device, char **uuid)
+{
+  char *volset_ident;
+  struct grub_udf_data *data;
+  data = grub_udf_mount (device->disk);
+
+  if (data)
+    {
+      volset_ident = read_string (data->pvd.volset_ident, sizeof (data->pvd.volset_ident), 0, 0);
+      if (volset_ident)
+        {
+          *uuid = gen_uuid_from_volset (volset_ident);
+          grub_free (volset_ident);
+        }
+      else
+        *uuid = 0;
+      grub_free (data);
+    }
+  else
+    *uuid = 0;
+
+  return grub_errno;
+}
+
 static struct grub_fs grub_udf_fs = {
   .name = "udf",
   .dir = grub_udf_dir,
@@ -1213,6 +1338,7 @@ static struct grub_fs grub_udf_fs = {
   .read = grub_udf_read,
   .close = grub_udf_close,
   .label = grub_udf_label,
+  .uuid = grub_udf_uuid,
 #ifdef GRUB_UTIL
   .reserved_first_sector = 1,
   .blocklist_install = 1,
-- 
1.7.9.5



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] * grub-core/fs/udf.c: Add support for UUID
  2017-04-10 18:35 [PATCH] * grub-core/fs/udf.c: Add support for UUID Pali Rohár
@ 2017-04-19 17:48 ` Pali Rohár
  2017-04-19 18:11   ` Andrei Borzenkov
  2017-05-08 12:55   ` Pali Rohár
  2017-05-08 13:13 ` Vladimir 'phcoder' Serbinenko
  2017-06-22 12:42 ` [PATCH v2] " Pali Rohár
  2 siblings, 2 replies; 10+ messages in thread
From: Pali Rohár @ 2017-04-19 17:48 UTC (permalink / raw)
  To: grub-devel

Hi! I would like to remind this patch. It allows to use UUID of UDF
partition in grub2. Linux tool blkid is already able to handle it, so it
is possible to specify UUID of UDF partition in /etc/fstab.

UDF is filesystem used on optical disks (DVD), but also on hard disks as
it is natively supported by Windows, Linux and Mac OS X kernels. Which
is a good benefit for multi-boot environment.

On Monday 10 April 2017 20:35:30 Pali Rohár wrote:
> Use same algorithm as in libblkid from util-linux.
> ---
>  grub-core/fs/udf.c |  136 ++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 131 insertions(+), 5 deletions(-)
> 
> diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
> index 839bff8..a4baa4c 100644
> --- a/grub-core/fs/udf.c
> +++ b/grub-core/fs/udf.c
> @@ -321,6 +321,32 @@ struct grub_udf_partmap
>    };
>  } GRUB_PACKED;
>  
> +struct grub_udf_pvd
> +{
> +  struct grub_udf_tag tag;
> +  grub_uint32_t seq_num;
> +  grub_uint32_t pvd_num;
> +  grub_uint8_t ident[32];
> +  grub_uint16_t vol_seq_num;
> +  grub_uint16_t max_vol_seq_num;
> +  grub_uint16_t interchange_level;
> +  grub_uint16_t max_interchange_level;
> +  grub_uint32_t charset_list;
> +  grub_uint32_t max_charset_list;
> +  grub_uint8_t volset_ident[128];
> +  struct grub_udf_charspec desc_charset;
> +  struct grub_udf_charspec expl_charset;
> +  struct grub_udf_extent_ad vol_abstract;
> +  struct grub_udf_extent_ad vol_copyright;
> +  struct grub_udf_regid app_ident;
> +  struct grub_udf_timestamp recording_time;
> +  struct grub_udf_regid imp_ident;
> +  grub_uint8_t imp_use[64];
> +  grub_uint32_t pred_vds_loc;
> +  grub_uint16_t flags;
> +  grub_uint8_t reserved[22];
> +} GRUB_PACKED;
> +
>  struct grub_udf_lvd
>  {
>    struct grub_udf_tag tag;
> @@ -348,6 +374,7 @@ struct grub_udf_aed
>  struct grub_udf_data
>  {
>    grub_disk_t disk;
> +  struct grub_udf_pvd pvd;
>    struct grub_udf_lvd lvd;
>    struct grub_udf_pd pds[GRUB_UDF_MAX_PDS];
>    struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS];
> @@ -692,7 +719,17 @@ grub_udf_mount (grub_disk_t disk)
>  	}
>  
>        tag.tag_ident = U16 (tag.tag_ident);
> -      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
> +      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PVD)
> +	{
> +	  if (grub_disk_read (disk, block << lbshift, 0,
> +			      sizeof (struct grub_udf_pvd),
> +			      &data->pvd))
> +	    {
> +	      grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
> +	      goto fail;
> +	    }
> +	}
> +      else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
>  	{
>  	  if (data->npd >= GRUB_UDF_MAX_PDS)
>  	    {
> @@ -821,7 +858,7 @@ grub_udf_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn)
>  #endif
>  
>  static char *
> -read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
> +read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf, int normalize_utf8)
>  {
>    grub_uint16_t *utf16 = NULL;
>    grub_size_t utf16len = 0;
> @@ -832,6 +869,15 @@ read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
>    if (raw[0] != 8 && raw[0] != 16)
>      return NULL;
>  
> +  if (raw[0] == 8 && !normalize_utf8)
> +    {
> +      if (!outbuf)
> +        outbuf = grub_strndup ((char *)raw + 1, sz - 1);
> +      else
> +        grub_memcpy (outbuf, raw + 1, sz - 1);
> +      return outbuf;
> +    }
> +
>    if (raw[0] == 8)
>      {
>        unsigned i;
> @@ -923,7 +969,7 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
>  		  != dirent.file_ident_length)
>  		return 0;
>  
> -	      filename = read_string (raw, dirent.file_ident_length, 0);
> +	      filename = read_string (raw, dirent.file_ident_length, 0, 1);
>  	      if (!filename)
>  		grub_print_error ();
>  
> @@ -1009,7 +1055,7 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
>  	  /* in 4 + n bytes. out, at most: 1 + 2 * n bytes.  */
>  	  if (optr != out)
>  	    *optr++ = '/';
> -	  if (!read_string (ptr + 4, s - 4, optr))
> +	  if (!read_string (ptr + 4, s - 4, optr, 1))
>  	    goto fail;
>  	  optr += grub_strlen (optr);
>  	  break;
> @@ -1197,7 +1243,7 @@ grub_udf_label (grub_device_t device, char **label)
>  
>    if (data)
>      {
> -      *label = read_string (data->lvd.ident, sizeof (data->lvd.ident), 0);
> +      *label = read_string (data->lvd.ident, sizeof (data->lvd.ident), 0, 1);
>        grub_free (data);
>      }
>    else
> @@ -1206,6 +1252,85 @@ grub_udf_label (grub_device_t device, char **label)
>    return grub_errno;
>  }
>  
> +static char *
> +gen_uuid_from_volset (char *volset_ident)
> +{
> +  grub_size_t i;
> +  grub_size_t len;
> +  grub_size_t binpos;
> +  grub_uint8_t buf[17];
> +  char *uuid;
> +
> +  len = grub_strlen (volset_ident);
> +  if (len < 8)
> +    return NULL;
> +
> +  uuid = grub_malloc (17);
> +  if (!uuid)
> +    return NULL;
> +
> +  if (len > 16)
> +    len = 16;
> +
> +  grub_memset (buf, 0, sizeof (buf));
> +  grub_memcpy (buf, volset_ident, len);
> +
> +  binpos = 16;
> +  for (i = 0; i < len; ++i)
> +    {
> +      if (!grub_isalnum (buf[i]))
> +        {
> +          binpos = i;
> +          break;
> +        }
> +    }
> +
> +  if (binpos < 8)
> +    {
> +      grub_snprintf (uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
> +                    buf[0], buf[1], buf[2], buf[3],
> +                    buf[4], buf[5], buf[6], buf[7]);
> +    }
> +  else if (binpos < 16)
> +    {
> +      grub_memcpy (uuid, buf, 8);
> +      grub_snprintf (uuid+8, 9, "%02x%02x%02x%02x",
> +                    buf[8], buf[9], buf[10], buf[11]);
> +    }
> +  else
> +    {
> +      grub_memcpy (uuid, buf, 16);
> +      uuid[16] = 0;
> +    }
> +
> +  return uuid;
> +}
> +
> +static grub_err_t
> +grub_udf_uuid (grub_device_t device, char **uuid)
> +{
> +  char *volset_ident;
> +  struct grub_udf_data *data;
> +  data = grub_udf_mount (device->disk);
> +
> +  if (data)
> +    {
> +      volset_ident = read_string (data->pvd.volset_ident, sizeof (data->pvd.volset_ident), 0, 0);
> +      if (volset_ident)
> +        {
> +          *uuid = gen_uuid_from_volset (volset_ident);
> +          grub_free (volset_ident);
> +        }
> +      else
> +        *uuid = 0;
> +      grub_free (data);
> +    }
> +  else
> +    *uuid = 0;
> +
> +  return grub_errno;
> +}
> +
>  static struct grub_fs grub_udf_fs = {
>    .name = "udf",
>    .dir = grub_udf_dir,
> @@ -1213,6 +1338,7 @@ static struct grub_fs grub_udf_fs = {
>    .read = grub_udf_read,
>    .close = grub_udf_close,
>    .label = grub_udf_label,
> +  .uuid = grub_udf_uuid,
>  #ifdef GRUB_UTIL
>    .reserved_first_sector = 1,
>    .blocklist_install = 1,

-- 
Pali Rohár
pali.rohar@gmail.com


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] * grub-core/fs/udf.c: Add support for UUID
  2017-04-19 17:48 ` Pali Rohár
@ 2017-04-19 18:11   ` Andrei Borzenkov
  2017-05-08 12:55   ` Pali Rohár
  1 sibling, 0 replies; 10+ messages in thread
From: Andrei Borzenkov @ 2017-04-19 18:11 UTC (permalink / raw)
  To: The development of GNU GRUB

19.04.2017 20:48, Pali Rohár пишет:
> Hi! I would like to remind this patch. It allows to use UUID of UDF
> partition in grub2. Linux tool blkid is already able to handle it, so it
> is possible to specify UUID of UDF partition in /etc/fstab.
> 
> UDF is filesystem used on optical disks (DVD), but also on hard disks as
> it is natively supported by Windows, Linux and Mac OS X kernels. Which
> is a good benefit for multi-boot environment.
> 
Yes, I wanted to review it, but did not have time. In any case we are in
complete freeze for next release, so it will have to wait until then.
Thank you for the patience.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] * grub-core/fs/udf.c: Add support for UUID
  2017-04-19 17:48 ` Pali Rohár
  2017-04-19 18:11   ` Andrei Borzenkov
@ 2017-05-08 12:55   ` Pali Rohár
  1 sibling, 0 replies; 10+ messages in thread
From: Pali Rohár @ 2017-05-08 12:55 UTC (permalink / raw)
  To: grub-devel

Gentle PING for this patch!

On Wednesday 19 April 2017 19:48:39 Pali Rohár wrote:
> Hi! I would like to remind this patch. It allows to use UUID of UDF
> partition in grub2. Linux tool blkid is already able to handle it, so it
> is possible to specify UUID of UDF partition in /etc/fstab.
> 
> UDF is filesystem used on optical disks (DVD), but also on hard disks as
> it is natively supported by Windows, Linux and Mac OS X kernels. Which
> is a good benefit for multi-boot environment.
> 
> On Monday 10 April 2017 20:35:30 Pali Rohár wrote:
> > Use same algorithm as in libblkid from util-linux.
> > ---
> >  grub-core/fs/udf.c |  136 ++++++++++++++++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 131 insertions(+), 5 deletions(-)
> > 
> > diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
> > index 839bff8..a4baa4c 100644
> > --- a/grub-core/fs/udf.c
> > +++ b/grub-core/fs/udf.c
> > @@ -321,6 +321,32 @@ struct grub_udf_partmap
> >    };
> >  } GRUB_PACKED;
> >  
> > +struct grub_udf_pvd
> > +{
> > +  struct grub_udf_tag tag;
> > +  grub_uint32_t seq_num;
> > +  grub_uint32_t pvd_num;
> > +  grub_uint8_t ident[32];
> > +  grub_uint16_t vol_seq_num;
> > +  grub_uint16_t max_vol_seq_num;
> > +  grub_uint16_t interchange_level;
> > +  grub_uint16_t max_interchange_level;
> > +  grub_uint32_t charset_list;
> > +  grub_uint32_t max_charset_list;
> > +  grub_uint8_t volset_ident[128];
> > +  struct grub_udf_charspec desc_charset;
> > +  struct grub_udf_charspec expl_charset;
> > +  struct grub_udf_extent_ad vol_abstract;
> > +  struct grub_udf_extent_ad vol_copyright;
> > +  struct grub_udf_regid app_ident;
> > +  struct grub_udf_timestamp recording_time;
> > +  struct grub_udf_regid imp_ident;
> > +  grub_uint8_t imp_use[64];
> > +  grub_uint32_t pred_vds_loc;
> > +  grub_uint16_t flags;
> > +  grub_uint8_t reserved[22];
> > +} GRUB_PACKED;
> > +
> >  struct grub_udf_lvd
> >  {
> >    struct grub_udf_tag tag;
> > @@ -348,6 +374,7 @@ struct grub_udf_aed
> >  struct grub_udf_data
> >  {
> >    grub_disk_t disk;
> > +  struct grub_udf_pvd pvd;
> >    struct grub_udf_lvd lvd;
> >    struct grub_udf_pd pds[GRUB_UDF_MAX_PDS];
> >    struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS];
> > @@ -692,7 +719,17 @@ grub_udf_mount (grub_disk_t disk)
> >  	}
> >  
> >        tag.tag_ident = U16 (tag.tag_ident);
> > -      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
> > +      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PVD)
> > +	{
> > +	  if (grub_disk_read (disk, block << lbshift, 0,
> > +			      sizeof (struct grub_udf_pvd),
> > +			      &data->pvd))
> > +	    {
> > +	      grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
> > +	      goto fail;
> > +	    }
> > +	}
> > +      else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
> >  	{
> >  	  if (data->npd >= GRUB_UDF_MAX_PDS)
> >  	    {
> > @@ -821,7 +858,7 @@ grub_udf_get_cluster_sector (grub_disk_t disk, grub_uint64_t *sec_per_lcn)
> >  #endif
> >  
> >  static char *
> > -read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
> > +read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf, int normalize_utf8)
> >  {
> >    grub_uint16_t *utf16 = NULL;
> >    grub_size_t utf16len = 0;
> > @@ -832,6 +869,15 @@ read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
> >    if (raw[0] != 8 && raw[0] != 16)
> >      return NULL;
> >  
> > +  if (raw[0] == 8 && !normalize_utf8)
> > +    {
> > +      if (!outbuf)
> > +        outbuf = grub_strndup ((char *)raw + 1, sz - 1);
> > +      else
> > +        grub_memcpy (outbuf, raw + 1, sz - 1);
> > +      return outbuf;
> > +    }
> > +
> >    if (raw[0] == 8)
> >      {
> >        unsigned i;
> > @@ -923,7 +969,7 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
> >  		  != dirent.file_ident_length)
> >  		return 0;
> >  
> > -	      filename = read_string (raw, dirent.file_ident_length, 0);
> > +	      filename = read_string (raw, dirent.file_ident_length, 0, 1);
> >  	      if (!filename)
> >  		grub_print_error ();
> >  
> > @@ -1009,7 +1055,7 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
> >  	  /* in 4 + n bytes. out, at most: 1 + 2 * n bytes.  */
> >  	  if (optr != out)
> >  	    *optr++ = '/';
> > -	  if (!read_string (ptr + 4, s - 4, optr))
> > +	  if (!read_string (ptr + 4, s - 4, optr, 1))
> >  	    goto fail;
> >  	  optr += grub_strlen (optr);
> >  	  break;
> > @@ -1197,7 +1243,7 @@ grub_udf_label (grub_device_t device, char **label)
> >  
> >    if (data)
> >      {
> > -      *label = read_string (data->lvd.ident, sizeof (data->lvd.ident), 0);
> > +      *label = read_string (data->lvd.ident, sizeof (data->lvd.ident), 0, 1);
> >        grub_free (data);
> >      }
> >    else
> > @@ -1206,6 +1252,85 @@ grub_udf_label (grub_device_t device, char **label)
> >    return grub_errno;
> >  }
> >  
> > +static char *
> > +gen_uuid_from_volset (char *volset_ident)
> > +{
> > +  grub_size_t i;
> > +  grub_size_t len;
> > +  grub_size_t binpos;
> > +  grub_uint8_t buf[17];
> > +  char *uuid;
> > +
> > +  len = grub_strlen (volset_ident);
> > +  if (len < 8)
> > +    return NULL;
> > +
> > +  uuid = grub_malloc (17);
> > +  if (!uuid)
> > +    return NULL;
> > +
> > +  if (len > 16)
> > +    len = 16;
> > +
> > +  grub_memset (buf, 0, sizeof (buf));
> > +  grub_memcpy (buf, volset_ident, len);
> > +
> > +  binpos = 16;
> > +  for (i = 0; i < len; ++i)
> > +    {
> > +      if (!grub_isalnum (buf[i]))
> > +        {
> > +          binpos = i;
> > +          break;
> > +        }
> > +    }
> > +
> > +  if (binpos < 8)
> > +    {
> > +      grub_snprintf (uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
> > +                    buf[0], buf[1], buf[2], buf[3],
> > +                    buf[4], buf[5], buf[6], buf[7]);
> > +    }
> > +  else if (binpos < 16)
> > +    {
> > +      grub_memcpy (uuid, buf, 8);
> > +      grub_snprintf (uuid+8, 9, "%02x%02x%02x%02x",
> > +                    buf[8], buf[9], buf[10], buf[11]);
> > +    }
> > +  else
> > +    {
> > +      grub_memcpy (uuid, buf, 16);
> > +      uuid[16] = 0;
> > +    }
> > +
> > +  return uuid;
> > +}
> > +
> > +static grub_err_t
> > +grub_udf_uuid (grub_device_t device, char **uuid)
> > +{
> > +  char *volset_ident;
> > +  struct grub_udf_data *data;
> > +  data = grub_udf_mount (device->disk);
> > +
> > +  if (data)
> > +    {
> > +      volset_ident = read_string (data->pvd.volset_ident, sizeof (data->pvd.volset_ident), 0, 0);
> > +      if (volset_ident)
> > +        {
> > +          *uuid = gen_uuid_from_volset (volset_ident);
> > +          grub_free (volset_ident);
> > +        }
> > +      else
> > +        *uuid = 0;
> > +      grub_free (data);
> > +    }
> > +  else
> > +    *uuid = 0;
> > +
> > +  return grub_errno;
> > +}
> > +
> >  static struct grub_fs grub_udf_fs = {
> >    .name = "udf",
> >    .dir = grub_udf_dir,
> > @@ -1213,6 +1338,7 @@ static struct grub_fs grub_udf_fs = {
> >    .read = grub_udf_read,
> >    .close = grub_udf_close,
> >    .label = grub_udf_label,
> > +  .uuid = grub_udf_uuid,
> >  #ifdef GRUB_UTIL
> >    .reserved_first_sector = 1,
> >    .blocklist_install = 1,
> 

-- 
Pali Rohár
pali.rohar@gmail.com


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] * grub-core/fs/udf.c: Add support for UUID
  2017-04-10 18:35 [PATCH] * grub-core/fs/udf.c: Add support for UUID Pali Rohár
  2017-04-19 17:48 ` Pali Rohár
@ 2017-05-08 13:13 ` Vladimir 'phcoder' Serbinenko
  2017-05-08 14:24   ` Pali Rohár
  2017-05-12 14:39   ` Pali Rohár
  2017-06-22 12:42 ` [PATCH v2] " Pali Rohár
  2 siblings, 2 replies; 10+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2017-05-08 13:13 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Pali Rohár

[-- Attachment #1: Type: text/plain, Size: 7342 bytes --]

On Mon, Apr 10, 2017, 23:17 Pali Rohár <pali.rohar@gmail.com> wrote:

> Use same algorithm as in libblkid from util-linux.
> ---
>  grub-core/fs/udf.c |  136
> ++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 131 insertions(+), 5 deletions(-)
>
> diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
> index 839bff8..a4baa4c 100644
> --- a/grub-core/fs/udf.c
> +++ b/grub-core/fs/udf.c
> @@ -321,6 +321,32 @@ struct grub_udf_partmap
>    };
>  } GRUB_PACKED;
>
> +struct grub_udf_pvd
> +{
> +  struct grub_udf_tag tag;
> +  grub_uint32_t seq_num;
> +  grub_uint32_t pvd_num;
> +  grub_uint8_t ident[32];
> +  grub_uint16_t vol_seq_num;
> +  grub_uint16_t max_vol_seq_num;
> +  grub_uint16_t interchange_level;
> +  grub_uint16_t max_interchange_level;
> +  grub_uint32_t charset_list;
> +  grub_uint32_t max_charset_list;
> +  grub_uint8_t volset_ident[128];
> +  struct grub_udf_charspec desc_charset;
> +  struct grub_udf_charspec expl_charset;
> +  struct grub_udf_extent_ad vol_abstract;
> +  struct grub_udf_extent_ad vol_copyright;
> +  struct grub_udf_regid app_ident;
> +  struct grub_udf_timestamp recording_time;
> +  struct grub_udf_regid imp_ident;
> +  grub_uint8_t imp_use[64];
> +  grub_uint32_t pred_vds_loc;
> +  grub_uint16_t flags;
> +  grub_uint8_t reserved[22];
> +} GRUB_PACKED;
> +
>  struct grub_udf_lvd
>  {
>    struct grub_udf_tag tag;
> @@ -348,6 +374,7 @@ struct grub_udf_aed
>  struct grub_udf_data
>  {
>    grub_disk_t disk;
> +  struct grub_udf_pvd pvd;
>    struct grub_udf_lvd lvd;
>    struct grub_udf_pd pds[GRUB_UDF_MAX_PDS];
>    struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS];
> @@ -692,7 +719,17 @@ grub_udf_mount (grub_disk_t disk)
>         }
>
>        tag.tag_ident = U16 (tag.tag_ident);
> -      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
> +      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PVD)
> +       {
> +         if (grub_disk_read (disk, block << lbshift, 0,
> +                             sizeof (struct grub_udf_pvd),
> +                             &data->pvd))
> +           {
> +             grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
> +             goto fail;
> +           }
> +       }
> +      else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
>         {
>           if (data->npd >= GRUB_UDF_MAX_PDS)
>             {
> @@ -821,7 +858,7 @@ grub_udf_get_cluster_sector (grub_disk_t disk,
> grub_uint64_t *sec_per_lcn)
>  #endif
>
>  static char *
> -read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf)
> +read_string (const grub_uint8_t *raw, grub_size_t sz, char *outbuf, int
> normalize_utf8)
>
Normalize isn't the right word. And it's not utf-8 but latin1 (called
compressed utf-16 by udf docs).
Are you sure you handle utf-16 case correctly? What is the expected
behavior in those cases? Ideally you may want to just parse raw string in
caller

>  {
>    grub_uint16_t *utf16 = NULL;
>    grub_size_t utf16len = 0;
> @@ -832,6 +869,15 @@ read_string (const grub_uint8_t *raw, grub_size_t sz,
> char *outbuf)
>    if (raw[0] != 8 && raw[0] != 16)
>      return NULL;
>
> +  if (raw[0] == 8 && !normalize_utf8)
> +    {
> +      if (!outbuf)
> +        outbuf = grub_strndup ((char *)raw + 1, sz - 1);
> +      else
> +        grub_memcpy (outbuf, raw + 1, sz - 1);
> +      return outbuf;
> +    }
> +
>    if (raw[0] == 8)
>      {
>        unsigned i;
> @@ -923,7 +969,7 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
>                   != dirent.file_ident_length)
>                 return 0;
>
> -             filename = read_string (raw, dirent.file_ident_length, 0);
> +             filename = read_string (raw, dirent.file_ident_length, 0, 1);
>               if (!filename)
>                 grub_print_error ();
>
> @@ -1009,7 +1055,7 @@ grub_udf_read_symlink (grub_fshelp_node_t node)
>           /* in 4 + n bytes. out, at most: 1 + 2 * n bytes.  */
>           if (optr != out)
>             *optr++ = '/';
> -         if (!read_string (ptr + 4, s - 4, optr))
> +         if (!read_string (ptr + 4, s - 4, optr, 1))
>             goto fail;
>           optr += grub_strlen (optr);
>           break;
> @@ -1197,7 +1243,7 @@ grub_udf_label (grub_device_t device, char **label)
>
>    if (data)
>      {
> -      *label = read_string (data->lvd.ident, sizeof (data->lvd.ident), 0);
> +      *label = read_string (data->lvd.ident, sizeof (data->lvd.ident), 0,
> 1);
>        grub_free (data);
>      }
>    else
> @@ -1206,6 +1252,85 @@ grub_udf_label (grub_device_t device, char **label)
>    return grub_errno;
>  }
>
> +static char *
> +gen_uuid_from_volset (char *volset_ident)
> +{
> +  grub_size_t i;
> +  grub_size_t len;
> +  grub_size_t binpos;
> +  grub_uint8_t buf[17];
> +  char *uuid;
> +
> +  len = grub_strlen (volset_ident);
> +  if (len < 8)
> +    return NULL;
> +
> +  uuid = grub_malloc (17);
> +  if (!uuid)
> +    return NULL;
> +
> +  if (len > 16)
> +    len = 16;
> +
> +  grub_memset (buf, 0, sizeof (buf));
> +  grub_memcpy (buf, volset_ident, len);
> +
> +  binpos = 16;
> +  for (i = 0; i < len; ++i)
> +    {
> +      if (!grub_isalnum (buf[i]))
>
That looks real weird. What if first byte of UUID is 'a'? What if alnum
part contains non-English chars.
I have to admit I don't get what expected behaviour is. Can you elaborate
on this and enable UUID test in udf_test to check that UUID matches blkid?

> +        {
> +          binpos = i;
> +          break;
> +        }
> +    }
> +
> +  if (binpos < 8)
> +    {
> +      grub_snprintf (uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
> +                    buf[0], buf[1], buf[2], buf[3],
> +                    buf[4], buf[5], buf[6], buf[7]);
> +    }
> +  else if (binpos < 16)
> +    {
> +      grub_memcpy (uuid, buf, 8);
> +      grub_snprintf (uuid+8, 9, "%02x%02x%02x%02x",
> +                    buf[8], buf[9], buf[10], buf[11]);
> +    }
> +  else
> +    {
> +      grub_memcpy (uuid, buf, 16);
> +      uuid[16] = 0;
> +    }
> +
> +  return uuid;
> +}
> +
> +static grub_err_t
> +grub_udf_uuid (grub_device_t device, char **uuid)
> +{
> +  char *volset_ident;
> +  struct grub_udf_data *data;
> +  data = grub_udf_mount (device->disk);
> +
> +  if (data)
> +    {
> +      volset_ident = read_string (data->pvd.volset_ident, sizeof
> (data->pvd.volset_ident), 0, 0);
> +      if (volset_ident)
> +        {
> +          *uuid = gen_uuid_from_volset (volset_ident);
> +          grub_free (volset_ident);
> +        }
> +      else
> +        *uuid = 0;
> +      grub_free (data);
> +    }
> +  else
> +    *uuid = 0;
> +
> +  return grub_errno;
> +}
> +
>  static struct grub_fs grub_udf_fs = {
>    .name = "udf",
>    .dir = grub_udf_dir,
> @@ -1213,6 +1338,7 @@ static struct grub_fs grub_udf_fs = {
>    .read = grub_udf_read,
>    .close = grub_udf_close,
>    .label = grub_udf_label,
> +  .uuid = grub_udf_uuid,
>  #ifdef GRUB_UTIL
>    .reserved_first_sector = 1,
>    .blocklist_install = 1,
> --
> 1.7.9.5
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>

[-- Attachment #2: Type: text/html, Size: 9076 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] * grub-core/fs/udf.c: Add support for UUID
  2017-05-08 13:13 ` Vladimir 'phcoder' Serbinenko
@ 2017-05-08 14:24   ` Pali Rohár
  2017-05-11 10:59     ` Pali Rohár
  2017-05-12 14:39   ` Pali Rohár
  1 sibling, 1 reply; 10+ messages in thread
From: Pali Rohár @ 2017-05-08 14:24 UTC (permalink / raw)
  To: Vladimir 'phcoder' Serbinenko; +Cc: The development of GNU GRUB

[-- Attachment #1: Type: Text/Plain, Size: 2348 bytes --]

On Monday 08 May 2017 15:13:28 Vladimir 'phcoder' Serbinenko wrote:
> On Mon, Apr 10, 2017, 23:17 Pali Rohár <pali.rohar@gmail.com> wrote:
> > char *outbuf, int normalize_utf8)
> 
> Normalize isn't the right word. And it's not utf-8 but latin1 (called
> compressed utf-16 by udf docs).

Without this patch part read_string() expects that input string is 
either utf-8 or utf-16 in that compressed osta form. If input string is 
marked with leading 0x8 but contains invalid UTF-8 sequence (like chars 
80-FF) then it is treated as Latin1 and converted to UTF-8 in output. So 
input "\x80" is returned as "\xC2\x80".

What I need is to do not do this Latin1 --> UTF-8 conversion if input is 
marked with leading 0x8 and stay it in binary/raw/octets form. This is 
due to older versions of mkudffs which put into volset string not 
conforming to osta spec. libblkid do not do that "\x80" --> "\xC2\x80" 
conversion too so it is better to have same algorithm for providing UUID 
on running system (blkid on Linux) and in bootloader (Grub2).

> Are you sure you handle utf-16 case correctly? What is the expected
> behavior in those cases? Ideally you may want to just parse raw
> string in caller

If volsetid is stored according to osta spec, then it is handed 
correctly (both UTF-8 and UTF-16).

> > +  binpos = 16;
> > +  for (i = 0; i < len; ++i)
> > +    {
> > +      if (!grub_isalnum (buf[i]))
> 
> That looks real weird. What if first byte of UUID is 'a'? What if
> alnum part contains non-English chars.
> I have to admit I don't get what expected behaviour is. Can you
> elaborate on this and enable UUID test in udf_test to check that
> UUID matches blkid?

According to osta spec, first 16 characters of volsetid are unique and 
remaining anything. First 8 characters are hexadecimal representation of 
32bit timestamp and remaining 8 implementation free (but still are 
unique). Therefore those first 16 characters we use for generating UUID.
Again some generators of UDF disks do not put there hexadecimal number, 
but some garbage (sometimes not valid UTF-8...) so this code generates 
alphanumeric UUID from input with fact that in most cases is input 
hexadecimal (so used as is).

If you have other idea how to deal with this, let me know...

-- 
Pali Rohár
pali.rohar@gmail.com

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] * grub-core/fs/udf.c: Add support for UUID
  2017-05-08 14:24   ` Pali Rohár
@ 2017-05-11 10:59     ` Pali Rohár
  0 siblings, 0 replies; 10+ messages in thread
From: Pali Rohár @ 2017-05-11 10:59 UTC (permalink / raw)
  To: Vladimir 'phcoder' Serbinenko; +Cc: The development of GNU GRUB

On Monday 08 May 2017 16:24:24 Pali Rohár wrote:
> On Monday 08 May 2017 15:13:28 Vladimir 'phcoder' Serbinenko wrote:
> > On Mon, Apr 10, 2017, 23:17 Pali Rohár <pali.rohar@gmail.com> wrote:
> > > char *outbuf, int normalize_utf8)
> > 
> > Normalize isn't the right word. And it's not utf-8 but latin1 (called
> > compressed utf-16 by udf docs).
> 
> Without this patch part read_string() expects that input string is 
> either utf-8 or utf-16 in that compressed osta form. If input string is 
> marked with leading 0x8 but contains invalid UTF-8 sequence (like chars 
> 80-FF) then it is treated as Latin1 and converted to UTF-8 in output. So 
> input "\x80" is returned as "\xC2\x80".
> 
> What I need is to do not do this Latin1 --> UTF-8 conversion if input is 
> marked with leading 0x8 and stay it in binary/raw/octets form. This is 
> due to older versions of mkudffs which put into volset string not 
> conforming to osta spec. libblkid do not do that "\x80" --> "\xC2\x80" 
> conversion too so it is better to have same algorithm for providing UUID 
> on running system (blkid on Linux) and in bootloader (Grub2).
> 
> > Are you sure you handle utf-16 case correctly? What is the expected
> > behavior in those cases? Ideally you may want to just parse raw
> > string in caller
> 
> If volsetid is stored according to osta spec, then it is handed 
> correctly (both UTF-8 and UTF-16).
> 
> > > +  binpos = 16;
> > > +  for (i = 0; i < len; ++i)
> > > +    {
> > > +      if (!grub_isalnum (buf[i]))
> > 
> > That looks real weird. What if first byte of UUID is 'a'? What if
> > alnum part contains non-English chars.

Hm... check rather should be that buf[i] contains hexadecimal digit, not
arbitrary letter. But in most cases it is hexadecimal digit...

> > I have to admit I don't get what expected behaviour is. Can you
> > elaborate on this and enable UUID test in udf_test to check that
> > UUID matches blkid?
> 
> According to osta spec, first 16 characters of volsetid are unique and 
> remaining anything. First 8 characters are hexadecimal representation of 
> 32bit timestamp and remaining 8 implementation free (but still are 
> unique). Therefore those first 16 characters we use for generating UUID.
> Again some generators of UDF disks do not put there hexadecimal number, 
> but some garbage (sometimes not valid UTF-8...) so this code generates 
> alphanumeric UUID from input with fact that in most cases is input 
> hexadecimal (so used as is).
> 
> If you have other idea how to deal with this, let me know...
> 

-- 
Pali Rohár
pali.rohar@gmail.com


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] * grub-core/fs/udf.c: Add support for UUID
  2017-05-08 13:13 ` Vladimir 'phcoder' Serbinenko
  2017-05-08 14:24   ` Pali Rohár
@ 2017-05-12 14:39   ` Pali Rohár
  1 sibling, 0 replies; 10+ messages in thread
From: Pali Rohár @ 2017-05-12 14:39 UTC (permalink / raw)
  To: Vladimir 'phcoder' Serbinenko; +Cc: The development of GNU GRUB

[-- Attachment #1: Type: Text/Plain, Size: 2436 bytes --]

On Monday 08 May 2017 15:13:28 Vladimir 'phcoder' Serbinenko wrote:
> On Mon, Apr 10, 2017, 23:17 Pali Rohár <pali.rohar@gmail.com> wrote:
> > -read_string (const grub_uint8_t *raw, grub_size_t sz, char
> > *outbuf) +read_string (const grub_uint8_t *raw, grub_size_t sz,
> > char *outbuf, int normalize_utf8)
> 
> Normalize isn't the right word. And it's not utf-8 but latin1 (called
> compressed utf-16 by udf docs).
> Are you sure you handle utf-16 case correctly? What is the expected
> behavior in those cases? Ideally you may want to just parse raw
> string in caller

Hi! Now I looked at OSTA UDF spec again and found reason for my 
disinformation... libblkid has wrongly implemented 8bit OSTA compressed 
unicode and I just tried to mimic libblkid in grub...

libblkid handles 16bit OSTA compressed unicode as UTF-16BE and 8bit OSTA 
compressed unicode as UTF-8.

In UDF 2.01 specification is written:
====
For a CompressionID of 8 or 16, the value of the CompressionID shall 
specify the number of BitsPerCharacter for the d-characters defined in 
the CharacterBitStream field. Each sequence of CompressionID bits in the 
CharacterBitStream field shall represent an OSTA Compressed Unicode d-
character. The bits of the character being encoded shall be added to the 
CharacterBitStream from most- to least-significant-bit. The bits shall 
be added to the CharacterBitStream starting from the most significant 
bit of the current byte being encoded into. The value of the OSTA 
Compressed Unicode d-character interpreted as a Uint16 defines the value 
of the corresponding d-character in the Unicode 2.0 standard.
====

So it means that 8bit OSTA compressed unicode buffer contains sequence 
of Unicode codepoints, one per 8 bits. What effectively means 
equivalence with Latin1 (ISO-8859-1) encoding.

And 16bit OSTA compressed unicode means sequence of Unicode codepoints, 
one per 16 bits in big endian. What is probably only UCS-2 and not full 
UTF-16.

So problem is with 8bit OSTA compressed unicode if contains bytes which 
are not UTF-8 invariants (ASCII). As those those are decoded differently 
with Latin1 and UTF-8.

(Please correct me if I'm wrong here)

For now rather scratch/suspend this my patch until we decide what to do 
with it due to different/wrong implementation of reading strings in 
libblkid from util-linux.

-- 
Pali Rohár
pali.rohar@gmail.com

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2] * grub-core/fs/udf.c: Add support for UUID
  2017-04-10 18:35 [PATCH] * grub-core/fs/udf.c: Add support for UUID Pali Rohár
  2017-04-19 17:48 ` Pali Rohár
  2017-05-08 13:13 ` Vladimir 'phcoder' Serbinenko
@ 2017-06-22 12:42 ` Pali Rohár
  2017-08-07 15:50   ` Vladimir 'phcoder' Serbinenko
  2 siblings, 1 reply; 10+ messages in thread
From: Pali Rohár @ 2017-06-22 12:42 UTC (permalink / raw)
  To: grub-devel; +Cc: Vladimir 'phcoder' Serbinenko, Pali Rohár

Use same algorithm as in libblkid from util-linux v2.30.

1. Take first 16 bytes from UTF-8 encoded string of VolumeSetIdentifier
2. If all bytes are hexadecimal digits, convert to lowercase and use as UUID
3. If first 8 bytes are not all hexadecimal digits, convert those 8 bytes
   to their hexadecimal representation, resulting in 16 bytes for UUID
4. Otherwise, compose UUID from two parts:
   1. part: converted first 8 bytes (which are hexadecimal digits) to lowercase
   2. part: encoded following 4 bytes to their hexadecimal representation (16 bytes)

So UUID would always have 16 hexadecimal digits in lowercase variant.

According to UDF specification, first 16 Unicode characters of
VolumeSetIdentifier should be unique value and first 8 should be
hexadecimal characters.

In most cases all 16 characters are hexadecimal, but e.g. MS Windows
format.exe set only first 8 as hexadecimal and remaining as fixed
(non-unique) which violates specification.
---
Changes since v1:
* Fixed handling strings in 8 bit OSTA compressed Unicode format
* Use xdigit instead of alnum
* Compatibility with blkid from util-linux v2.30
---
 grub-core/fs/udf.c |  121 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 120 insertions(+), 1 deletion(-)

diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c
index e7a4d4e..ce12a49 100644
--- a/grub-core/fs/udf.c
+++ b/grub-core/fs/udf.c
@@ -321,6 +321,32 @@ struct grub_udf_partmap
   };
 } GRUB_PACKED;
 
+struct grub_udf_pvd
+{
+  struct grub_udf_tag tag;
+  grub_uint32_t seq_num;
+  grub_uint32_t pvd_num;
+  grub_uint8_t ident[32];
+  grub_uint16_t vol_seq_num;
+  grub_uint16_t max_vol_seq_num;
+  grub_uint16_t interchange_level;
+  grub_uint16_t max_interchange_level;
+  grub_uint32_t charset_list;
+  grub_uint32_t max_charset_list;
+  grub_uint8_t volset_ident[128];
+  struct grub_udf_charspec desc_charset;
+  struct grub_udf_charspec expl_charset;
+  struct grub_udf_extent_ad vol_abstract;
+  struct grub_udf_extent_ad vol_copyright;
+  struct grub_udf_regid app_ident;
+  struct grub_udf_timestamp recording_time;
+  struct grub_udf_regid imp_ident;
+  grub_uint8_t imp_use[64];
+  grub_uint32_t pred_vds_loc;
+  grub_uint16_t flags;
+  grub_uint8_t reserved[22];
+} GRUB_PACKED;
+
 struct grub_udf_lvd
 {
   struct grub_udf_tag tag;
@@ -348,6 +374,7 @@ struct grub_udf_aed
 struct grub_udf_data
 {
   grub_disk_t disk;
+  struct grub_udf_pvd pvd;
   struct grub_udf_lvd lvd;
   struct grub_udf_pd pds[GRUB_UDF_MAX_PDS];
   struct grub_udf_partmap *pms[GRUB_UDF_MAX_PMS];
@@ -692,7 +719,17 @@ grub_udf_mount (grub_disk_t disk)
 	}
 
       tag.tag_ident = U16 (tag.tag_ident);
-      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
+      if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PVD)
+	{
+	  if (grub_disk_read (disk, block << lbshift, 0,
+			      sizeof (struct grub_udf_pvd),
+			      &data->pvd))
+	    {
+	      grub_error (GRUB_ERR_BAD_FS, "not an UDF filesystem");
+	      goto fail;
+	    }
+	}
+      else if (tag.tag_ident == GRUB_UDF_TAG_IDENT_PD)
 	{
 	  if (data->npd >= GRUB_UDF_MAX_PDS)
 	    {
@@ -1225,6 +1262,87 @@ grub_udf_label (grub_device_t device, char **label)
   return grub_errno;
 }
 
+static char *
+gen_uuid_from_volset (char *volset_ident)
+{
+  grub_size_t i;
+  grub_size_t len;
+  grub_size_t nonhexpos;
+  grub_uint8_t buf[17];
+  char *uuid;
+
+  len = grub_strlen (volset_ident);
+  if (len < 8)
+    return NULL;
+
+  uuid = grub_malloc (17);
+  if (!uuid)
+    return NULL;
+
+  if (len > 16)
+    len = 16;
+
+  grub_memset (buf, 0, sizeof (buf));
+  grub_memcpy (buf, volset_ident, len);
+
+  nonhexpos = 16;
+  for (i = 0; i < 16; ++i)
+    {
+      if (!grub_isxdigit (buf[i]))
+        {
+          nonhexpos = i;
+          break;
+        }
+    }
+
+  if (nonhexpos < 8)
+    {
+      grub_snprintf (uuid, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
+                    buf[0], buf[1], buf[2], buf[3],
+                    buf[4], buf[5], buf[6], buf[7]);
+    }
+  else if (nonhexpos < 16)
+    {
+      for (i = 0; i < 8; ++i)
+        uuid[i] = grub_tolower (buf[i]);
+      grub_snprintf (uuid+8, 9, "%02x%02x%02x%02x",
+                    buf[8], buf[9], buf[10], buf[11]);
+    }
+  else
+    {
+      for (i = 0; i < 16; ++i)
+        uuid[i] = grub_tolower (buf[i]);
+      uuid[16] = 0;
+    }
+
+  return uuid;
+}
+
+static grub_err_t
+grub_udf_uuid (grub_device_t device, char **uuid)
+{
+  char *volset_ident;
+  struct grub_udf_data *data;
+  data = grub_udf_mount (device->disk);
+
+  if (data)
+    {
+      volset_ident = read_dstring (data->pvd.volset_ident, sizeof (data->pvd.volset_ident), 0);
+      if (volset_ident)
+        {
+          *uuid = gen_uuid_from_volset (volset_ident);
+          grub_free (volset_ident);
+        }
+      else
+        *uuid = 0;
+      grub_free (data);
+    }
+  else
+    *uuid = 0;
+
+  return grub_errno;
+}
+
 static struct grub_fs grub_udf_fs = {
   .name = "udf",
   .dir = grub_udf_dir,
@@ -1232,6 +1350,7 @@ static struct grub_fs grub_udf_fs = {
   .read = grub_udf_read,
   .close = grub_udf_close,
   .label = grub_udf_label,
+  .uuid = grub_udf_uuid,
 #ifdef GRUB_UTIL
   .reserved_first_sector = 1,
   .blocklist_install = 1,
-- 
1.7.9.5



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2] * grub-core/fs/udf.c: Add support for UUID
  2017-06-22 12:42 ` [PATCH v2] " Pali Rohár
@ 2017-08-07 15:50   ` Vladimir 'phcoder' Serbinenko
  0 siblings, 0 replies; 10+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2017-08-07 15:50 UTC (permalink / raw)
  To: Pali Rohár, grub-devel

[-- Attachment #1: Type: text/plain, Size: 6027 bytes --]

Committed with few fixes. Thanks

Le Thu, Jun 22, 2017 à 2:42 PM, Pali Rohár <pali.rohar@gmail.com> a écrit :

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

[-- Attachment #2: Type: text/html, Size: 7060 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-08-07 15:50 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-10 18:35 [PATCH] * grub-core/fs/udf.c: Add support for UUID Pali Rohár
2017-04-19 17:48 ` Pali Rohár
2017-04-19 18:11   ` Andrei Borzenkov
2017-05-08 12:55   ` Pali Rohár
2017-05-08 13:13 ` Vladimir 'phcoder' Serbinenko
2017-05-08 14:24   ` Pali Rohár
2017-05-11 10:59     ` Pali Rohár
2017-05-12 14:39   ` Pali Rohár
2017-06-22 12:42 ` [PATCH v2] " Pali Rohár
2017-08-07 15:50   ` Vladimir 'phcoder' Serbinenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).