Blame SOURCES/0132-inspect-get-windows-drive-letters-for-GPT-disks.patch

e76f14
From 3d23c51e654f479de8ddbfd1cd7e44753d4bb19d Mon Sep 17 00:00:00 2001
e76f14
From: Dawid Zamirski <dzamirski@datto.com>
e76f14
Date: Sat, 6 Feb 2016 11:50:05 -0500
e76f14
Subject: [PATCH] inspect: get windows drive letters for GPT disks.
e76f14
e76f14
This patch updates the guestfs_inspect_get_drive_mappings API call to
e76f14
also return drive letters for GPT paritions. Previously this worked
e76f14
only for MBR partitions. This is achieved by matching the GPT partition
e76f14
GUID with the info stored in the blob from
e76f14
HKLM\SYSTEM\MountedDevices\DosDevices keys. For GPT partions this blob
e76f14
contains a "DMIO:ID:" prefix followed by a 16 byte binary GUID.
e76f14
e76f14
(cherry picked from commit 7cb28488a6b974c86a9dd0264d892cd01739c36e)
e76f14
---
e76f14
 src/inspect-fs-windows.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++-
e76f14
 1 file changed, 94 insertions(+), 2 deletions(-)
e76f14
e76f14
diff --git a/src/inspect-fs-windows.c b/src/inspect-fs-windows.c
e76f14
index 7e3ead5..f8717fc 100644
e76f14
--- a/src/inspect-fs-windows.c
e76f14
+++ b/src/inspect-fs-windows.c
e76f14
@@ -25,6 +25,7 @@
e76f14
 #include <string.h>
e76f14
 #include <errno.h>
e76f14
 #include <iconv.h>
e76f14
+#include <inttypes.h>
e76f14
 
e76f14
 #ifdef HAVE_ENDIAN_H
e76f14
 #include <endian.h>
e76f14
@@ -57,6 +58,8 @@ static int check_windows_arch (guestfs_h *g, struct inspect_fs *fs);
e76f14
 static int check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs);
e76f14
 static int check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs);
e76f14
 static char *map_registry_disk_blob (guestfs_h *g, const void *blob);
e76f14
+static char *map_registry_disk_blob_gpt (guestfs_h *g, const void *blob);
e76f14
+static char *extract_guid_from_registry_blob (guestfs_h *g, const void *blob);
e76f14
 
e76f14
 /* XXX Handling of boot.ini in the Perl version was pretty broken.  It
e76f14
  * essentially didn't do anything for modern Windows guests.
e76f14
@@ -386,6 +389,7 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
e76f14
   int r;
e76f14
   size_t len = strlen (fs->windows_systemroot) + 64;
e76f14
   char system[len];
e76f14
+  char gpt_prefix[] = "DMIO:ID:";
e76f14
   snprintf (system, len, "%s/system32/config/system",
e76f14
             fs->windows_systemroot);
e76f14
 
e76f14
@@ -490,12 +494,18 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
e76f14
       CLEANUP_FREE char *blob = NULL;
e76f14
       char *device;
e76f14
       int64_t type;
e76f14
+      bool is_gpt;
e76f14
 
e76f14
       type = guestfs_hivex_value_type (g, v);
e76f14
       blob = guestfs_hivex_value_value (g, v, &len;;
e76f14
-      if (blob != NULL && type == 3 && len == 12) {
e76f14
+      is_gpt = memcmp (blob, gpt_prefix, 8) == 0;
e76f14
+      if (blob != NULL && type == 3 && (len == 12 || is_gpt)) {
e76f14
         /* Try to map the blob to a known disk and partition. */
e76f14
-        device = map_registry_disk_blob (g, blob);
e76f14
+        if (is_gpt)
e76f14
+          device = map_registry_disk_blob_gpt (g, blob);
e76f14
+        else
e76f14
+          device = map_registry_disk_blob (g, blob);
e76f14
+
e76f14
         if (device != NULL) {
e76f14
           fs->drive_mappings[count++] = safe_strndup (g, &key[12], 1);
e76f14
           fs->drive_mappings[count++] = device;
e76f14
@@ -605,6 +615,88 @@ map_registry_disk_blob (guestfs_h *g, const void *blob)
e76f14
   return safe_asprintf (g, "%s%d", devices[i], partitions->val[j].part_num);
e76f14
 }
e76f14
 
e76f14
+/* Matches Windows registry HKLM\SYSYTEM\MountedDevices\DosDevices blob to
e76f14
+ * to libguestfs GPT partition device. For GPT disks, the blob is made of
e76f14
+ * "DMIO:ID:" prefix followed by the GPT partition GUID.
e76f14
+ */
e76f14
+static char *
e76f14
+map_registry_disk_blob_gpt (guestfs_h *g, const void *blob)
e76f14
+{
e76f14
+  CLEANUP_FREE_STRING_LIST char **parts = NULL;
e76f14
+  CLEANUP_FREE char *blob_guid = extract_guid_from_registry_blob (g, blob);
e76f14
+  size_t i;
e76f14
+
e76f14
+  parts = guestfs_list_partitions (g);
e76f14
+  if (parts == NULL)
e76f14
+    return NULL;
e76f14
+
e76f14
+  for (i = 0; parts[i] != NULL; ++i) {
e76f14
+    CLEANUP_FREE char *fs_guid = NULL;
e76f14
+    int partnum;
e76f14
+    CLEANUP_FREE char *device = NULL;
e76f14
+    CLEANUP_FREE char *type = NULL;
e76f14
+
e76f14
+    partnum = guestfs_part_to_partnum (g, parts[i]);
e76f14
+    if (partnum == -1)
e76f14
+      continue;
e76f14
+
e76f14
+    device = guestfs_part_to_dev (g, parts[i]);
e76f14
+    if (device == NULL)
e76f14
+      continue;
e76f14
+
e76f14
+    type = guestfs_part_get_parttype (g, device);
e76f14
+    if (type == NULL)
e76f14
+      continue;
e76f14
+
e76f14
+    if (STRCASENEQ (type, "gpt"))
e76f14
+      continue;
e76f14
+
e76f14
+    /* get the GPT parition GUID from the partition block device */
e76f14
+    fs_guid = guestfs_part_get_gpt_guid (g, device, partnum);
e76f14
+    if (fs_guid == NULL)
e76f14
+      continue;
e76f14
+
e76f14
+    /* if both GUIDs match, we have found the mapping for our device */
e76f14
+    if (STRCASEEQ (fs_guid, blob_guid))
e76f14
+      return safe_strdup (g, parts[i]);
e76f14
+  }
e76f14
+
e76f14
+  return NULL;
e76f14
+}
e76f14
+
e76f14
+/* Extracts the binary GUID stored in blob from Windows registry
e76f14
+ * HKLM\SYSTYEM\MountedDevices\DosDevices value and converts it to a
e76f14
+ * GUID string so that it can be matched against libguestfs partition
e76f14
+ * device GPT GUID.
e76f14
+ */
e76f14
+static char *
e76f14
+extract_guid_from_registry_blob (guestfs_h *g, const void *blob)
e76f14
+{
e76f14
+  char guid_bytes[16];
e76f14
+  uint32_t data1;
e76f14
+  uint16_t data2, data3;
e76f14
+  uint64_t data4;
e76f14
+
e76f14
+  /* get the GUID bytes from blob (skip 8 byte "DMIO:ID:" prefix) */
e76f14
+  memcpy (&guid_bytes, (char *) blob + 8, sizeof (guid_bytes));
e76f14
+
e76f14
+  /* copy relevant sections from blob to respective ints */
e76f14
+  memcpy (&data1, guid_bytes, sizeof (data1));
e76f14
+  memcpy (&data2, guid_bytes + 4, sizeof (data2));
e76f14
+  memcpy (&data3, guid_bytes + 6, sizeof (data3));
e76f14
+  memcpy (&data4, guid_bytes + 8, sizeof (data4));
e76f14
+
e76f14
+  /* ensure proper endianness */
e76f14
+  data1 = le32toh (data1);
e76f14
+  data2 = le16toh (data2);
e76f14
+  data3 = le16toh (data3);
e76f14
+  data4 = be64toh (data4);
e76f14
+
e76f14
+  return safe_asprintf (g,
e76f14
+           "%08" PRIX32 "-%04" PRIX16 "-%04" PRIX16 "-%04" PRIX64 "-%012" PRIX64,
e76f14
+           data1, data2, data3, data4 >> 48, data4 & 0xffffffffffff);
e76f14
+}
e76f14
+
e76f14
 /* NB: This function DOES NOT test for the existence of the file.  It
e76f14
  * will return non-NULL even if the file/directory does not exist.
e76f14
  * You have to call guestfs_is_file{,_opts} etc.
e76f14
-- 
7af31e
1.8.3.1
e76f14