On Mon, Apr 10, 2017, 23:17 Pali Rohár <pali.ro...@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
>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to