[USETUP][SETUPLIB] Code refactoring.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 9 Aug 2017 20:39:45 +0000 (20:39 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 27 Oct 2018 16:13:32 +0000 (18:13 +0200)
- Move several global setup variables into a structure "USETUP_DATA",
  similar to the syssetup structure "SETUPDATA" (or the WIP 1st-stage
  installer structure of the same name), so that these variables can be
  set easily by different helper setup functions;

- Move CheckUnattendedSetup() and GetSourcePaths() to setuplib and make
  CheckUnattendedSetup() use the USETUP_DATA structure;

- Add a LoadSetupInf() function that loads the txtsetup.sif file
  (factoring out the corresponding code in USETUP);

- Add a InstallSetupInfFile() function (that I'll probably rename later on)
  whose purpose is to create a valid "$winnt$.inf" setup installation file
  in the ReactOS\system32 directory, which should help the 2nd-stage installer
  to correctly retrieve the source installation media we used during 1st-stage,
  and contain the unattended setup lines copied from unattend.inf. This is
  done in a Windows-compatible way.

svn path=/branches/setup_improvements/; revision=75518

[USETUP] Close the txtsetup.sif file at the end of the operations.

svn path=/branches/setup_improvements/; revision=75539

base/setup/lib/CMakeLists.txt
base/setup/lib/setuplib.c [new file with mode: 0644]
base/setup/lib/setuplib.h
base/setup/usetup/usetup.c

index c1164c8..cf3f2b8 100644 (file)
@@ -12,6 +12,7 @@ list(APPEND SOURCE
     partlist.c
     registry.c
     regutil.c
+    setuplib.c
     precomp.h)
 
 add_library(setuplib ${SOURCE})
diff --git a/base/setup/lib/setuplib.c b/base/setup/lib/setuplib.c
new file mode 100644 (file)
index 0000000..306065f
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS Setup Library
+ * FILE:            base/setup/lib/setuplib.c
+ * PURPOSE:         Setup Library - Main initialization helpers
+ * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
+ *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "precomp.h"
+#include "filesup.h"
+#include "infsupp.h"
+#include "inicache.h"
+
+#include "setuplib.h"
+
+// HACK!
+#include <strsafe.h>
+
+#define NDEBUG
+#include <debug.h>
+
+
+/* GLOBALS ******************************************************************/
+
+/* FUNCTIONS ****************************************************************/
+
+VOID
+CheckUnattendedSetup(
+    IN OUT PUSETUP_DATA pSetupData)
+{
+    INFCONTEXT Context;
+    HINF UnattendInf;
+    UINT ErrorLine;
+    INT IntValue;
+    PWCHAR Value;
+    WCHAR UnattendInfPath[MAX_PATH];
+
+    CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2,
+                 pSetupData->SourcePath.Buffer, L"unattend.inf");
+
+    if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
+    {
+        DPRINT("Does not exist: %S\n", UnattendInfPath);
+        return;
+    }
+
+    /* Load 'unattend.inf' from installation media */
+    UnattendInf = SetupOpenInfFileExW(UnattendInfPath,
+                                      NULL,
+                                      INF_STYLE_WIN4,
+                                      pSetupData->LanguageId,
+                                      &ErrorLine);
+
+    if (UnattendInf == INVALID_HANDLE_VALUE)
+    {
+        DPRINT("SetupOpenInfFileExW() failed\n");
+        return;
+    }
+
+    /* Open 'Unattend' section */
+    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"Signature", &Context))
+    {
+        DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
+        goto Quit;
+    }
+
+    /* Get pointer 'Signature' key */
+    if (!INF_GetData(&Context, NULL, &Value))
+    {
+        DPRINT("INF_GetData() failed for key 'Signature'\n");
+        goto Quit;
+    }
+
+    /* Check 'Signature' string */
+    if (_wcsicmp(Value, L"$ReactOS$") != 0)
+    {
+        DPRINT("Signature not $ReactOS$\n");
+        INF_FreeData(Value);
+        goto Quit;
+    }
+
+    INF_FreeData(Value);
+
+    /* Check if Unattend setup is enabled */
+    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"UnattendSetupEnabled", &Context))
+    {
+        DPRINT("Can't find key 'UnattendSetupEnabled'\n");
+        goto Quit;
+    }
+
+    if (!INF_GetData(&Context, NULL, &Value))
+    {
+        DPRINT("Can't read key 'UnattendSetupEnabled'\n");
+        goto Quit;
+    }
+
+    if (_wcsicmp(Value, L"yes") != 0)
+    {
+        DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
+        INF_FreeData(Value);
+        goto Quit;
+    }
+
+    INF_FreeData(Value);
+
+    /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
+    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context))
+    {
+        DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
+        goto Quit;
+    }
+
+    if (!SetupGetIntField(&Context, 1, &IntValue))
+    {
+        DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
+        goto Quit;
+    }
+
+    pSetupData->DestinationDiskNumber = (LONG)IntValue;
+
+    /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
+    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
+    {
+        DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
+        goto Quit;
+    }
+
+    if (!SetupGetIntField(&Context, 1, &IntValue))
+    {
+        DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
+        goto Quit;
+    }
+
+    pSetupData->DestinationPartitionNumber = (LONG)IntValue;
+
+    /* Search for 'InstallationDirectory' in the 'Unattend' section (optional) */
+    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"InstallationDirectory", &Context))
+    {
+        /* Get pointer 'InstallationDirectory' key */
+        if (!INF_GetData(&Context, NULL, &Value))
+        {
+            DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
+            goto Quit;
+        }
+        wcscpy(pSetupData->InstallationDirectory, Value);
+        INF_FreeData(Value);
+    }
+
+    IsUnattendedSetup = TRUE;
+    DPRINT("Running unattended setup\n");
+
+    /* Search for 'MBRInstallType' in the 'Unattend' section */
+    pSetupData->MBRInstallType = -1;
+    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"MBRInstallType", &Context))
+    {
+        if (SetupGetIntField(&Context, 1, &IntValue))
+        {
+            pSetupData->MBRInstallType = IntValue;
+        }
+    }
+
+    /* Search for 'FormatPartition' in the 'Unattend' section */
+    pSetupData->FormatPartition = 0;
+    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"FormatPartition", &Context))
+    {
+        if (SetupGetIntField(&Context, 1, &IntValue))
+        {
+            pSetupData->FormatPartition = IntValue;
+        }
+    }
+
+    pSetupData->AutoPartition = 0;
+    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"AutoPartition", &Context))
+    {
+        if (SetupGetIntField(&Context, 1, &IntValue))
+        {
+            pSetupData->AutoPartition = IntValue;
+        }
+    }
+
+    /* Search for LocaleID in the 'Unattend' section */
+    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"LocaleID", &Context))
+    {
+        if (INF_GetData(&Context, NULL, &Value))
+        {
+            LONG Id = wcstol(Value, NULL, 16);
+            swprintf(pSetupData->LocaleID, L"%08lx", Id);
+            INF_FreeData(Value);
+       }
+    }
+
+Quit:
+    SetupCloseInfFile(UnattendInf);
+}
+
+VOID
+InstallSetupInfFile(
+    IN OUT PUSETUP_DATA pSetupData)
+{
+    NTSTATUS Status;
+    PINICACHE IniCache;
+
+#if 0 // HACK FIXME!
+    PINICACHE UnattendCache;
+    PINICACHEITERATOR Iterator;
+#else
+    // PCWSTR CrLf = L"\r\n";
+    PCSTR CrLf = "\r\n";
+    HANDLE FileHandle, UnattendFileHandle, SectionHandle;
+    FILE_STANDARD_INFORMATION FileInfo;
+    ULONG FileSize;
+    PVOID ViewBase;
+    UNICODE_STRING FileName;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK IoStatusBlock;
+#endif
+
+    PINICACHESECTION IniSection;
+    WCHAR PathBuffer[MAX_PATH];
+    WCHAR UnattendInfPath[MAX_PATH];
+
+    /* Create a $winnt$.inf file with default entries */
+    IniCache = IniCacheCreate();
+    if (!IniCache)
+        return;
+
+    IniSection = IniCacheAppendSection(IniCache, L"SetupParams");
+    if (IniSection)
+    {
+        /* Key "skipmissingfiles" */
+        // StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+                         // L"\"%s\"", L"WinNt5.2");
+        // IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
+                          // L"Version", PathBuffer);
+    }
+
+    IniSection = IniCacheAppendSection(IniCache, L"Data");
+    if (IniSection)
+    {
+        StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+                         L"\"%s\"", IsUnattendedSetup ? L"yes" : L"no");
+        IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
+                          L"UnattendedInstall", PathBuffer);
+
+        // "floppylessbootpath" (yes/no)
+
+        StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+                         L"\"%s\"", L"winnt");
+        IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
+                          L"ProductType", PathBuffer);
+
+        StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+                         L"\"%s\\\"", pSetupData->SourceRootPath.Buffer);
+        IniCacheInsertKey(IniSection, NULL, INSERT_LAST,
+                          L"SourcePath", PathBuffer);
+
+        // "floppyless" ("0")
+    }
+
+#if 0
+
+    /* TODO: Append the standard unattend.inf file */
+    CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, pSetupData->SourcePath.Buffer, L"unattend.inf");
+    if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
+    {
+        DPRINT("Does not exist: %S\n", UnattendInfPath);
+        goto Quit;
+    }
+
+    Status = IniCacheLoad(&UnattendCache, UnattendInfPath, FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Cannot load %S as an INI file!\n", UnattendInfPath);
+        goto Quit;
+    }
+
+    IniCacheDestroy(UnattendCache);
+
+Quit:
+    CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
+                 pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf");
+    IniCacheSave(IniCache, PathBuffer);
+    IniCacheDestroy(IniCache);
+
+#else
+
+    CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
+                 pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf");
+    IniCacheSave(IniCache, PathBuffer);
+    IniCacheDestroy(IniCache);
+
+    /* TODO: Append the standard unattend.inf file */
+    CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2,
+                 pSetupData->SourcePath.Buffer, L"unattend.inf");
+    if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
+    {
+        DPRINT("Does not exist: %S\n", UnattendInfPath);
+        return;
+    }
+
+    RtlInitUnicodeString(&FileName, PathBuffer);
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &FileName,
+                               OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
+                               NULL,
+                               NULL);
+    Status = NtOpenFile(&FileHandle,
+                        FILE_APPEND_DATA | SYNCHRONIZE,
+                        &ObjectAttributes,
+                        &IoStatusBlock,
+                        FILE_SHARE_READ,
+                        FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Cannot load %S as an INI file!\n", PathBuffer);
+        return;
+    }
+
+    /* Query the file size */
+    Status = NtQueryInformationFile(FileHandle,
+                                    &IoStatusBlock,
+                                    &FileInfo,
+                                    sizeof(FileInfo),
+                                    FileStandardInformation);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
+        FileInfo.EndOfFile.QuadPart = 0ULL;
+    }
+
+    Status = OpenAndMapFile(NULL,
+                            UnattendInfPath,
+                            &UnattendFileHandle,
+                            &SectionHandle,
+                            &ViewBase,
+                            &FileSize,
+                            FALSE);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Cannot load %S !\n", UnattendInfPath);
+        NtClose(FileHandle);
+        return;
+    }
+
+    /* Write to the INI file */
+
+    /* "\r\n" */
+    Status = NtWriteFile(FileHandle,
+                         NULL,
+                         NULL,
+                         NULL,
+                         &IoStatusBlock,
+                         (PVOID)CrLf,
+                         2 * sizeof(CHAR), // 2 * sizeof(WCHAR),
+                         &FileInfo.EndOfFile,
+                         NULL);
+
+    Status = NtWriteFile(FileHandle,
+                         NULL,
+                         NULL,
+                         NULL,
+                         &IoStatusBlock,
+                         ViewBase,
+                         FileSize,
+                         NULL,
+                         NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
+    }
+
+    /* Finally, unmap and close the file */
+    UnMapFile(SectionHandle, ViewBase);
+    NtClose(UnattendFileHandle);
+
+    NtClose(FileHandle);
+#endif
+}
+
+
+
+NTSTATUS
+GetSourcePaths(
+    OUT PUNICODE_STRING SourcePath,
+    OUT PUNICODE_STRING SourceRootPath,
+    OUT PUNICODE_STRING SourceRootDir)
+{
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"\\SystemRoot");
+    UNICODE_STRING SourceName;
+    WCHAR SourceBuffer[MAX_PATH] = L"";
+    HANDLE Handle;
+    ULONG Length;
+    PWCHAR Ptr;
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LinkName,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+
+    Status = NtOpenSymbolicLinkObject(&Handle,
+                                      SYMBOLIC_LINK_ALL_ACCESS,
+                                      &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    RtlInitEmptyUnicodeString(&SourceName, SourceBuffer, sizeof(SourceBuffer));
+
+    Status = NtQuerySymbolicLinkObject(Handle,
+                                       &SourceName,
+                                       &Length);
+    NtClose(Handle);
+
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    RtlCreateUnicodeString(SourcePath,
+                           SourceName.Buffer);
+
+    /* Strip trailing directory */
+    Ptr = wcsrchr(SourceName.Buffer, OBJ_NAME_PATH_SEPARATOR);
+    if (Ptr)
+    {
+        RtlCreateUnicodeString(SourceRootDir, Ptr);
+        *Ptr = UNICODE_NULL;
+    }
+    else
+    {
+        RtlCreateUnicodeString(SourceRootDir, L"");
+    }
+
+    RtlCreateUnicodeString(SourceRootPath,
+                           SourceName.Buffer);
+
+    return STATUS_SUCCESS;
+}
+
+
+ERROR_NUMBER
+LoadSetupInf(
+    OUT HINF* SetupInf,
+    IN OUT PUSETUP_DATA pSetupData)
+{
+    INFCONTEXT Context;
+    UINT ErrorLine;
+    INT IntValue;
+    PWCHAR Value;
+    WCHAR FileNameBuffer[MAX_PATH];
+
+    CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2,
+                 pSetupData->SourcePath.Buffer, L"txtsetup.sif");
+
+    *SetupInf = SetupOpenInfFileExW(FileNameBuffer,
+                                   NULL,
+                                   INF_STYLE_WIN4,
+                                   pSetupData->LanguageId,
+                                   &ErrorLine);
+
+    if (*SetupInf == INVALID_HANDLE_VALUE)
+        return ERROR_LOAD_TXTSETUPSIF;
+
+    /* Open 'Version' section */
+    if (!SetupFindFirstLineW(*SetupInf, L"Version", L"Signature", &Context))
+        return ERROR_CORRUPT_TXTSETUPSIF;
+
+    /* Get pointer 'Signature' key */
+    if (!INF_GetData(&Context, NULL, &Value))
+        return ERROR_CORRUPT_TXTSETUPSIF;
+
+    /* Check 'Signature' string */
+    if (_wcsicmp(Value, L"$ReactOS$") != 0)
+    {
+        INF_FreeData(Value);
+        return ERROR_SIGNATURE_TXTSETUPSIF;
+    }
+
+    INF_FreeData(Value);
+
+    /* Open 'DiskSpaceRequirements' section */
+    if (!SetupFindFirstLineW(*SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
+        return ERROR_CORRUPT_TXTSETUPSIF;
+
+    pSetupData->RequiredPartitionDiskSpace = ~0;
+
+    /* Get the 'FreeSysPartDiskSpace' value */
+    if (!SetupGetIntField(&Context, 1, &IntValue))
+        return ERROR_CORRUPT_TXTSETUPSIF;
+
+    pSetupData->RequiredPartitionDiskSpace = (ULONG)IntValue;
+
+    //
+    // TODO: Support "SetupSourceDevice" and "SetupSourcePath" in txtsetup.sif
+    // See CORE-9023
+    //
+
+    /* Search for 'DefaultPath' in the 'SetupData' section */
+    if (SetupFindFirstLineW(*SetupInf, L"SetupData", L"DefaultPath", &Context))
+    {
+        /* Get pointer 'DefaultPath' key */
+        if (!INF_GetData(&Context, NULL, &Value))
+            return ERROR_CORRUPT_TXTSETUPSIF;
+
+        wcscpy(pSetupData->InstallationDirectory, Value);
+        INF_FreeData(Value);
+    }
+
+    return ERROR_SUCCESS;
+}
+
+/* EOF */
index 223a1ac..154b1d5 100644 (file)
@@ -32,6 +32,7 @@ extern HANDLE ProcessHeap;
 #include "filesup.h"
 #include "fsutil.h"
 #include "genlist.h"
+#include "infsupp.h"
 #include "inicache.h"
 #include "partlist.h"
 #include "arcname.h"
@@ -49,4 +50,74 @@ extern HANDLE ProcessHeap;
 // #define PB (KB*KB*KB*KB*KB)
 
 
+/* TYPEDEFS *****************************************************************/
+
+typedef struct _USETUP_DATA
+{
+/* SOURCE Paths *****/
+    UNICODE_STRING SourceRootPath;
+    UNICODE_STRING SourceRootDir;
+    UNICODE_STRING SourcePath;
+
+/* DESTINATION Paths *****/
+    /*
+     * Path to the system partition, where the boot manager resides.
+     * On x86 PCs, this is usually the active partition.
+     * On ARC, (u)EFI, ... platforms, this is a dedicated partition.
+     *
+     * For more information, see:
+     * https://en.wikipedia.org/wiki/System_partition_and_boot_partition
+     * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/boot-and-system-volumes.html
+     * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/arc-boot-process.html
+     * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/efi-boot-process.html
+     * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-system-volume.html
+     * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-boot-volume.html
+     */
+    UNICODE_STRING SystemRootPath;
+
+    /* Path to the installation directory inside the ReactOS boot partition */
+    UNICODE_STRING DestinationPath;     /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
+    UNICODE_STRING DestinationArcPath;  /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
+    UNICODE_STRING DestinationRootPath;
+
+    LONG DestinationDiskNumber;
+    LONG DestinationPartitionNumber;
+    LONG MBRInstallType;
+
+    LONG FormatPartition;
+    LONG AutoPartition;
+
+    WCHAR LocaleID[9];
+    LANGID LanguageId;
+
+    ULONG RequiredPartitionDiskSpace;
+    WCHAR InstallationDirectory[MAX_PATH];
+} USETUP_DATA, *PUSETUP_DATA;
+
+// HACK!!
+extern BOOLEAN IsUnattendedSetup;
+
+
+/* FUNCTIONS ****************************************************************/
+
+VOID
+CheckUnattendedSetup(
+    IN OUT PUSETUP_DATA pSetupData);
+
+VOID
+InstallSetupInfFile(
+    IN OUT PUSETUP_DATA pSetupData);
+
+NTSTATUS
+GetSourcePaths(
+    OUT PUNICODE_STRING SourcePath,
+    OUT PUNICODE_STRING SourceRootPath,
+    OUT PUNICODE_STRING SourceRootDir);
+
+ERROR_NUMBER
+LoadSetupInf(
+    OUT HINF* SetupInf,
+    IN OUT PUSETUP_DATA pSetupData);
+
+
 /* EOF */
index c87a3fe..af5708f 100644 (file)
 #include <strsafe.h>
 
 
-/* GLOBALS ******************************************************************/
+/* GLOBALS & LOCALS *********************************************************/
 
 HANDLE ProcessHeap;
 
-static UNICODE_STRING SourceRootPath;
-static UNICODE_STRING SourceRootDir;
-static UNICODE_STRING SourcePath;
-
 BOOLEAN IsUnattendedSetup = FALSE;
-LONG UnattendDestinationDiskNumber;
-LONG UnattendDestinationPartitionNumber;
-LONG UnattendMBRInstallType = -1;
-LONG UnattendFormatPartition = 0;
-LONG AutoPartition = 0;
-WCHAR UnattendInstallationDirectory[MAX_PATH];
-PWCHAR SelectedLanguageId;
-WCHAR LocaleID[9];
-WCHAR DefaultLanguage[20];
-WCHAR DefaultKBLayout[20];
-static BOOLEAN RepairUpdateFlag = FALSE;
-static HANDLE hPnpThread = INVALID_HANDLE_VALUE;
-
-static PPARTLIST PartitionList = NULL;
-static PPARTENTRY TempPartition = NULL;
-static FORMATMACHINESTATE FormatState = Start;
-
-
-/* LOCALS *******************************************************************/
-
-static PFILE_SYSTEM_LIST FileSystemList = NULL;
+static USETUP_DATA USetupData;
 
 /*
  * NOTE: Technically only used for the COPYCONTEXT InstallPath member
@@ -78,29 +54,27 @@ static PFILE_SYSTEM_LIST FileSystemList = NULL;
  */
 static UNICODE_STRING InstallPath;
 
-/*
- * Path to the system partition, where the boot manager resides.
- * On x86 PCs, this is usually the active partition.
- * On ARC, (u)EFI, ... platforms, this is a dedicated partition.
- *
- * For more information, see:
- * https://en.wikipedia.org/wiki/System_partition_and_boot_partition
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/boot-and-system-volumes.html
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/arc-boot-process.html
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/efi-boot-process.html
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-system-volume.html
- * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/determining-boot-volume.html
- */
-static UNICODE_STRING SystemRootPath;
-
-/* Path to the installation directory inside the ReactOS boot partition */
-static UNICODE_STRING DestinationPath;
-static UNICODE_STRING DestinationArcPath;
-static UNICODE_STRING DestinationRootPath;
-
 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
 static WCHAR DestinationDriveLetter;
 
+
+/* OTHER Stuff *****/
+
+PWCHAR SelectedLanguageId;
+static WCHAR DefaultLanguage[20];   // Copy of string inside LanguageList
+static WCHAR DefaultKBLayout[20];   // Copy of string inside KeyboardList
+
+static BOOLEAN RepairUpdateFlag = FALSE;
+
+static HANDLE hPnpThread = NULL;
+
+static PPARTLIST PartitionList = NULL;
+static PPARTENTRY TempPartition = NULL;
+static PFILE_SYSTEM_LIST FileSystemList = NULL;
+static FORMATMACHINESTATE FormatState = Start;
+
+/*****************************************************/
+
 static HINF SetupInf;
 
 static HSPFILEQ SetupFileQueue = NULL;
@@ -114,9 +88,6 @@ static PGENERIC_LIST KeyboardList = NULL;
 static PGENERIC_LIST LayoutList   = NULL;
 static PGENERIC_LIST LanguageList = NULL;
 
-static LANGID LanguageId = 0;
-
-static ULONG RequiredPartitionDiskSpace = ~0;
 
 /* FUNCTIONS ****************************************************************/
 
@@ -273,7 +244,7 @@ PopupError(PCCH Text,
         if (Length > MaxLength)
             MaxLength = Length;
 
-        if (LastLine != FALSE)
+        if (LastLine)
             break;
 
         pnext = p + 1;
@@ -339,7 +310,7 @@ PopupError(PCCH Text,
                                          &Written);
         }
 
-        if (LastLine != FALSE)
+        if (LastLine)
             break;
 
         coPos.Y++;
@@ -429,178 +400,6 @@ ConfirmQuit(PINPUT_RECORD Ir)
 }
 
 
-static VOID
-CheckUnattendedSetup(VOID)
-{
-    WCHAR UnattendInfPath[MAX_PATH];
-    INFCONTEXT Context;
-    HINF UnattendInf;
-    UINT ErrorLine;
-    INT IntValue;
-    PWCHAR Value;
-
-    CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, SourcePath.Buffer, L"unattend.inf");
-
-    if (DoesFileExist(NULL, UnattendInfPath) == FALSE)
-    {
-        DPRINT("Does not exist: %S\n", UnattendInfPath);
-        return;
-    }
-
-    /* Load 'unattend.inf' from install media. */
-    UnattendInf = SetupOpenInfFileExW(UnattendInfPath,
-                                      NULL,
-                                      INF_STYLE_WIN4,
-                                      LanguageId,
-                                      &ErrorLine);
-
-    if (UnattendInf == INVALID_HANDLE_VALUE)
-    {
-        DPRINT("SetupOpenInfFileExW() failed\n");
-        return;
-    }
-
-    /* Open 'Unattend' section */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"Signature", &Context))
-    {
-        DPRINT("SetupFindFirstLineW() failed for section 'Unattend'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Get pointer 'Signature' key */
-    if (!INF_GetData(&Context, NULL, &Value))
-    {
-        DPRINT("INF_GetData() failed for key 'Signature'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Check 'Signature' string */
-    if (_wcsicmp(Value, L"$ReactOS$") != 0)
-    {
-        DPRINT("Signature not $ReactOS$\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Check if Unattend setup is enabled */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"UnattendSetupEnabled", &Context))
-    {
-        DPRINT("Can't find key 'UnattendSetupEnabled'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    if (!INF_GetData(&Context, NULL, &Value))
-    {
-        DPRINT("Can't read key 'UnattendSetupEnabled'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    if (_wcsicmp(Value, L"yes") != 0)
-    {
-        DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Search for 'DestinationDiskNumber' in the 'Unattend' section */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context))
-    {
-        DPRINT("SetupFindFirstLine() failed for key 'DestinationDiskNumber'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    if (!SetupGetIntField(&Context, 1, &IntValue))
-    {
-        DPRINT("SetupGetIntField() failed for key 'DestinationDiskNumber'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    UnattendDestinationDiskNumber = (LONG)IntValue;
-
-    /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context))
-    {
-        DPRINT("SetupFindFirstLine() failed for key 'DestinationPartitionNumber'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    if (!SetupGetIntField(&Context, 1, &IntValue))
-    {
-        DPRINT("SetupGetIntField() failed for key 'DestinationPartitionNumber'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    UnattendDestinationPartitionNumber = (LONG)IntValue;
-
-    /* Search for 'InstallationDirectory' in the 'Unattend' section */
-    if (!SetupFindFirstLineW(UnattendInf, L"Unattend", L"InstallationDirectory", &Context))
-    {
-        DPRINT("SetupFindFirstLine() failed for key 'InstallationDirectory'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    /* Get pointer 'InstallationDirectory' key */
-    if (!INF_GetData(&Context, NULL, &Value))
-    {
-        DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n");
-        SetupCloseInfFile(UnattendInf);
-        return;
-    }
-
-    wcscpy(UnattendInstallationDirectory, Value);
-
-    IsUnattendedSetup = TRUE;
-    DPRINT("Running unattended setup\n");
-
-    /* Search for 'MBRInstallType' in the 'Unattend' section */
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"MBRInstallType", &Context))
-    {
-        if (SetupGetIntField(&Context, 1, &IntValue))
-        {
-            UnattendMBRInstallType = IntValue;
-        }
-    }
-
-    /* Search for 'FormatPartition' in the 'Unattend' section */
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"FormatPartition", &Context))
-    {
-        if (SetupGetIntField(&Context, 1, &IntValue))
-        {
-            UnattendFormatPartition = IntValue;
-        }
-    }
-
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"AutoPartition", &Context))
-    {
-        if (SetupGetIntField(&Context, 1, &IntValue))
-        {
-            AutoPartition = IntValue;
-        }
-    }
-
-    /* search for LocaleID in the 'Unattend' section*/
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"LocaleID", &Context))
-    {
-        if (INF_GetData(&Context, NULL, &Value))
-        {
-            LONG Id = wcstol(Value, NULL, 16);
-            swprintf(LocaleID, L"%08lx", Id);
-       }
-    }
-
-    SetupCloseInfFile(UnattendInf);
-}
-
-
 static VOID
 UpdateKBLayout(VOID)
 {
@@ -645,7 +444,7 @@ UpdateKBLayout(VOID)
  *
  * SIDEEFFECTS
  *  Init SelectedLanguageId
- *  Init LanguageId
+ *  Init USetupData.LanguageId
  *
  * RETURNS
  *   Number of the next page.
@@ -669,6 +468,7 @@ LanguagePage(PINPUT_RECORD Ir)
     }
 
     /* Load the font */
+    USetupData.LanguageId = 0;
     SelectedLanguageId = DefaultLanguage;
     SetConsoleCodePage();
     UpdateKBLayout();
@@ -677,7 +477,7 @@ LanguagePage(PINPUT_RECORD Ir)
      * the language selection process altogether! */
     if (GenericListHasSingleEntry(LanguageList))
     {
-        LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+        USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
         return WELCOME_PAGE;
     }
 
@@ -723,7 +523,7 @@ LanguagePage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
             else
                 RedrawGenericList(&ListUi);
@@ -732,7 +532,7 @@ LanguagePage(PINPUT_RECORD Ir)
         {
             SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
 
-            LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+            USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
 
             if (wcscmp(SelectedLanguageId, DefaultLanguage))
             {
@@ -777,65 +577,6 @@ LanguagePage(PINPUT_RECORD Ir)
 }
 
 
-static NTSTATUS
-GetSourcePaths(
-    OUT PUNICODE_STRING SourcePath,
-    OUT PUNICODE_STRING SourceRootPath,
-    OUT PUNICODE_STRING SourceRootDir)
-{
-    NTSTATUS Status;
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"\\SystemRoot");
-    UNICODE_STRING SourceName;
-    WCHAR SourceBuffer[MAX_PATH] = L"";
-    HANDLE Handle;
-    ULONG Length;
-    PWCHAR Ptr;
-
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &LinkName,
-                               OBJ_CASE_INSENSITIVE,
-                               NULL,
-                               NULL);
-
-    Status = NtOpenSymbolicLinkObject(&Handle,
-                                      SYMBOLIC_LINK_ALL_ACCESS,
-                                      &ObjectAttributes);
-    if (!NT_SUCCESS(Status))
-        return Status;
-
-    RtlInitEmptyUnicodeString(&SourceName, SourceBuffer, sizeof(SourceBuffer));
-
-    Status = NtQuerySymbolicLinkObject(Handle,
-                                       &SourceName,
-                                       &Length);
-    NtClose(Handle);
-
-    if (!NT_SUCCESS(Status))
-        return Status;
-
-    RtlCreateUnicodeString(SourcePath,
-                           SourceName.Buffer);
-
-    /* Strip trailing directory */
-    Ptr = wcsrchr(SourceName.Buffer, OBJ_NAME_PATH_SEPARATOR);
-    if (Ptr)
-    {
-        RtlCreateUnicodeString(SourceRootDir, Ptr);
-        *Ptr = UNICODE_NULL;
-    }
-    else
-    {
-        RtlCreateUnicodeString(SourceRootDir, L"");
-    }
-
-    RtlCreateUnicodeString(SourceRootPath,
-                           SourceName.Buffer);
-
-    return STATUS_SUCCESS;
-}
-
-
 /*
  * Start page
  *
@@ -846,15 +587,15 @@ GetSourcePaths(
  *
  * SIDEEFFECTS
  *  Init Sdi
- *  Init SourcePath
- *  Init SourceRootPath
- *  Init SourceRootDir
+ *  Init USetupData.SourcePath
+ *  Init USetupData.SourceRootPath
+ *  Init USetupData.SourceRootDir
  *  Init SetupInf
- *  Init RequiredPartitionDiskSpace
+ *  Init USetupData.RequiredPartitionDiskSpace
  *  Init IsUnattendedSetup
  *  If unattended, init *List and sets the Codepage
  *  If unattended, init SelectedLanguageId
- *  If unattended, init LanguageId
+ *  If unattended, init USetupData.LanguageId
  *
  * RETURNS
  *   Number of the next page.
@@ -863,80 +604,33 @@ static PAGE_NUMBER
 SetupStartPage(PINPUT_RECORD Ir)
 {
     NTSTATUS Status;
-    WCHAR FileNameBuffer[MAX_PATH];
-    INFCONTEXT Context;
-    PWCHAR Value;
-    UINT ErrorLine;
+    ULONG Error;
     PGENERIC_LIST_ENTRY ListEntry;
-    INT IntValue;
 
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
     /* Get the source path and source root path */
-    Status = GetSourcePaths(&SourcePath,
-                            &SourceRootPath,
-                            &SourceRootDir);
+    Status = GetSourcePaths(&USetupData.SourcePath,
+                            &USetupData.SourceRootPath,
+                            &USetupData.SourceRootDir);
     if (!NT_SUCCESS(Status))
     {
         CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status);
         MUIDisplayError(ERROR_NO_SOURCE_DRIVE, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
-    DPRINT1("SourcePath: '%wZ'\n", &SourcePath);
-    DPRINT1("SourceRootPath: '%wZ'\n", &SourceRootPath);
-    DPRINT1("SourceRootDir: '%wZ'\n", &SourceRootDir);
+    DPRINT1("SourcePath: '%wZ'\n", &USetupData.SourcePath);
+    DPRINT1("SourceRootPath: '%wZ'\n", &USetupData.SourceRootPath);
+    DPRINT1("SourceRootDir: '%wZ'\n", &USetupData.SourceRootDir);
 
-    /* Load txtsetup.sif from install media. */
-    CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2, SourcePath.Buffer, L"txtsetup.sif");
-    SetupInf = SetupOpenInfFileExW(FileNameBuffer,
-                                   NULL,
-                                   INF_STYLE_WIN4,
-                                   LanguageId,
-                                   &ErrorLine);
-
-    if (SetupInf == INVALID_HANDLE_VALUE)
+    /* Load 'txtsetup.sif' from the installation media */
+    Error = LoadSetupInf(&SetupInf, &USetupData);
+    if (Error != ERROR_SUCCESS)
     {
-        MUIDisplayError(ERROR_LOAD_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
+        MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
 
-    /* Open 'Version' section */
-    if (!SetupFindFirstLineW(SetupInf, L"Version", L"Signature", &Context))
-    {
-        MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Get pointer 'Signature' key */
-    if (!INF_GetData(&Context, NULL, &Value))
-    {
-        MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Check 'Signature' string */
-    if (_wcsicmp(Value, L"$ReactOS$") != 0)
-    {
-        MUIDisplayError(ERROR_SIGNATURE_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Open 'DiskSpaceRequirements' section */
-    if (!SetupFindFirstLineW(SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context))
-    {
-        MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Get the 'FreeSysPartDiskSpace' value */
-    if (!SetupGetIntField(&Context, 1, &IntValue))
-    {
-        MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    RequiredPartitionDiskSpace = (ULONG)IntValue;
-
     /* Start the PnP thread */
     if (hPnpThread != NULL)
     {
@@ -944,7 +638,7 @@ SetupStartPage(PINPUT_RECORD Ir)
         hPnpThread = NULL;
     }
 
-    CheckUnattendedSetup();
+    CheckUnattendedSetup(&USetupData);
 
     if (IsUnattendedSetup)
     {
@@ -956,14 +650,14 @@ SetupStartPage(PINPUT_RECORD Ir)
         LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
 
         /* new part */
-        wcscpy(SelectedLanguageId, LocaleID);
-        LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+        wcscpy(SelectedLanguageId, USetupData.LocaleID);
+        USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
 
         /* first we hack LanguageList */
         ListEntry = GetFirstListEntry(LanguageList);
         while (ListEntry != NULL)
         {
-            if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
+            if (!wcsicmp(USetupData.LocaleID, GetListEntryUserData(ListEntry)))
             {
                 DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry));
                 SetCurrentListEntry(LanguageList, ListEntry);
@@ -977,7 +671,7 @@ SetupStartPage(PINPUT_RECORD Ir)
         ListEntry = GetFirstListEntry(LayoutList);
         while (ListEntry != NULL)
         {
-            if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
+            if (!wcsicmp(USetupData.LocaleID, GetListEntryUserData(ListEntry)))
             {
                 DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry));
                 SetCurrentListEntry(LayoutList, ListEntry);
@@ -1021,7 +715,7 @@ WelcomePage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1199,7 +893,7 @@ UpgradeRepairPage(PINPUT_RECORD Ir)
                 break;
             case VK_F3:     /* F3 */
             {
-                if (ConfirmQuit(Ir) == TRUE)
+                if (ConfirmQuit(Ir))
                     return QUIT_PAGE;
                 else
                     RedrawGenericList(&ListUi);
@@ -1286,7 +980,7 @@ InstallIntroPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1323,7 +1017,7 @@ ScsiControllerPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1355,7 +1049,7 @@ OemDriverPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
         {
-            if (ConfirmQuit(Ir) == TRUE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1492,7 +1186,7 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -1556,7 +1250,7 @@ HandleGenericList(PGENERIC_LIST_UI ListUi,
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
             else
                 RedrawGenericList(ListUi);
@@ -1704,10 +1398,10 @@ IsDiskSizeValid(PPARTENTRY PartEntry)
     size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
     size = (size + (512 * KB)) / MB;  /* in MBytes */
 
-    if (size < RequiredPartitionDiskSpace)
+    if (size < USetupData.RequiredPartitionDiskSpace)
     {
         /* Partition is too small so ask for another one */
-        DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, RequiredPartitionDiskSpace);
+        DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, USetupData.RequiredPartitionDiskSpace);
         return FALSE;
     }
     else
@@ -1786,9 +1480,11 @@ SelectPartitionPage(PINPUT_RECORD Ir)
 
     if (IsUnattendedSetup)
     {
-        if (!SelectPartition(PartitionList, UnattendDestinationDiskNumber, UnattendDestinationPartitionNumber))
+        if (!SelectPartition(PartitionList,
+                             USetupData.DestinationDiskNumber,
+                             USetupData.DestinationPartitionNumber))
         {
-            if (AutoPartition)
+            if (USetupData.AutoPartition)
             {
                 if (PartitionList->CurrentPartition->LogicalPartition)
                 {
@@ -1807,7 +1503,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
                 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
                 {
                     MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
-                                    RequiredPartitionDiskSpace);
+                                    USetupData.RequiredPartitionDiskSpace);
                     return SELECT_PARTITION_PAGE; /* let the user select another partition */
                 }
 
@@ -1822,7 +1518,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
             if (!IsDiskSizeValid(PartitionList->CurrentPartition))
             {
                 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
-                                RequiredPartitionDiskSpace);
+                                USetupData.RequiredPartitionDiskSpace);
                 return SELECT_PARTITION_PAGE; /* let the user select another partition */
             }
 
@@ -1872,7 +1568,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
             {
                 DestroyPartitionList(PartitionList);
                 PartitionList = NULL;
@@ -1916,7 +1612,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
             if (!IsDiskSizeValid(PartitionList->CurrentPartition))
             {
                 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
-                                RequiredPartitionDiskSpace);
+                                USetupData.RequiredPartitionDiskSpace);
                 return SELECT_PARTITION_PAGE; /* let the user select another partition */
             }
 
@@ -1952,7 +1648,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L')  /* L */
         {
-            if (PartitionList->CurrentPartition->LogicalPartition != FALSE)
+            if (PartitionList->CurrentPartition->LogicalPartition)
             {
                 Error = LogicalPartitionCreationChecks(PartitionList);
                 if (Error != NOT_AN_ERROR)
@@ -2276,14 +1972,14 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
         ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
                                   MaxSize, InputBuffer, &Quit, &Cancel);
 
-        if (Quit != FALSE)
+        if (Quit)
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
         }
-        else if (Cancel != FALSE)
+        else if (Cancel)
         {
             return SELECT_PARTITION_PAGE;
         }
@@ -2435,14 +2131,14 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
         ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
                                   MaxSize, InputBuffer, &Quit, &Cancel);
 
-        if (Quit != FALSE)
+        if (Quit)
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
         }
-        else if (Cancel != FALSE)
+        else if (Cancel)
         {
             return SELECT_PARTITION_PAGE;
         }
@@ -2593,14 +2289,14 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
         ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
                                   MaxSize, InputBuffer, &Quit, &Cancel);
 
-        if (Quit != FALSE)
+        if (Quit)
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
         }
-        else if (Cancel != FALSE)
+        else if (Cancel)
         {
             return SELECT_PARTITION_PAGE;
         }
@@ -2672,7 +2368,7 @@ ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) == TRUE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -2819,7 +2515,7 @@ DeletePartitionPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -2845,8 +2541,8 @@ DeletePartitionPage(PINPUT_RECORD Ir)
  *
  * Next pages:
  *  CheckFileSystemPage (At once if RepairUpdate is selected)
- *  CheckFileSystemPage (At once if Unattended and not UnattendFormatPartition)
- *  FormatPartitionPage (At once if Unattended and UnattendFormatPartition)
+ *  CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
+ *  FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
  *  SelectPartitionPage (If the user aborts)
  *  FormatPartitionPage (Default)
  *  QuitPage
@@ -3009,7 +2705,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                                        PartTypeString,
                                        ARRAYSIZE(PartTypeString));
 
-    if (PartEntry->AutoCreate != FALSE)
+    if (PartEntry->AutoCreate)
     {
         CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
 
@@ -3035,7 +2731,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
 
         PartEntry->AutoCreate = FALSE;
     }
-    else if (PartEntry->New != FALSE)
+    else if (PartEntry->New)
     {
         switch (FormatState)
         {
@@ -3114,7 +2810,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
 
     if (IsUnattendedSetup)
     {
-        if (UnattendFormatPartition)
+        if (USetupData.FormatPartition)
         {
             /*
              * We use whatever currently selected file system we have
@@ -3138,7 +2834,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -3184,7 +2880,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
  *
  * SIDEEFFECTS
  *  Sets PartitionList->CurrentPartition->FormatState
- *  Sets DestinationRootPath
+ *  Sets USetupData.DestinationRootPath
  *
  * RETURNS
  *   Number of the next page.
@@ -3230,7 +2926,7 @@ FormatPartitionPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -3443,31 +3139,31 @@ BuildInstallPaths(PWSTR InstallDir,
     RtlFreeUnicodeString(&InstallPath);
     RtlCreateUnicodeString(&InstallPath, InstallDir);
 
-    /* Create 'DestinationRootPath' string */
-    RtlFreeUnicodeString(&DestinationRootPath);
+    /* Create 'USetupData.DestinationRootPath' string */
+    RtlFreeUnicodeString(&USetupData.DestinationRootPath);
     StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
             L"\\Device\\Harddisk%lu\\Partition%lu\\",
             DiskEntry->DiskNumber,
             PartEntry->PartitionNumber);
-    RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
-    DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
+    RtlCreateUnicodeString(&USetupData.DestinationRootPath, PathBuffer);
+    DPRINT("DestinationRootPath: %wZ\n", &USetupData.DestinationRootPath);
 
 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
-    /* Create 'DestinationPath' string */
-    RtlFreeUnicodeString(&DestinationPath);
+    /* Create 'USetupData.DestinationPath' string */
+    RtlFreeUnicodeString(&USetupData.DestinationPath);
     CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                 DestinationRootPath.Buffer, InstallDir);
-    RtlCreateUnicodeString(&DestinationPath, PathBuffer);
+                 USetupData.DestinationRootPath.Buffer, InstallDir);
+    RtlCreateUnicodeString(&USetupData.DestinationPath, PathBuffer);
 
 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
-    /* Create 'DestinationArcPath' */
-    RtlFreeUnicodeString(&DestinationArcPath);
+    /* Create 'USetupData.DestinationArcPath' */
+    RtlFreeUnicodeString(&USetupData.DestinationArcPath);
     StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
             L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
             DiskEntry->BiosDiskNumber,
             PartEntry->PartitionNumber);
     ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallDir);
-    RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
+    RtlCreateUnicodeString(&USetupData.DestinationArcPath, PathBuffer);
 
     /* Initialize DestinationDriveLetter */
     DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
@@ -3489,7 +3185,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
 {
     PDISKENTRY DiskEntry;
     PPARTENTRY PartEntry;
-    WCHAR InstallDir[51];
+    WCHAR InstallDir[MAX_PATH];
     WCHAR c;
     ULONG Length, Pos;
 
@@ -3511,10 +3207,11 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
     DiskEntry = PartitionList->CurrentDisk;
     PartEntry = PartitionList->CurrentPartition;
 
-    if (IsUnattendedSetup)
-        wcscpy(InstallDir, UnattendInstallationDirectory);
-    else if (RepairUpdateFlag)
+    // if (IsUnattendedSetup)
+    if (RepairUpdateFlag)
         wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
+    else if (USetupData.InstallationDirectory[0])
+        wcscpy(InstallDir, USetupData.InstallationDirectory);
     else
         wcscpy(InstallDir, L"\\ReactOS");
 
@@ -3551,7 +3248,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
         {
             CONSOLE_SetCursorType(TRUE, FALSE);
 
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             CONSOLE_SetCursorType(TRUE, TRUE);
@@ -3737,8 +3434,8 @@ AddSectionToCopyQueueCab(HINF InfFile,
 
         if (!SetupQueueCopy(SetupFileQueue,
                             SourceCabinet,
-                            SourceRootPath.Buffer,
-                            SourceRootDir.Buffer,
+                            USetupData.SourceRootPath.Buffer,
+                            USetupData.SourceRootDir.Buffer,
                             FileKeyName,
                             DirKeyValue,
                             TargetFileName))
@@ -3846,7 +3543,7 @@ AddSectionToCopyQueue(HINF InfFile,
             DPRINT("InstallationPath: '%S'\n", DirKeyValue);
 
             StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
-                           SourceRootDir.Buffer);
+                           USetupData.SourceRootDir.Buffer);
 
             DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
         }
@@ -3866,14 +3563,14 @@ AddSectionToCopyQueue(HINF InfFile,
             DPRINT("RelativePath: '%S'\n", DirKeyValue);
 
             CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
-                         SourceRootDir.Buffer, DirKeyValue);
+                         USetupData.SourceRootDir.Buffer, DirKeyValue);
 
             DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
         }
 
         if (!SetupQueueCopy(SetupFileQueue,
                             SourceCabinet,
-                            SourceRootPath.Buffer,
+                            USetupData.SourceRootPath.Buffer,
                             CompleteOrigDirName,
                             FileKeyName,
                             DirKeyValue,
@@ -3904,7 +3601,7 @@ PrepareCopyPageInfFile(HINF InfFile,
     WCHAR PathBuffer[MAX_PATH];
 
     /* Add common files */
-    if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &DestinationPath, Ir))
+    if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &USetupData.DestinationPath, Ir))
         return FALSE;
 
     /* Add specific files depending of computer type */
@@ -3915,7 +3612,7 @@ PrepareCopyPageInfFile(HINF InfFile,
 
         if (AdditionalSectionName)
         {
-            if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &DestinationPath, Ir))
+            if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &USetupData.DestinationPath, Ir))
                 return FALSE;
         }
     }
@@ -3924,14 +3621,14 @@ PrepareCopyPageInfFile(HINF InfFile,
 
     /*
      * FIXME:
-     * Copying files to DestinationRootPath should be done from within
+     * Copying files to USetupData.DestinationRootPath should be done from within
      * the SystemPartitionFiles section.
      * At the moment we check whether we specify paths like '\foo' or '\\' for that.
-     * For installing to DestinationPath specify just '\' .
+     * For installing to USetupData.DestinationPath specify just '\' .
      */
 
     /* Get destination path */
-    StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), DestinationPath.Buffer);
+    StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), USetupData.DestinationPath.Buffer);
 
     DPRINT("FullPath(1): '%S'\n", PathBuffer);
 
@@ -3974,7 +3671,7 @@ PrepareCopyPageInfFile(HINF InfFile,
             DPRINT("InstallationPath: '%S'\n", DirKeyValue);
 
             StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
-                           DestinationPath.Buffer);
+                           USetupData.DestinationPath.Buffer);
 
             DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
         }
@@ -3984,7 +3681,7 @@ PrepareCopyPageInfFile(HINF InfFile,
             DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
 
             CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                         DestinationRootPath.Buffer, DirKeyValue);
+                         USetupData.DestinationRootPath.Buffer, DirKeyValue);
 
             DPRINT("AbsolutePath(2): '%S'\n", PathBuffer);
 
@@ -4003,7 +3700,7 @@ PrepareCopyPageInfFile(HINF InfFile,
             DPRINT("RelativePath: '%S'\n", DirKeyValue);
 
             CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                         DestinationPath.Buffer, DirKeyValue);
+                         USetupData.DestinationPath.Buffer, DirKeyValue);
 
             DPRINT("RelativePath(2): '%S'\n", PathBuffer);
 
@@ -4081,7 +3778,7 @@ PrepareCopyPage(PINPUT_RECORD Ir)
             break;
 
         CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                     SourcePath.Buffer, KeyValue);
+                     USetupData.SourcePath.Buffer, KeyValue);
 
         CabinetInitialize();
         CabinetSetEventHandlers(NULL, NULL, NULL);
@@ -4109,7 +3806,7 @@ PrepareCopyPage(PINPUT_RECORD Ir)
                                           InfFileSize,
                                           NULL,
                                           INF_STYLE_WIN4,
-                                          LanguageId,
+                                          USetupData.LanguageId,
                                           &ErrorLine);
 
         if (InfHandle == INVALID_HANDLE_VALUE)
@@ -4224,7 +3921,7 @@ FileCopyPage(PINPUT_RECORD Ir)
     MUIDisplayPage(FILE_COPY_PAGE);
 
     /* Create context for the copy process */
-    CopyContext.DestinationRootPath = DestinationRootPath.Buffer;
+    CopyContext.DestinationRootPath = USetupData.DestinationRootPath.Buffer;
     CopyContext.InstallPath = InstallPath.Buffer;
     CopyContext.TotalOperations = 0;
     CopyContext.CompletedOperations = 0;
@@ -4286,6 +3983,9 @@ FileCopyPage(PINPUT_RECORD Ir)
     DestroyProgressBar(CopyContext.MemoryBars[1]);
     DestroyProgressBar(CopyContext.MemoryBars[2]);
 
+    /* Create the $winnt$.inf file */
+    InstallSetupInfFile(&USetupData);
+
     /* Go display the next page */
     return REGISTRY_PAGE;
 }
@@ -4327,7 +4027,7 @@ RegistryPage(PINPUT_RECORD Ir)
         DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
 
         /* Verify the registry hives and check whether we need to update or repair any of them */
-        Status = VerifyRegistryHives(&DestinationPath, &ShouldRepairRegistry);
+        Status = VerifyRegistryHives(&USetupData.DestinationPath, &ShouldRepairRegistry);
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status);
@@ -4342,7 +4042,7 @@ DoUpdate:
     CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));
 
     /* Initialize the registry and setup the registry hives */
-    Status = RegInitializeRegistry(&DestinationPath);
+    Status = RegInitializeRegistry(&USetupData.DestinationPath);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("RegInitializeRegistry() failed\n");
@@ -4431,7 +4131,7 @@ DoUpdate:
 
         CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE), File);
 
-        if (!ImportRegistryFile(SourcePath.Buffer, File, Section, LanguageId, Delete))
+        if (!ImportRegistryFile(USetupData.SourcePath.Buffer, File, Section, USetupData.LanguageId, Delete))
         {
             DPRINT1("Importing %S failed\n", File);
             INF_FreeData(File);
@@ -4508,7 +4208,7 @@ Cleanup:
     // TODO: Unload all the registry stuff, perform cleanup,
     // and copy the created hive files into .sav files.
     //
-    RegCleanupRegistry(&DestinationPath);
+    RegCleanupRegistry(&USetupData.DestinationPath);
 
     /*
      * Check whether we were in update/repair mode but we were actually
@@ -4564,28 +4264,30 @@ BootLoaderPage(PINPUT_RECORD Ir)
 
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
-    RtlFreeUnicodeString(&SystemRootPath);
+    RtlFreeUnicodeString(&USetupData.SystemRootPath);
     StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
             L"\\Device\\Harddisk%lu\\Partition%lu\\",
             PartitionList->SystemPartition->DiskEntry->DiskNumber,
             PartitionList->SystemPartition->PartitionNumber);
-    RtlCreateUnicodeString(&SystemRootPath, PathBuffer);
-    DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath);
+    RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer);
+    DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath);
 
     PartitionType = PartitionList->SystemPartition->PartitionType;
 
+    /* For unattended setup, skip MBR installation or install on floppy if needed */
     if (IsUnattendedSetup)
     {
-        if (UnattendMBRInstallType == 0) /* skip MBR installation */
-        {
-            return SUCCESS_PAGE;
-        }
-        else if (UnattendMBRInstallType == 1) /* install on floppy */
+        if ((USetupData.MBRInstallType == 0) ||
+            (USetupData.MBRInstallType == 1))
         {
-            return BOOT_LOADER_FLOPPY_PAGE;
+            goto Quit;
         }
     }
 
+    /*
+     * We may install an MBR or VBR, but before that, check whether
+     * we need to actually install the VBR on floppy.
+     */
     if (PartitionType == PARTITION_ENTRY_UNUSED)
     {
         DPRINT("Error: system partition invalid (unused)\n");
@@ -4628,15 +4330,21 @@ BootLoaderPage(PINPUT_RECORD Ir)
         InstallOnFloppy = TRUE;
     }
 
-    if (InstallOnFloppy != FALSE)
+    /* We should install on floppy */
+    if (InstallOnFloppy)
     {
-        return BOOT_LOADER_FLOPPY_PAGE;
+        USetupData.MBRInstallType = 1;
+        goto Quit;
     }
 
-    /* Unattended install on hdd? */
-    if (IsUnattendedSetup && UnattendMBRInstallType == 2)
+    /* Is it an unattended install on hdd? */
+    if (IsUnattendedSetup)
     {
-        return BOOT_LOADER_HARDDISK_MBR_PAGE;
+        if ((USetupData.MBRInstallType == 2) ||
+            (USetupData.MBRInstallType == 3))
+        {
+            goto Quit;
+        }
     }
 
     MUIDisplayPage(BOOT_LOADER_PAGE);
@@ -4677,7 +4385,7 @@ BootLoaderPage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -4686,25 +4394,53 @@ BootLoaderPage(PINPUT_RECORD Ir)
         {
             if (Line == 12)
             {
-                return BOOT_LOADER_HARDDISK_MBR_PAGE;
+                /* Install on both MBR and VBR */
+                USetupData.MBRInstallType = 2;
+                break;
             }
             else if (Line == 13)
             {
-                return BOOT_LOADER_HARDDISK_VBR_PAGE;
+                /* Install on VBR only */
+                USetupData.MBRInstallType = 3;
+                break;
             }
             else if (Line == 14)
             {
-                return BOOT_LOADER_FLOPPY_PAGE;
+                /* Install on floppy */
+                USetupData.MBRInstallType = 1;
+                break;
             }
             else if (Line == 15)
             {
-                return SUCCESS_PAGE;
+                /* Skip MBR installation */
+                USetupData.MBRInstallType = 0;
+                break;
             }
 
             return BOOT_LOADER_PAGE;
         }
     }
 
+Quit:
+    switch (USetupData.MBRInstallType)
+    {
+        /* Skip MBR installation */
+        case 0:
+            return SUCCESS_PAGE;
+
+        /* Install on floppy */
+        case 1:
+            return BOOT_LOADER_FLOPPY_PAGE;
+
+        /* Install on both MBR and VBR */
+        case 2:
+            return BOOT_LOADER_HARDDISK_MBR_PAGE;
+
+        /* Install on VBR only */
+        case 3:
+            return BOOT_LOADER_HARDDISK_VBR_PAGE;
+    }
+
     return BOOT_LOADER_PAGE;
 }
 
@@ -4738,7 +4474,7 @@ BootLoaderFloppyPage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))  /* F3 */
         {
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             break;
@@ -4751,7 +4487,7 @@ BootLoaderFloppyPage(PINPUT_RECORD Ir)
                 return BOOT_LOADER_FLOPPY_PAGE;
             }
 
-            Status = InstallFatBootcodeToFloppy(&SourceRootPath, &DestinationArcPath);
+            Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath, &USetupData.DestinationArcPath);
             if (!NT_SUCCESS(Status))
             {
                 /* Print error message */
@@ -4784,9 +4520,9 @@ BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
 {
     NTSTATUS Status;
 
-    Status = InstallVBRToPartition(&SystemRootPath,
-                                   &SourceRootPath,
-                                   &DestinationArcPath,
+    Status = InstallVBRToPartition(&USetupData.SystemRootPath,
+                                   &USetupData.SourceRootPath,
+                                   &USetupData.DestinationArcPath,
                                    PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
@@ -4821,9 +4557,9 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
     WCHAR DstPath[MAX_PATH];
 
     /* Step 1: Write the VBR */
-    Status = InstallVBRToPartition(&SystemRootPath,
-                                   &SourceRootPath,
-                                   &DestinationArcPath,
+    Status = InstallVBRToPartition(&USetupData.SystemRootPath,
+                                   &USetupData.SourceRootPath,
+                                   &USetupData.DestinationArcPath,
                                    PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
@@ -4836,12 +4572,12 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
             L"\\Device\\Harddisk%d\\Partition0",
             PartitionList->SystemPartition->DiskEntry->DiskNumber);
 
-    CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2, SourceRootPath.Buffer, L"\\loader\\dosmbr.bin");
+    CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2, USetupData.SourceRootPath.Buffer, L"\\loader\\dosmbr.bin");
 
     if (IsThereAValidBootSector(DestinationDevicePathBuffer))
     {
         /* Save current MBR */
-        CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath.Buffer, L"mbr.old");
+        CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, USetupData.SystemRootPath.Buffer, L"mbr.old");
 
         DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
         Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
@@ -5236,14 +4972,14 @@ RunUSetup(VOID)
     }
 
     /* Initialize global unicode strings */
-    RtlInitUnicodeString(&SourcePath, NULL);
-    RtlInitUnicodeString(&SourceRootPath, NULL);
-    RtlInitUnicodeString(&SourceRootDir, NULL);
+    RtlInitUnicodeString(&USetupData.SourcePath, NULL);
+    RtlInitUnicodeString(&USetupData.SourceRootPath, NULL);
+    RtlInitUnicodeString(&USetupData.SourceRootDir, NULL);
     RtlInitUnicodeString(&InstallPath, NULL);
-    RtlInitUnicodeString(&DestinationPath, NULL);
-    RtlInitUnicodeString(&DestinationArcPath, NULL);
-    RtlInitUnicodeString(&DestinationRootPath, NULL);
-    RtlInitUnicodeString(&SystemRootPath, NULL);
+    RtlInitUnicodeString(&USetupData.DestinationPath, NULL);
+    RtlInitUnicodeString(&USetupData.DestinationArcPath, NULL);
+    RtlInitUnicodeString(&USetupData.DestinationRootPath, NULL);
+    RtlInitUnicodeString(&USetupData.SystemRootPath, NULL);
 
     /* Hide the cursor */
     CONSOLE_SetCursorType(TRUE, FALSE);
@@ -5408,6 +5144,8 @@ RunUSetup(VOID)
         }
     }
 
+    SetupCloseInfFile(SetupInf);
+
     if (Page == RECOVERY_PAGE)
         RecoveryConsole();