New tool: virt-sysprep: system preparation for guests.
[libguestfs.git] / src / inspect_fs_windows.c
index 9a2e1fb..7d09fd1 100644 (file)
@@ -29,9 +29,7 @@
 #include <errno.h>
 #include <endian.h>
 
-#ifdef HAVE_PCRE
 #include <pcre.h>
-#endif
 
 #ifdef HAVE_HIVEX
 #include <hivex.h>
@@ -46,7 +44,7 @@
 #include "guestfs-internal-actions.h"
 #include "guestfs_protocol.h"
 
-#if defined(HAVE_PCRE) && defined(HAVE_HIVEX)
+#if defined(HAVE_HIVEX)
 
 /* Compile all the regular expressions once when the shared library is
  * loaded.  PCRE is thread safe so we're supposedly OK here if
@@ -91,23 +89,77 @@ static char *map_registry_disk_blob (guestfs_h *g, const char *blob);
  * essentially didn't do anything for modern Windows guests.
  * Therefore I've omitted all that code.
  */
+
+/* Try to find Windows systemroot using some common locations.
+ *
+ * Notes:
+ *
+ * (1) We check for some directories inside to see if it is a real
+ * systemroot, and not just a directory that happens to have the same
+ * name.
+ *
+ * (2) If a Windows guest has multiple disks and applications are
+ * installed on those other disks, then those other disks will contain
+ * "/Program Files" and "/System Volume Information".  Those would
+ * *not* be Windows root disks.  (RHBZ#674130)
+ */
+static const char *systemroots[] =
+  { "/windows", "/winnt", "/win32", "/win", NULL };
+
+int
+guestfs___has_windows_systemroot (guestfs_h *g)
+{
+  size_t i;
+  char *systemroot, *p;
+  char path[256];
+
+  for (i = 0; i < sizeof systemroots / sizeof systemroots[0]; ++i) {
+    systemroot = guestfs___case_sensitive_path_silently (g, systemroots[i]);
+    if (!systemroot)
+      continue;
+
+    snprintf (path, sizeof path, "%s/system32", systemroot);
+    if (!guestfs___is_dir_nocase (g, path)) {
+      free (systemroot);
+      continue;
+    }
+
+    snprintf (path, sizeof path, "%s/system32/config", systemroot);
+    if (!guestfs___is_dir_nocase (g, path)) {
+      free (systemroot);
+      continue;
+    }
+
+    snprintf (path, sizeof path, "%s/system32/cmd.exe", systemroot);
+    if (!guestfs___is_file_nocase (g, path)) {
+      free (systemroot);
+      continue;
+    }
+
+    free (systemroot);
+
+    return (int)i;
+  }
+
+  return -1; /* not found */
+}
+
 int
 guestfs___check_windows_root (guestfs_h *g, struct inspect_fs *fs)
 {
+  int i;
+  char *systemroot;
+
   fs->type = OS_TYPE_WINDOWS;
   fs->distro = OS_DISTRO_WINDOWS;
 
-  /* Try to find Windows systemroot using some common locations. */
-  const char *systemroots[] =
-    { "/windows", "/winnt", "/win32", "/win" };
-  size_t i;
-  char *systemroot = NULL;
-  for (i = 0;
-       systemroot == NULL && i < sizeof systemroots / sizeof systemroots[0];
-       ++i) {
-    systemroot = guestfs___case_sensitive_path_silently (g, systemroots[i]);
+  i = guestfs___has_windows_systemroot (g);
+  if (i == -1) {
+    error (g, "check_windows_root: has_windows_systemroot unexpectedly returned -1");
+    return -1;
   }
 
+  systemroot = guestfs___case_sensitive_path_silently (g, systemroots[i]);
   if (!systemroot) {
     error (g, _("cannot resolve Windows %%SYSTEMROOT%%"));
     return -1;
@@ -159,11 +211,6 @@ check_windows_arch (guestfs_h *g, struct inspect_fs *fs)
 static int
 check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
 {
-  const char *basename = "software";
-  char tmpdir_basename[strlen (g->tmpdir) + strlen (basename) + 2];
-  snprintf (tmpdir_basename, sizeof tmpdir_basename, "%s/%s",
-            g->tmpdir, basename);
-
   size_t len = strlen (fs->windows_systemroot) + 64;
   char software[len];
   snprintf (software, len, "%s/system32/config/software",
@@ -176,15 +223,17 @@ check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
      */
     return 0;
 
+  char *software_hive = NULL;
   int ret = -1;
   hive_h *h = NULL;
   hive_value_h *values = NULL;
 
-  if (guestfs___download_to_tmp (g, software_path, basename,
-                                 MAX_REGISTRY_SIZE) == -1)
+  software_hive = guestfs___download_to_tmp (g, fs, software_path, "software",
+                                             MAX_REGISTRY_SIZE);
+  if (software_hive == NULL)
     goto out;
 
-  h = hivex_open (tmpdir_basename, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
+  h = hivex_open (software_hive, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
   if (h == NULL) {
     perrorf (g, "hivex_open");
     goto out;
@@ -268,6 +317,7 @@ check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
   if (h) hivex_close (h);
   free (values);
   free (software_path);
+  free (software_hive);
 
   return ret;
 }
@@ -275,11 +325,6 @@ check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
 static int
 check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
 {
-  const char *basename = "system";
-  char tmpdir_basename[strlen (g->tmpdir) + strlen (basename) + 2];
-  snprintf (tmpdir_basename, sizeof tmpdir_basename, "%s/%s",
-            g->tmpdir, basename);
-
   size_t len = strlen (fs->windows_systemroot) + 64;
   char system[len];
   snprintf (system, len, "%s/system32/config/system",
@@ -292,6 +337,7 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
      */
     return 0;
 
+  char *system_hive = NULL;
   int ret = -1;
   hive_h *h = NULL;
   hive_node_h root, node;
@@ -299,11 +345,13 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
   int32_t dword;
   size_t i, count;
 
-  if (guestfs___download_to_tmp (g, system_path, basename,
-                                 MAX_REGISTRY_SIZE) == -1)
+  system_hive =
+    guestfs___download_to_tmp (g, fs, system_path, "system",
+                               MAX_REGISTRY_SIZE);
+  if (system_hive == NULL)
     goto out;
 
-  h = hivex_open (tmpdir_basename, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
+  h = hivex_open (system_hive, g->verbose ? HIVEX_OPEN_VERBOSE : 0);
   if (h == NULL) {
     perrorf (g, "hivex_open");
     goto out;
@@ -449,6 +497,7 @@ check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
   if (h) hivex_close (h);
   free (values);
   free (system_path);
+  free (system_hive);
 
   return ret;
 }
@@ -532,4 +581,4 @@ guestfs___case_sensitive_path_silently (guestfs_h *g, const char *path)
   return ret;
 }
 
-#endif /* defined(HAVE_PCRE) && defined(HAVE_HIVEX) */
+#endif /* defined(HAVE_HIVEX) */