From 2c57305f72cd6181d1849ae6e1b892aa01c7f844 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 8 Aug 2011 18:52:23 +0100 Subject: [PATCH] inspection: Better checking for Windows root disks (RHBZ#729075). 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). --- src/guestfs-internal.h | 3 ++ src/inspect_fs.c | 30 ++++++-------------- src/inspect_fs_windows.c | 72 ++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 75 insertions(+), 30 deletions(-) diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index de073d2..d2deb1c 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -357,6 +357,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_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); @@ -372,6 +374,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 diff --git a/src/inspect_fs.c b/src/inspect_fs.c index 3fa5c98..3f7be0e 100644 --- a/src/inspect_fs.c +++ b/src/inspect_fs.c @@ -87,8 +87,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. @@ -214,18 +212,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; @@ -233,11 +221,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). @@ -286,8 +274,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; @@ -300,8 +288,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; diff --git a/src/inspect_fs_windows.c b/src/inspect_fs_windows.c index 60d9c0f..7d09fd1 100644 --- a/src/inspect_fs_windows.c +++ b/src/inspect_fs_windows.c @@ -89,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; -- 1.8.3.1