[Libguestfs] [PATCHv2] inspect: get windows drive letters for GPT disks.
Richard W.M. Jones
rjones at redhat.com
Fri Feb 5 22:21:20 UTC 2016
On Fri, Feb 05, 2016 at 05:14:43PM -0500, Dawid Zamirski wrote:
> This patch updates the guestfs_inspect_get_drive_mappings API call to
> also return drive letters for GPT paritions. Previously this worked
> only for MBR partitions. This is achieved by matching the GPT partition
> GUID with the info stored in the blob from
> HKLM\SYSTEM\MountedDevices\DosDevices keys. For GPT partions this blob
> contains a "DMIO:ID:" prefix followed by a 16 byte binary GUID.
Yup, this looks OK to me. I'll have a play with it tomorrow as I
believe somewhere I have a UEFI (hence GPT) Windows disk image. If it
works I'll push it upstream.
Thanks,
Rich.
>
> changes since v1:
> * applied style changes from review
> * use guestfs_list_partitions instead of guestfs_list_filesystems
> * do the GUID endianness conversion correctly
> * check all API calls for errors
> * do not call guestfs_canonical_device_name to prevent from changing
> * block device names, i.e /dev/vda1 as it comes from list_partitions
> * to /dev/sda1 in inspect_get_drive_mappings
>
> src/inspect-fs-windows.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 102 insertions(+), 2 deletions(-)
>
> diff --git a/src/inspect-fs-windows.c b/src/inspect-fs-windows.c
> index ccf5cba..1698e81 100644
> --- a/src/inspect-fs-windows.c
> +++ b/src/inspect-fs-windows.c
> @@ -25,6 +25,7 @@
> #include <string.h>
> #include <errno.h>
> #include <iconv.h>
> +#include <inttypes.h>
>
> #ifdef HAVE_ENDIAN_H
> #include <endian.h>
> @@ -57,6 +58,8 @@ static int check_windows_arch (guestfs_h *g, struct inspect_fs *fs);
> static int check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs);
> static int check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs);
> static char *map_registry_disk_blob (guestfs_h *g, const void *blob);
> +static char *map_registry_disk_blob_gpt (guestfs_h *g, const void *blob);
> +static char *extract_guid_from_registry_blob (guestfs_h *g, const void *blob);
>
> /* XXX Handling of boot.ini in the Perl version was pretty broken. It
> * essentially didn't do anything for modern Windows guests.
> @@ -386,6 +389,7 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
> int r;
> size_t len = strlen (fs->windows_systemroot) + 64;
> char system[len];
> + char gpt_prefix[] = "DMIO:ID:";
> snprintf (system, len, "%s/system32/config/system",
> fs->windows_systemroot);
>
> @@ -490,12 +494,18 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
> CLEANUP_FREE char *blob = NULL;
> char *device;
> int64_t type;
> + bool is_gpt;
>
> type = guestfs_hivex_value_type (g, v);
> blob = guestfs_hivex_value_value (g, v, &len);
> - if (blob != NULL && type == 3 && len == 12) {
> + is_gpt = memcmp (blob, gpt_prefix, 8) == 0;
> + if (blob != NULL && type == 3 && (len == 12 || is_gpt)) {
> /* Try to map the blob to a known disk and partition. */
> - device = map_registry_disk_blob (g, blob);
> + if (is_gpt)
> + device = map_registry_disk_blob_gpt (g, blob);
> + else
> + device = map_registry_disk_blob (g, blob);
> +
> if (device != NULL) {
> fs->drive_mappings[count++] = safe_strndup (g, &key[12], 1);
> fs->drive_mappings[count++] = device;
> @@ -605,6 +615,96 @@ map_registry_disk_blob (guestfs_h *g, const void *blob)
> return safe_asprintf (g, "%s%d", devices[i], partitions->val[j].part_num);
> }
>
> +/* Matches Windows registry HKLM\SYSYTEM\MountedDevices\DosDevices blob to
> + * to libguestfs GPT partition device. For GPT disks, the blob is made of
> + * "DMIO:ID:" prefix followed by the GPT partition GUID.
> + */
> +static char *
> +map_registry_disk_blob_gpt (guestfs_h *g, const void *blob)
> +{
> + CLEANUP_FREE_STRING_LIST char **parts = NULL;
> + size_t i;
> +
> + parts = guestfs_list_partitions (g);
> +
> + if (parts == NULL)
> + return NULL;
> +
> + for (i = 0; parts[i] != NULL; i += 2) {
> + CLEANUP_FREE char *fs_guid = NULL;
> + CLEANUP_FREE char *blob_guid = NULL;
> + int partnum;
> + CLEANUP_FREE char *device = NULL;
> + CLEANUP_FREE char *type = NULL;
> +
> + partnum = guestfs_part_to_partnum (g, parts[i]);
> +
> + if (partnum == -1)
> + continue;
> +
> + device = guestfs_part_to_dev (g, parts[i]);
> +
> + if (device == NULL)
> + continue;
> +
> + type = guestfs_part_get_parttype (g, device);
> +
> + if (type == NULL)
> + continue;
> +
> + if (STRCASENEQ (type, "gpt"))
> + continue;
> +
> + /* get the GPT parition GUID from the partition block device */
> + fs_guid = guestfs_part_get_gpt_guid (g, device, partnum);
> +
> + if (fs_guid == NULL)
> + continue;
> +
> + /* extract the GUID from the Windows registry blob */
> + blob_guid = extract_guid_from_registry_blob (g, blob);
> +
> + /* if both GUIDs match, we have found mapping for out device */
> + if (STRCASEEQ (fs_guid, blob_guid))
> + return safe_strdup (g, parts[i]);
> + }
> +
> + return NULL;
> +}
> +
> +/* Extracts the binary GUID stored in blob from Windows registry
> + * HKLM\SYSTYEM\MountedDevices\DosDevices value and converts it to a
> + * GUID string so that it can be matched against libguestfs partition
> + * device GPT GUID.
> + */
> +static char *
> +extract_guid_from_registry_blob (guestfs_h *g, const void *blob)
> +{
> + char guid_bytes[16];
> + uint32_t data1;
> + uint16_t data2, data3;
> + uint64_t data4;
> +
> + /* get the GUID bytes from blob (skip 8 byte "DMIO:ID:" prefix) */
> + memcpy (&guid_bytes, (char *) blob + 8, sizeof (guid_bytes));
> +
> + /* copy relevant sections from blob to respective ints */
> + memcpy (&data1, guid_bytes, sizeof (data1));
> + memcpy (&data2, guid_bytes + 4, sizeof (data2));
> + memcpy (&data3, guid_bytes + 6, sizeof (data3));
> + memcpy (&data4, guid_bytes + 8, sizeof (data4));
> +
> + /* ensure proper endianness */
> + data1 = le32toh (data1);
> + data2 = le16toh (data2);
> + data3 = le16toh (data3);
> + data4 = be64toh (data4);
> +
> + return safe_asprintf (g,
> + "%08" PRIX32 "-%04" PRIX16 "-%04" PRIX16 "-%04" PRIX64 "-%06" PRIX64,
> + data1, data2, data3, (data4 >> 48), (data4 << 16));
> +}
> +
> /* NB: This function DOES NOT test for the existence of the file. It
> * will return non-NULL even if the file/directory does not exist.
> * You have to call guestfs_is_file{,_opts} etc.
> --
> 2.5.0
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
Fedora Windows cross-compiler. Compile Windows programs, test, and
build Windows installers. Over 100 libraries supported.
http://fedoraproject.org/wiki/MinGW
More information about the Libguestfs
mailing list