inspection: Better checking for Windows root disks (RHBZ#729075).
authorRichard W.M. Jones <rjones@redhat.com>
Mon, 8 Aug 2011 17:52:23 +0000 (18:52 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Wed, 17 Aug 2011 12:05:22 +0000 (13:05 +0100)
Previously any disk that had /autoexec.bat or /boot.ini or /ntldr
would be picked up as a candidate for a Windows root disk.  If further
checking could not find any systemroot (eg. /windows) then this would
result in complete failure of inspection.

In particular, this got confused by Hp_recovery partitions which have
/autoexec.bat, but don't have a systemroot in one of the usual places
(they have /MiniNT instead).

What we do now is to properly investigate all possible systemroot
places before deciding this is a Windows systemroot, so the subsequent
failure cannot occur.

(Thanks to lorimar for reporting this bug).

Cherry picked from commit 2c57305f72cd6181d1849ae6e1b892aa01c7f844
and backported to stable-1.10 branch.

src/guestfs-internal.h
src/inspect_fs.c
src/inspect_fs_windows.c

index 8d4d300..7304a56 100644 (file)
@@ -347,6 +347,8 @@ extern void guestfs___rollback_cmdline (guestfs_h *g, size_t pos);
 extern void guestfs___call_callbacks_void (guestfs_h *g, uint64_t event);
 extern void guestfs___call_callbacks_message (guestfs_h *g, uint64_t event, const char *buf, size_t buf_len);
 extern void guestfs___call_callbacks_array (guestfs_h *g, uint64_t event, const uint64_t *array, size_t array_len);
+extern int guestfs___is_file_nocase (guestfs_h *g, const char *);
+extern int guestfs___is_dir_nocase (guestfs_h *g, const char *);
 #if defined(HAVE_PCRE) && defined(HAVE_HIVEX)
 extern int guestfs___check_for_filesystem_on (guestfs_h *g, const char *device, int is_block, int is_partnum);
 extern char *guestfs___download_to_tmp (guestfs_h *g, struct inspect_fs *fs, const char *filename, const char *basename, int64_t max_size);
@@ -362,6 +364,7 @@ extern int guestfs___read_db_dump (guestfs_h *g, const char *dumpfile, void *opa
 extern int guestfs___check_installer_root (guestfs_h *g, struct inspect_fs *fs);
 extern int guestfs___check_linux_root (guestfs_h *g, struct inspect_fs *fs);
 extern int guestfs___check_freebsd_root (guestfs_h *g, struct inspect_fs *fs);
+extern int guestfs___has_windows_systemroot (guestfs_h *g);
 extern int guestfs___check_windows_root (guestfs_h *g, struct inspect_fs *fs);
 #endif
 
index ff54634..5c06d44 100644 (file)
@@ -89,8 +89,6 @@ static int check_filesystem (guestfs_h *g, const char *device, int is_block, int
 static void check_package_format (guestfs_h *g, struct inspect_fs *fs);
 static void check_package_management (guestfs_h *g, struct inspect_fs *fs);
 static int extend_fses (guestfs_h *g);
-static int is_file_nocase (guestfs_h *g, const char *);
-static int is_dir_nocase (guestfs_h *g, const char *);
 
 /* Find out if 'device' contains a filesystem.  If it does, add
  * another entry in g->fses.
@@ -216,18 +214,8 @@ check_filesystem (guestfs_h *g, const char *device,
            guestfs_is_dir (g, "/run") > 0 &&
            guestfs_is_dir (g, "/spool") > 0)
     fs->content = FS_CONTENT_LINUX_VAR;
-  /* Windows root?
-   * Note that 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)
-   */
-  else if (is_file_nocase (g, "/AUTOEXEC.BAT") > 0 ||
-           is_dir_nocase (g, "/WINDOWS/SYSTEM32") > 0 ||
-           is_dir_nocase (g, "/WIN32/SYSTEM32") > 0 ||
-           is_dir_nocase (g, "/WINNT/SYSTEM32") > 0 ||
-           is_file_nocase (g, "/boot.ini") > 0 ||
-           is_file_nocase (g, "/ntldr") > 0) {
+  /* Windows root? */
+  else if (guestfs___has_windows_systemroot (g) >= 0) {
     fs->is_root = 1;
     fs->content = FS_CONTENT_WINDOWS_ROOT;
     fs->format = OS_FORMAT_INSTALLED;
@@ -235,11 +223,11 @@ check_filesystem (guestfs_h *g, const char *device,
       return -1;
   }
   /* Windows volume with installed applications (but not root)? */
-  else if (is_dir_nocase (g, "/System Volume Information") > 0 &&
-           is_dir_nocase (g, "/Program Files") > 0)
+  else if (guestfs___is_dir_nocase (g, "/System Volume Information") > 0 &&
+           guestfs___is_dir_nocase (g, "/Program Files") > 0)
     fs->content = FS_CONTENT_WINDOWS_VOLUME_WITH_APPS;
   /* Windows volume (but not root)? */
-  else if (is_dir_nocase (g, "/System Volume Information") > 0)
+  else if (guestfs___is_dir_nocase (g, "/System Volume Information") > 0)
     fs->content = FS_CONTENT_WINDOWS_VOLUME;
   /* Install CD/disk?  Skip these checks if it's not a whole device
    * (eg. CD) or the first partition (eg. bootable USB key).
@@ -288,8 +276,8 @@ extend_fses (guestfs_h *g)
   return 0;
 }
 
-static int
-is_file_nocase (guestfs_h *g, const char *path)
+int
+guestfs___is_file_nocase (guestfs_h *g, const char *path)
 {
   char *p;
   int r;
@@ -302,8 +290,8 @@ is_file_nocase (guestfs_h *g, const char *path)
   return r > 0;
 }
 
-static int
-is_dir_nocase (guestfs_h *g, const char *path)
+int
+guestfs___is_dir_nocase (guestfs_h *g, const char *path)
 {
   char *p;
   int r;
index da7540f..0fd7965 100644 (file)
@@ -91,23 +91,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;