[USETUP] Improvements for the File-queues code.
[reactos.git] / base / setup / usetup / usetup.c
index 234bfa4..929a4dc 100644 (file)
@@ -21,8 +21,7 @@
  * PROJECT:         ReactOS text-mode setup
  * FILE:            base/setup/usetup/usetup.c
  * PURPOSE:         Text-mode setup
- * PROGRAMMER:      Eric Kohl
- *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
  *                  HervĂ© Poussineau (hpoussin@reactos.org)
  */
 
 #include "chkdsk.h"
 #include "cmdcons.h"
 #include "format.h"
-#include "drivesup.h"
-#include "settings.h"
 
 #define NDEBUG
 #include <debug.h>
 
 
-/* GLOBALS ******************************************************************/
+/* GLOBALS & LOCALS *********************************************************/
 
 HANDLE ProcessHeap;
-UNICODE_STRING SourceRootPath;
-UNICODE_STRING SourceRootDir;
-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];
-BOOLEAN RepairUpdateFlag = FALSE;
-HANDLE hPnpThread = INVALID_HANDLE_VALUE;
-PPARTLIST PartitionList = NULL;
-
-/* LOCALS *******************************************************************/
 
-static PFILE_SYSTEM_LIST FileSystemList = NULL;
+static USETUP_DATA USetupData;
 
-static UNICODE_STRING InstallPath;
+// FIXME: Is it really useful?? Just used for SetDefaultPagefile...
+static WCHAR DestinationDriveLetter;
 
-/*
- * 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 install directory inside the ReactOS boot partition */
-static UNICODE_STRING DestinationPath;
-static UNICODE_STRING DestinationArcPath;
-static UNICODE_STRING DestinationRootPath;
+/* OTHER Stuff *****/
 
-static WCHAR DestinationDriveLetter;
+PCWSTR 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 HINF SetupInf;
+static PPARTLIST PartitionList = NULL;
+static PPARTENTRY TempPartition = NULL;
+static PFILE_SYSTEM_LIST FileSystemList = NULL;
+static FORMATMACHINESTATE FormatState = Start;
+
+/*****************************************************/
 
-static HSPFILEQ SetupFileQueue = NULL;
+static PNTOS_INSTALLATION CurrentInstallation = NULL;
+static PGENERIC_LIST NtOsInstallsList = NULL;
 
-static PGENERIC_LIST ComputerList = NULL;
-static PGENERIC_LIST DisplayList = NULL;
-static PGENERIC_LIST KeyboardList = NULL;
-static PGENERIC_LIST LayoutList = NULL;
-static PGENERIC_LIST LanguageList = NULL;
 
-static LANGID LanguageId = 0;
+// HACK: Temporary compatibility code.
+#if 1
+    #define SetupQueueCopy SetupQueueCopyWithCab
+
+    static CABINET_CONTEXT CabinetContext;
+    #define CabinetInitialize() (CabinetInitialize(&CabinetContext))
+    #define CabinetSetEventHandlers(a,b,c) (CabinetSetEventHandlers(&CabinetContext,(a),(b),(c)))
+    #define CabinetSetCabinetName(a) (CabinetSetCabinetName(&CabinetContext,(a)))
+    #define CabinetOpen() (CabinetOpen(&CabinetContext))
+    #define CabinetGetCabinetName() (CabinetGetCabinetName(&CabinetContext))
+    #define CabinetGetCabinetReservedArea(a) (CabinetGetCabinetReservedArea(&CabinetContext,(a)))
+    #define CabinetCleanup() (CabinetCleanup(&CabinetContext))
+#endif
 
-static ULONG RequiredPartitionDiskSpace = ~0;
 
 /* FUNCTIONS ****************************************************************/
 
@@ -133,7 +114,7 @@ DrawBox(IN SHORT xLeft,
     COORD coPos;
     DWORD Written;
 
-    /* draw upper left corner */
+    /* Draw upper left corner */
     coPos.X = xLeft;
     coPos.Y = yTop;
     FillConsoleOutputCharacterA(StdOutput,
@@ -142,7 +123,7 @@ DrawBox(IN SHORT xLeft,
                                 coPos,
                                 &Written);
 
-    /* draw upper edge */
+    /* Draw upper edge */
     coPos.X = xLeft + 1;
     coPos.Y = yTop;
     FillConsoleOutputCharacterA(StdOutput,
@@ -151,7 +132,7 @@ DrawBox(IN SHORT xLeft,
                                 coPos,
                                 &Written);
 
-    /* draw upper right corner */
+    /* Draw upper right corner */
     coPos.X = xLeft + Width - 1;
     coPos.Y = yTop;
     FillConsoleOutputCharacterA(StdOutput,
@@ -185,7 +166,7 @@ DrawBox(IN SHORT xLeft,
                                     &Written);
     }
 
-    /* draw lower left corner */
+    /* Draw lower left corner */
     coPos.X = xLeft;
     coPos.Y = yTop + Height - 1;
     FillConsoleOutputCharacterA(StdOutput,
@@ -194,7 +175,7 @@ DrawBox(IN SHORT xLeft,
                                 coPos,
                                 &Written);
 
-    /* draw lower edge */
+    /* Draw lower edge */
     coPos.X = xLeft + 1;
     coPos.Y = yTop + Height - 1;
     FillConsoleOutputCharacterA(StdOutput,
@@ -203,7 +184,7 @@ DrawBox(IN SHORT xLeft,
                                 coPos,
                                 &Written);
 
-    /* draw lower right corner */
+    /* Draw lower right corner */
     coPos.X = xLeft + Width - 1;
     coPos.Y = yTop + Height - 1;
     FillConsoleOutputCharacterA(StdOutput,
@@ -258,7 +239,7 @@ PopupError(PCCH Text,
         if (Length > MaxLength)
             MaxLength = Length;
 
-        if (LastLine != FALSE)
+        if (LastLine)
             break;
 
         pnext = p + 1;
@@ -324,7 +305,7 @@ PopupError(PCCH Text,
                                          &Written);
         }
 
-        if (LastLine != FALSE)
+        if (LastLine)
             break;
 
         coPos.Y++;
@@ -414,213 +395,77 @@ ConfirmQuit(PINPUT_RECORD Ir)
 }
 
 
-VOID
-CheckUnattendedSetup(VOID)
+static VOID
+UpdateKBLayout(VOID)
 {
-    WCHAR UnattendInfPath[MAX_PATH];
-    INFCONTEXT Context;
-    HINF UnattendInf;
-    UINT ErrorLine;
-    INT IntValue;
-    PWCHAR Value;
-
-    if (DoesFileExist(NULL, SourcePath.Buffer, L"unattend.inf") == FALSE)
-    {
-        DPRINT("Does not exist: %S\\%S\n", SourcePath.Buffer, L"unattend.inf");
-        return;
-    }
-
-    wcscpy(UnattendInfPath, SourcePath.Buffer);
-    wcscat(UnattendInfPath, L"\\unattend.inf");
-
-    /* Load 'unattend.inf' from install media. */
-    UnattendInf = SetupOpenInfFileW(UnattendInfPath,
-                                    NULL,
-                                    INF_STYLE_WIN4,
-                                    LanguageId,
-                                    &ErrorLine);
-
-    if (UnattendInf == INVALID_HANDLE_VALUE)
-    {
-        DPRINT("SetupOpenInfFileW() 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 = 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;
+    PGENERIC_LIST_ENTRY ListEntry;
+    PCWSTR pszNewLayout;
 
-    /* Search for 'MBRInstallType' in the 'Unattend' section */
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"MBRInstallType", &Context))
-    {
-        if (SetupGetIntField(&Context, 1, &IntValue))
-        {
-            UnattendMBRInstallType = IntValue;
-        }
-    }
+    pszNewLayout = MUIDefaultKeyboardLayout(SelectedLanguageId);
 
-    /* Search for 'FormatPartition' in the 'Unattend' section */
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"FormatPartition", &Context))
+    if (USetupData.LayoutList == NULL)
     {
-        if (SetupGetIntField(&Context, 1, &IntValue))
+        USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
+        if (USetupData.LayoutList == NULL)
         {
-            UnattendFormatPartition = IntValue;
+            /* FIXME: Handle error! */
+            return;
         }
     }
 
-    if (SetupFindFirstLineW(UnattendInf, L"Unattend", L"AutoPartition", &Context))
+    /* Search for default layout (if provided) */
+    if (pszNewLayout != NULL)
     {
-        if (SetupGetIntField(&Context, 1, &IntValue))
+        for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
+             ListEntry = GetNextListEntry(ListEntry))
         {
-            AutoPartition = IntValue;
+            if (!wcscmp(pszNewLayout, ((PGENENTRY)GetListEntryData(ListEntry))->Id))
+            {
+                SetCurrentListEntry(USetupData.LayoutList, ListEntry);
+                break;
+            }
         }
     }
-
-    /* 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);
-
-    DPRINT("Running unattended setup\n");
 }
 
 
-VOID
-UpdateKBLayout(VOID)
+static NTSTATUS
+NTAPI
+GetSettingDescription(
+    IN PGENERIC_LIST_ENTRY Entry,
+    OUT PSTR Buffer,
+    IN SIZE_T cchBufferSize)
 {
-    PGENERIC_LIST_ENTRY ListEntry;
-    LPCWSTR pszNewLayout;
+    return RtlStringCchPrintfA(Buffer, cchBufferSize, "%S",
+                               ((PGENENTRY)GetListEntryData(Entry))->Value);
+}
 
-    pszNewLayout = MUIDefaultKeyboardLayout();
+static NTSTATUS
+NTAPI
+GetNTOSInstallationName(
+    IN PGENERIC_LIST_ENTRY Entry,
+    OUT PSTR Buffer,
+    IN SIZE_T cchBufferSize)
+{
+    PNTOS_INSTALLATION NtOsInstall = (PNTOS_INSTALLATION)GetListEntryData(Entry);
+    PPARTENTRY PartEntry = NtOsInstall->PartEntry;
 
-    if (LayoutList == NULL)
+    if (PartEntry && PartEntry->DriveLetter)
     {
-        LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
-        if (LayoutList == NULL)
-        {
-            /* FIXME: Handle error! */
-            return;
-        }
+        /* We have retrieved a partition that is mounted */
+        return RtlStringCchPrintfA(Buffer, cchBufferSize,
+                                   "%c:%S  \"%S\"",
+                                   PartEntry->DriveLetter,
+                                   NtOsInstall->PathComponent,
+                                   NtOsInstall->InstallationName);
     }
-
-    ListEntry = GetFirstListEntry(LayoutList);
-
-    /* Search for default layout (if provided) */
-    if (pszNewLayout != NULL)
+    else
     {
-        while (ListEntry != NULL)
-        {
-            if (!wcscmp(pszNewLayout, GetListEntryUserData(ListEntry)))
-            {
-                SetCurrentListEntry(LayoutList, ListEntry);
-                break;
-            }
-
-            ListEntry = GetNextListEntry(ListEntry);
-        }
+        /* We failed somewhere, just show the NT path */
+        return RtlStringCchPrintfA(Buffer, cchBufferSize,
+                                   "%wZ  \"%S\"",
+                                   &NtOsInstall->SystemNtPath,
+                                   NtOsInstall->InstallationName);
     }
 }
 
@@ -628,11 +473,11 @@ UpdateKBLayout(VOID)
 /*
  * Displays the LanguagePage.
  *
- * Next pages: IntroPage, QuitPage
+ * Next pages: WelcomePage, QuitPage
  *
  * SIDEEFFECTS
  *  Init SelectedLanguageId
- *  Init LanguageId
+ *  Init USetupData.LanguageId
  *
  * RETURNS
  *   Number of the next page.
@@ -640,41 +485,45 @@ UpdateKBLayout(VOID)
 static PAGE_NUMBER
 LanguagePage(PINPUT_RECORD Ir)
 {
-    PWCHAR NewLanguageId;
+    GENERIC_LIST_UI ListUi;
+    PCWSTR NewLanguageId;
     BOOL RefreshPage = FALSE;
 
     /* Initialize the computer settings list */
-    if (LanguageList == NULL)
+    if (USetupData.LanguageList == NULL)
     {
-        LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
-
-        if (LanguageList == NULL)
+        USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
+        if (USetupData.LanguageList == NULL)
         {
            PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
-           return INTRO_PAGE;
+           return WELCOME_PAGE;
         }
     }
 
-    /* Load the font */
     SelectedLanguageId = DefaultLanguage;
+    USetupData.LanguageId = 0;
+
+    /* Load the font */
     SetConsoleCodePage();
     UpdateKBLayout();
 
-    /* If there's just a single language in the list skip
-     * the language selection process altogether! */
-    if (GenericListHasSingleEntry(LanguageList))
+    /*
+     * If there is no language or just a single one in the list,
+     * skip the language selection process altogether.
+     */
+    if (GetNumberOfListEntries(USetupData.LanguageList) <= 1)
     {
-        LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
-        return INTRO_PAGE;
+        USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+        return WELCOME_PAGE;
     }
 
-    DrawGenericList(LanguageList,
-                    2,
-                    18,
+    InitGenericListUi(&ListUi, USetupData.LanguageList, GetSettingDescription);
+    DrawGenericList(&ListUi,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
-    ScrollToPositionGenericList(LanguageList, GetDefaultLanguageIndex());
+    ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex());
 
     MUIDisplayPage(LANGUAGE_PAGE);
 
@@ -685,40 +534,43 @@ LanguagePage(PINPUT_RECORD Ir)
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN))  /* DOWN */
         {
-            ScrollDownGenericList(LanguageList);
+            ScrollDownGenericList(&ListUi);
             RefreshPage = TRUE;
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP))  /* UP */
         {
-            ScrollUpGenericList(LanguageList);
+            ScrollUpGenericList(&ListUi);
             RefreshPage = TRUE;
         }
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT))  /* PAGE DOWN */
         {
-            ScrollPageDownGenericList(LanguageList);
+            ScrollPageDownGenericList(&ListUi);
             RefreshPage = TRUE;
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR))  /* PAGE UP */
         {
-            ScrollPageUpGenericList(LanguageList);
+            ScrollPageUpGenericList(&ListUi);
             RefreshPage = TRUE;
         }
         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(LanguageList);
+                RedrawGenericList(&ListUi);
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)  /* ENTER */
         {
-            SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
+            ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
 
-            LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+            SelectedLanguageId =
+                ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
+
+            USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
 
             if (wcscmp(SelectedLanguageId, DefaultLanguage))
             {
@@ -728,20 +580,23 @@ LanguagePage(PINPUT_RECORD Ir)
             /* Load the font */
             SetConsoleCodePage();
 
-            return INTRO_PAGE;
+            return WELCOME_PAGE;
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
         {
             /* a-z */
-            GenericListKeyPress(LanguageList, Ir->Event.KeyEvent.uChar.AsciiChar);
+            GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
             RefreshPage = TRUE;
         }
 
         if (RefreshPage)
         {
-            NewLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
+            ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
+
+            NewLanguageId =
+                ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
 
-            if (SelectedLanguageId != NewLanguageId)
+            if (wcscmp(SelectedLanguageId, NewLanguageId))
             {
                 /* Clear the language page */
                 MUIClearPage(LANGUAGE_PAGE);
@@ -759,7 +614,7 @@ LanguagePage(PINPUT_RECORD Ir)
         }
     }
 
-    return INTRO_PAGE;
+    return WELCOME_PAGE;
 }
 
 
@@ -773,15 +628,15 @@ LanguagePage(PINPUT_RECORD Ir)
  *
  * SIDEEFFECTS
  *  Init Sdi
- *  Init SourcePath
- *  Init SourceRootPath
- *  Init SourceRootDir
- *  Init SetupInf
- *  Init RequiredPartitionDiskSpace
+ *  Init USetupData.SourcePath
+ *  Init USetupData.SourceRootPath
+ *  Init USetupData.SourceRootDir
+ *  Init USetupData.SetupInf
+ *  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.
@@ -789,163 +644,71 @@ LanguagePage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 SetupStartPage(PINPUT_RECORD Ir)
 {
-    //SYSTEM_DEVICE_INFORMATION Sdi;
-    NTSTATUS Status;
-    WCHAR FileNameBuffer[MAX_PATH];
-    INFCONTEXT Context;
-    PWCHAR Value;
-    UINT ErrorLine;
-    //ULONG ReturnSize;
+    ULONG Error;
     PGENERIC_LIST_ENTRY ListEntry;
-    INT IntValue;
+    PCWSTR LocaleId;
 
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
-#if 0
-    /* Check whether a harddisk is available */
-    Status = NtQuerySystemInformation(SystemDeviceInformation,
-                                      &Sdi,
-                                      sizeof(SYSTEM_DEVICE_INFORMATION),
-                                      &ReturnSize);
-
-    if (!NT_SUCCESS(Status))
-    {
-        CONSOLE_PrintTextXY(6, 15, "NtQuerySystemInformation() failed (Status 0x%08lx)", Status);
-        MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    if (Sdi.NumberOfDisks == 0)
-    {
-        MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-#endif
-
-    /* Get the source path and source root path */
-    Status = GetSourcePaths(&SourcePath,
-                            &SourceRootPath,
-                            &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;
-    }
-#if 0
-    else
-    {
-        CONSOLE_PrintTextXY(6, 15, "SourcePath: '%wZ'", &SourcePath);
-        CONSOLE_PrintTextXY(6, 16, "SourceRootPath: '%wZ'", &SourceRootPath);
-        CONSOLE_PrintTextXY(6, 17, "SourceRootDir: '%wZ'", &SourceRootDir);
-    }
-#endif
-
-    /* Load txtsetup.sif from install media. */
-    wcscpy(FileNameBuffer, SourcePath.Buffer);
-    wcscat(FileNameBuffer, L"\\txtsetup.sif");
-
-    SetupInf = SetupOpenInfFileW(FileNameBuffer,
-                                 NULL,
-                                 INF_STYLE_WIN4,
-                                 LanguageId,
-                                 &ErrorLine);
-
-    if (SetupInf == INVALID_HANDLE_VALUE)
-    {
-        MUIDisplayError(ERROR_LOAD_TXTSETUPSIF, 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))
+    /* Initialize Setup, phase 1 */
+    Error = InitializeSetup(&USetupData, 1);
+    if (Error != ERROR_SUCCESS)
     {
-        MUIDisplayError(ERROR_CORRUPT_TXTSETUPSIF, Ir, POPUP_WAIT_ENTER);
+        MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
 
-    RequiredPartitionDiskSpace = (ULONG)IntValue;
-
-    /* Start PnP thread */
-    if (hPnpThread != INVALID_HANDLE_VALUE)
+    /* Start the PnP thread */
+    if (hPnpThread != NULL)
     {
         NtResumeThread(hPnpThread, NULL);
-        hPnpThread = INVALID_HANDLE_VALUE;
+        hPnpThread = NULL;
     }
 
-    CheckUnattendedSetup();
+    CheckUnattendedSetup(&USetupData);
 
     if (IsUnattendedSetup)
     {
-        //TODO
-        //read options from inf
-        ComputerList = CreateComputerTypeList(SetupInf);
-        DisplayList = CreateDisplayDriverList(SetupInf);
-        KeyboardList = CreateKeyboardDriverList(SetupInf);
-        LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
-        LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
+        // TODO: Read options from inf
+        /* Load the hardware, language and keyboard layout lists */
+
+        USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
+        USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
+        USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
+
+        USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
 
         /* new part */
-        wcscpy(SelectedLanguageId,LocaleID);
-        LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
+        SelectedLanguageId = DefaultLanguage;
+        wcscpy(DefaultLanguage, USetupData.LocaleID);
+        USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
 
-        /* first we hack LanguageList */
-        ListEntry = GetFirstListEntry(LanguageList);
+        USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
 
-        while (ListEntry != NULL)
+        /* first we hack LanguageList */
+        for (ListEntry = GetFirstListEntry(USetupData.LanguageList); ListEntry;
+             ListEntry = GetNextListEntry(ListEntry))
         {
-            if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
+            LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
+            if (!wcsicmp(USetupData.LocaleID, LocaleId))
             {
-                DPRINT("found %S in LanguageList\n",GetListEntryUserData(ListEntry));
-                SetCurrentListEntry(LanguageList, ListEntry);
+                DPRINT("found %S in LanguageList\n", LocaleId);
+                SetCurrentListEntry(USetupData.LanguageList, ListEntry);
                 break;
             }
-
-            ListEntry = GetNextListEntry(ListEntry);
         }
 
         /* now LayoutList */
-        ListEntry = GetFirstListEntry(LayoutList);
-
-        while (ListEntry != NULL)
+        for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
+             ListEntry = GetNextListEntry(ListEntry))
         {
-            if (!wcsicmp(LocaleID, GetListEntryUserData(ListEntry)))
+            LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
+            if (!wcsicmp(USetupData.LocaleID, LocaleId))
             {
-                DPRINT("found %S in LayoutList\n",GetListEntryUserData(ListEntry));
-                SetCurrentListEntry(LayoutList, ListEntry);
+                DPRINT("found %S in LayoutList\n", LocaleId);
+                SetCurrentListEntry(USetupData.LayoutList, ListEntry);
                 break;
             }
-
-            ListEntry = GetNextListEntry(ListEntry);
         }
 
         SetConsoleCodePage();
@@ -958,11 +721,12 @@ SetupStartPage(PINPUT_RECORD Ir)
 
 
 /*
- * Displays the IntroPage.
+ * Displays the WelcomePage.
  *
  * Next pages:
  *  InstallIntroPage (default)
  *  RepairIntroPage
+ *  RecoveryPage
  *  LicensePage
  *  QuitPage
  *
@@ -970,9 +734,9 @@ SetupStartPage(PINPUT_RECORD Ir)
  *   Number of the next page.
  */
 static PAGE_NUMBER
-IntroPage(PINPUT_RECORD Ir)
+WelcomePage(PINPUT_RECORD Ir)
 {
-    MUIDisplayPage(START_PAGE);
+    MUIDisplayPage(WELCOME_PAGE);
 
     while (TRUE)
     {
@@ -981,7 +745,7 @@ IntroPage(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;
@@ -992,15 +756,15 @@ IntroPage(PINPUT_RECORD Ir)
         }
         else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
         {
-            return REPAIR_INTRO_PAGE;
+            return RECOVERY_PAGE; // REPAIR_INTRO_PAGE;
         }
-        else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* R */
+        else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */
         {
             return LICENSE_PAGE;
         }
     }
 
-    return INTRO_PAGE;
+    return WELCOME_PAGE;
 }
 
 
@@ -1008,7 +772,7 @@ IntroPage(PINPUT_RECORD Ir)
  * Displays the License page.
  *
  * Next page:
- *  IntroPage (default)
+ *  WelcomePage (default)
  *
  * RETURNS
  *   Number of the next page.
@@ -1024,7 +788,7 @@ LicensePage(PINPUT_RECORD Ir)
 
         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)  /* ENTER */
         {
-            return INTRO_PAGE;
+            return WELCOME_PAGE;
         }
     }
 
@@ -1069,7 +833,7 @@ RepairIntroPage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE))  /* ESC */
         {
-            return INTRO_PAGE;
+            return WELCOME_PAGE;
         }
     }
 
@@ -1077,78 +841,220 @@ RepairIntroPage(PINPUT_RECORD Ir)
 }
 
 /*
- * Displays the InstallIntroPage.
+ * Displays the UpgradeRepairPage.
  *
  * Next pages:
- *  DeviceSettingsPage  (At once if repair or update is selected)
- *  SelectPartitionPage (At once if unattended setup)
- *  DeviceSettingsPage  (default)
- *  QuitPage
+ *  RebootPage (default)
+ *  InstallIntroPage
+ *  RecoveryPage
+ *  WelcomePage
  *
  * RETURNS
  *   Number of the next page.
  */
 static PAGE_NUMBER
-InstallIntroPage(PINPUT_RECORD Ir)
+UpgradeRepairPage(PINPUT_RECORD Ir)
 {
-    MUIDisplayPage(INSTALL_INTRO_PAGE);
+    GENERIC_LIST_UI ListUi;
 
-    if (RepairUpdateFlag)
+/*** HACK!! ***/
+    if (PartitionList == NULL)
     {
-        //return SELECT_PARTITION_PAGE;
-        return DEVICE_SETTINGS_PAGE;
+        PartitionList = CreatePartitionList();
+        if (PartitionList == NULL)
+        {
+            /* FIXME: show an error dialog */
+            MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
+            return QUIT_PAGE;
+        }
+        else if (IsListEmpty(&PartitionList->DiskListHead))
+        {
+            MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
+            return QUIT_PAGE;
+        }
+
+        TempPartition = NULL;
+        FormatState = Start;
     }
+/**************/
 
-    if (IsUnattendedSetup)
+    NtOsInstallsList = CreateNTOSInstallationsList(PartitionList);
+    if (!NtOsInstallsList)
+        DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
+
+    /*
+     * If there is no available installation (or just a single one??) that can
+     * be updated in the list, just continue with the regular installation.
+     */
+    if (!NtOsInstallsList || GetNumberOfListEntries(NtOsInstallsList) == 0)
     {
-        return SELECT_PARTITION_PAGE;
+        RepairUpdateFlag = FALSE;
+
+        // return INSTALL_INTRO_PAGE;
+        return DEVICE_SETTINGS_PAGE;
+        // return SCSI_CONTROLLER_PAGE;
     }
 
+    MUIDisplayPage(UPGRADE_REPAIR_PAGE);
+
+    InitGenericListUi(&ListUi, NtOsInstallsList, GetNTOSInstallationName);
+    DrawGenericList(&ListUi,
+                    2, 23,
+                    xScreen - 3,
+                    yScreen - 3);
+
+    // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
     while (TRUE)
     {
         CONSOLE_ConInKey(Ir);
 
-        if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-            (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+        if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00)
         {
-            if (ConfirmQuit(Ir) != FALSE)
-                return QUIT_PAGE;
+            switch (Ir->Event.KeyEvent.wVirtualKeyCode)
+            {
+            case VK_DOWN:   /* DOWN */
+                ScrollDownGenericList(&ListUi);
+                break;
+            case VK_UP:     /* UP */
+                ScrollUpGenericList(&ListUi);
+                break;
+            case VK_NEXT:   /* PAGE DOWN */
+                ScrollPageDownGenericList(&ListUi);
+                break;
+            case VK_PRIOR:  /* PAGE UP */
+                ScrollPageUpGenericList(&ListUi);
+                break;
+            case VK_F3:     /* F3 */
+            {
+                if (ConfirmQuit(Ir))
+                    return QUIT_PAGE;
+                else
+                    RedrawGenericList(&ListUi);
+                break;
+            }
+            case VK_ESCAPE: /* ESC */
+            {
+                RestoreGenericListUiState(&ListUi);
+                // return nextPage;    // prevPage;
 
-            break;
+                // return INSTALL_INTRO_PAGE;
+                return DEVICE_SETTINGS_PAGE;
+                // return SCSI_CONTROLLER_PAGE;
+            }
+            }
         }
-        else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+        else
         {
-            return DEVICE_SETTINGS_PAGE;
-            // return SCSI_CONTROLLER_PAGE;
+            // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
+            // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+            if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U')  /* U */
+            {
+                /* Retrieve the current installation */
+                ASSERT(GetNumberOfListEntries(NtOsInstallsList) >= 1);
+
+                CurrentInstallation =
+                    (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(NtOsInstallsList));
+
+                DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
+                        CurrentInstallation->InstallationName, CurrentInstallation->DiskNumber, CurrentInstallation->PartitionNumber);
+
+                RepairUpdateFlag = TRUE;
+
+                // return nextPage;
+                /***/return INSTALL_INTRO_PAGE;/***/
+            }
+            else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) &&
+                     (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))   /* a-z */
+            {
+                GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
+            }
         }
     }
 
-    return INSTALL_INTRO_PAGE;
+    return UPGRADE_REPAIR_PAGE;
 }
 
 
-#if 0
-static PAGE_NUMBER
-ScsiControllerPage(PINPUT_RECORD Ir)
-{
-    SetTextXY(6, 8, "Setup detected the following mass storage devices:");
-
-    /* FIXME: print loaded mass storage driver descriptions */
-#if 0
-    SetTextXY(8, 10, "TEST device");
+/*
+ * Displays the InstallIntroPage.
+ *
+ * Next pages:
+ *  DeviceSettingsPage  (At once if repair or update is selected)
+ *  SelectPartitionPage (At once if unattended setup)
+ *  DeviceSettingsPage  (default)
+ *  QuitPage
+ *
+ * RETURNS
+ *   Number of the next page.
+ */
+static PAGE_NUMBER
+InstallIntroPage(PINPUT_RECORD Ir)
+{
+    if (RepairUpdateFlag)
+    {
+#if 1 /* Old code that looks good */
+
+        // return SELECT_PARTITION_PAGE;
+        return DEVICE_SETTINGS_PAGE;
+
+#else /* Possible new code? */
+
+        return DEVICE_SETTINGS_PAGE;
+        // return SCSI_CONTROLLER_PAGE;
+
 #endif
+    }
+
+    if (IsUnattendedSetup)
+        return SELECT_PARTITION_PAGE;
+
+    MUIDisplayPage(INSTALL_INTRO_PAGE);
+
+    while (TRUE)
+    {
+        CONSOLE_ConInKey(Ir);
+
+        if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+            (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+        {
+            if (ConfirmQuit(Ir))
+                return QUIT_PAGE;
+
+            break;
+        }
+        else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+        {
+            return UPGRADE_REPAIR_PAGE;
+        }
+    }
+
+    return INSTALL_INTRO_PAGE;
+}
+
+
+#if 0
+static PAGE_NUMBER
+ScsiControllerPage(PINPUT_RECORD Ir)
+{
+    // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
+
+    CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
 
+    /* FIXME: print loaded mass storage driver descriptions */
+#if 0
+    CONSOLE_SetTextXY(8, 10, "TEST device");
+#endif
 
-    SetStatusText("   ENTER = Continue   F3 = Quit");
+    CONSOLE_SetStatusText("   ENTER = Continue   F3 = Quit");
 
     while (TRUE)
     {
-        ConInKey(Ir);
+        CONSOLE_ConInKey(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;
@@ -1161,6 +1067,38 @@ ScsiControllerPage(PINPUT_RECORD Ir)
 
     return SCSI_CONTROLLER_PAGE;
 }
+
+static PAGE_NUMBER
+OemDriverPage(PINPUT_RECORD Ir)
+{
+    // MUIDisplayPage(OEM_DRIVER_PAGE);
+
+    CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
+
+    /* FIXME: Implement!! */
+
+    CONSOLE_SetStatusText("   ENTER = Continue   F3 = Quit");
+
+    while (TRUE)
+    {
+        CONSOLE_ConInKey(Ir);
+
+        if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+            (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+        {
+            if (ConfirmQuit(Ir))
+                return QUIT_PAGE;
+
+            break;
+        }
+        else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+        {
+            return DEVICE_SETTINGS_PAGE;
+        }
+    }
+
+    return OEM_DRIVER_PAGE;
+}
 #endif
 
 
@@ -1177,10 +1115,10 @@ ScsiControllerPage(PINPUT_RECORD Ir)
  *  QuitPage
  *
  * SIDEEFFECTS
- *  Init ComputerList
- *  Init DisplayList
- *  Init KeyboardList
- *  Init LayoutList
+ *  Init USetupData.ComputerList
+ *  Init USetupData.DisplayList
+ *  Init USetupData.KeyboardList
+ *  Init USetupData.LayoutList
  *
  * RETURNS
  *   Number of the next page.
@@ -1189,13 +1127,12 @@ static PAGE_NUMBER
 DeviceSettingsPage(PINPUT_RECORD Ir)
 {
     static ULONG Line = 16;
-    MUIDisplayPage(DEVICE_SETTINGS_PAGE);
 
     /* Initialize the computer settings list */
-    if (ComputerList == NULL)
+    if (USetupData.ComputerList == NULL)
     {
-        ComputerList = CreateComputerTypeList(SetupInf);
-        if (ComputerList == NULL)
+        USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
+        if (USetupData.ComputerList == NULL)
         {
             MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
             return QUIT_PAGE;
@@ -1203,10 +1140,10 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
     }
 
     /* Initialize the display settings list */
-    if (DisplayList == NULL)
+    if (USetupData.DisplayList == NULL)
     {
-        DisplayList = CreateDisplayDriverList(SetupInf);
-        if (DisplayList == NULL)
+        USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
+        if (USetupData.DisplayList == NULL)
         {
             MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
             return QUIT_PAGE;
@@ -1214,10 +1151,10 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
     }
 
     /* Initialize the keyboard settings list */
-    if (KeyboardList == NULL)
+    if (USetupData.KeyboardList == NULL)
     {
-        KeyboardList = CreateKeyboardDriverList(SetupInf);
-        if (KeyboardList == NULL)
+        USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
+        if (USetupData.KeyboardList == NULL)
         {
             MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
             return QUIT_PAGE;
@@ -1225,10 +1162,10 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
     }
 
     /* Initialize the keyboard layout list */
-    if (LayoutList == NULL)
+    if (USetupData.LayoutList == NULL)
     {
-        LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
-        if (LayoutList == NULL)
+        USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
+        if (USetupData.LayoutList == NULL)
         {
             /* FIXME: report error */
             MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
@@ -1236,20 +1173,20 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
         }
     }
 
-    MUIDisplayPage(DEVICE_SETTINGS_PAGE);
+    if (RepairUpdateFlag)
+        return SELECT_PARTITION_PAGE;
 
+    // if (IsUnattendedSetup)
+        // return SELECT_PARTITION_PAGE;
 
-    CONSOLE_SetTextXY(25, 11, GetListEntryText(GetCurrentListEntry((ComputerList))));
-    CONSOLE_SetTextXY(25, 12, GetListEntryText(GetCurrentListEntry((DisplayList))));
-    CONSOLE_SetTextXY(25, 13, GetListEntryText(GetCurrentListEntry((KeyboardList))));
-    CONSOLE_SetTextXY(25, 14, GetListEntryText(GetCurrentListEntry((LayoutList))));
+    MUIDisplayPage(DEVICE_SETTINGS_PAGE);
 
-    CONSOLE_InvertTextXY(24, Line, 48, 1);
+    DrawGenericListCurrentItem(USetupData.ComputerList, GetSettingDescription, 25, 11);
+    DrawGenericListCurrentItem(USetupData.DisplayList , GetSettingDescription, 25, 12);
+    DrawGenericListCurrentItem(USetupData.KeyboardList, GetSettingDescription, 25, 13);
+    DrawGenericListCurrentItem(USetupData.LayoutList  , GetSettingDescription, 25, 14);
 
-    if (RepairUpdateFlag)
-    {
-        return SELECT_PARTITION_PAGE;
-    }
+    CONSOLE_InvertTextXY(24, Line, 48, 1);
 
     while (TRUE)
     {
@@ -1286,7 +1223,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;
@@ -1319,7 +1256,7 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
  * Ir: The PINPUT_RECORD
  */
 static PAGE_NUMBER
-HandleGenericList(PGENERIC_LIST GenericList,
+HandleGenericList(PGENERIC_LIST_UI ListUi,
                   PAGE_NUMBER nextPage,
                   PINPUT_RECORD Ir)
 {
@@ -1330,36 +1267,36 @@ HandleGenericList(PGENERIC_LIST GenericList,
         if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
             (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN))  /* DOWN */
         {
-            ScrollDownGenericList(GenericList);
+            ScrollDownGenericList(ListUi);
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP))  /* UP */
         {
-            ScrollUpGenericList(GenericList);
+            ScrollUpGenericList(ListUi);
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT))  /* PAGE DOWN */
         {
-            ScrollPageDownGenericList(GenericList);
+            ScrollPageDownGenericList(ListUi);
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR))  /* PAGE UP */
         {
-            ScrollPageUpGenericList(GenericList);
+            ScrollPageUpGenericList(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;
-
-            continue;
+            else
+                RedrawGenericList(ListUi);
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE))  /* ESC */
         {
-            RestoreGenericListState(GenericList);
-            return nextPage;
+            RestoreGenericListUiState(ListUi);
+            return nextPage;    // Use some "prevPage;" instead?
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
         {
@@ -1368,7 +1305,7 @@ HandleGenericList(PGENERIC_LIST GenericList,
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
         {
             /* a-z */
-            GenericListKeyPress(GenericList, Ir->Event.KeyEvent.uChar.AsciiChar);
+            GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
         }
     }
 }
@@ -1387,20 +1324,19 @@ HandleGenericList(PGENERIC_LIST GenericList,
 static PAGE_NUMBER
 ComputerSettingsPage(PINPUT_RECORD Ir)
 {
+    GENERIC_LIST_UI ListUi;
     MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
 
-    DrawGenericList(ComputerList,
-                    2,
-                    18,
+    InitGenericListUi(&ListUi, USetupData.ComputerList, GetSettingDescription);
+    DrawGenericList(&ListUi,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
-    SaveGenericListState(ComputerList);
-
-    return HandleGenericList(ComputerList, DEVICE_SETTINGS_PAGE, Ir);
+    return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
 }
+
+
 /*
  * Displays the DisplaySettingsPage.
  *
@@ -1414,17 +1350,16 @@ ComputerSettingsPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 DisplaySettingsPage(PINPUT_RECORD Ir)
 {
+    GENERIC_LIST_UI ListUi;
     MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
 
-    DrawGenericList(DisplayList,
-                    2,
-                    18,
+    InitGenericListUi(&ListUi, USetupData.DisplayList, GetSettingDescription);
+    DrawGenericList(&ListUi,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
-    SaveGenericListState(DisplayList);
-
-    return HandleGenericList(DisplayList, DEVICE_SETTINGS_PAGE, Ir);
+    return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
 }
 
 
@@ -1441,17 +1376,16 @@ DisplaySettingsPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 KeyboardSettingsPage(PINPUT_RECORD Ir)
 {
+    GENERIC_LIST_UI ListUi;
     MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
 
-    DrawGenericList(KeyboardList,
-                    2,
-                    18,
+    InitGenericListUi(&ListUi, USetupData.KeyboardList, GetSettingDescription);
+    DrawGenericList(&ListUi,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
-    SaveGenericListState(KeyboardList);
-
-    return HandleGenericList(KeyboardList, DEVICE_SETTINGS_PAGE, Ir);
+    return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
 }
 
 
@@ -1468,17 +1402,16 @@ KeyboardSettingsPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 LayoutSettingsPage(PINPUT_RECORD Ir)
 {
+    GENERIC_LIST_UI ListUi;
     MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
 
-    DrawGenericList(LayoutList,
-                    2,
-                    18,
+    InitGenericListUi(&ListUi, USetupData.LayoutList, GetSettingDescription);
+    DrawGenericList(&ListUi,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
-    SaveGenericListState(LayoutList);
-
-    return HandleGenericList(LayoutList, DEVICE_SETTINGS_PAGE, Ir);
+    return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
 }
 
 
@@ -1488,12 +1421,12 @@ IsDiskSizeValid(PPARTENTRY PartEntry)
     ULONGLONG size;
 
     size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
-    size = (size + 524288) / 1048576;  /* in MBytes */
+    size = (size + (512 * KB)) / MB;  /* in MBytes */
 
-    if (size < RequiredPartitionDiskSpace)
+    if (size < USetupData.RequiredPartitionDiskSpace)
     {
-        /* partition is too small so ask for another partition */
-        DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, 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, USetupData.RequiredPartitionDiskSpace);
         return FALSE;
     }
     else
@@ -1517,7 +1450,6 @@ IsDiskSizeValid(PPARTENTRY PartEntry)
  *  QuitPage
  *
  * SIDEEFFECTS
- *  Init DestinationDriveLetter (only if unattended or not free space is selected)
  *  Set InstallShortcut (only if not unattended + free space is selected)
  *
  * RETURNS
@@ -1526,19 +1458,16 @@ IsDiskSizeValid(PPARTENTRY PartEntry)
 static PAGE_NUMBER
 SelectPartitionPage(PINPUT_RECORD Ir)
 {
+    PARTLIST_UI ListUi;
     ULONG Error;
 
-    MUIDisplayPage(SELECT_PARTITION_PAGE);
-
     if (PartitionList == NULL)
     {
-        PartitionList = CreatePartitionList(2,
-                                            23,
-                                            xScreen - 3,
-                                            yScreen - 3);
+        PartitionList = CreatePartitionList();
         if (PartitionList == NULL)
         {
             /* FIXME: show an error dialog */
+            MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
             return QUIT_PAGE;
         }
         else if (IsListEmpty(&PartitionList->DiskListHead))
@@ -1546,15 +1475,41 @@ SelectPartitionPage(PINPUT_RECORD Ir)
             MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
             return QUIT_PAGE;
         }
+
+        TempPartition = NULL;
+        FormatState = Start;
+    }
+
+    if (RepairUpdateFlag)
+    {
+        /* Determine the selected installation disk & partition */
+        if (!SelectPartition(PartitionList,
+                             CurrentInstallation->DiskNumber,
+                             CurrentInstallation->PartitionNumber))
+        {
+            DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
+            ASSERT(FALSE);
+        }
+
+        return SELECT_FILE_SYSTEM_PAGE;
     }
 
-    DrawPartitionList(PartitionList);
+    MUIDisplayPage(SELECT_PARTITION_PAGE);
+
+    InitPartitionListUi(&ListUi, PartitionList,
+                        2,
+                        23,
+                        xScreen - 3,
+                        yScreen - 3);
+    DrawPartitionList(&ListUi);
 
     if (IsUnattendedSetup)
     {
-        if (!SelectPartition(PartitionList, UnattendDestinationDiskNumber, UnattendDestinationPartitionNumber))
+        if (!SelectPartition(PartitionList,
+                             USetupData.DestinationDiskNumber,
+                             USetupData.DestinationPartitionNumber))
         {
-            if (AutoPartition)
+            if (USetupData.AutoPartition)
             {
                 if (PartitionList->CurrentPartition->LogicalPartition)
                 {
@@ -1569,29 +1524,29 @@ SelectPartitionPage(PINPUT_RECORD Ir)
                                            TRUE);
                 }
 
+// FIXME?? Aren't we going to enter an infinite loop, if this test fails??
                 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 */
                 }
 
-                DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
-
                 return SELECT_FILE_SYSTEM_PAGE;
             }
         }
         else
         {
+            DrawPartitionList(&ListUi);
+
+// FIXME?? Aren't we going to enter an infinite loop, if this test fails??
             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 */
             }
 
-            DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
-
             return SELECT_FILE_SYSTEM_PAGE;
         }
     }
@@ -1638,7 +1593,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;
@@ -1650,14 +1605,12 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN))  /* DOWN */
         {
-            if (ScrollDownPartitionList(PartitionList))
-                DrawPartitionList(PartitionList);
+            ScrollDownPartitionList(&ListUi);
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP))  /* UP */
         {
-            if (ScrollUpPartitionList(PartitionList))
-                DrawPartitionList(PartitionList);
+            ScrollUpPartitionList(&ListUi);
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN)  /* ENTER */
         {
@@ -1684,12 +1637,10 @@ 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 */
             }
 
-            DestinationDriveLetter = (WCHAR)PartitionList->CurrentPartition->DriveLetter;
-
             return SELECT_FILE_SYSTEM_PAGE;
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P')  /* P */
@@ -1722,7 +1673,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)
@@ -1736,12 +1687,34 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D')  /* D */
         {
+            WCHAR PathBuffer[MAX_PATH];
+            UNICODE_STRING CurrentPartition;
+
             if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
             {
                 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
                 return SELECT_PARTITION_PAGE;
             }
 
+            RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+                    L"\\Device\\Harddisk%lu\\Partition%lu\\",
+                    PartitionList->CurrentDisk->DiskNumber,
+                    PartitionList->CurrentPartition->PartitionNumber);
+            RtlInitUnicodeString(&CurrentPartition, PathBuffer);
+
+            /*
+             * Check whether the user attempts to delete the partition on which
+             * the installation source is present. If so, fail with an error.
+             */
+            // &USetupData.SourceRootPath
+            if (RtlPrefixUnicodeString(&CurrentPartition, &USetupData.SourcePath, TRUE))
+            {
+                PopupError("You cannot delete the partition containing the installation source!",
+                           MUIGetString(STRING_CONTINUE),
+                           Ir, POPUP_WAIT_ENTER);
+                return SELECT_PARTITION_PAGE;
+            }
+
             if (PartitionList->CurrentPartition->BootIndicator ||
                 PartitionList->CurrentPartition == PartitionList->SystemPartition)
             {
@@ -1985,15 +1958,15 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
 
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         if (DiskSize == 0)
             DiskSize = 1;
 
@@ -2003,32 +1976,34 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
     if (DiskEntry->DriverName.Length > 0)
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDINFOPARTCREATE),
+                            MUIGetString(STRING_HDINFOPARTCREATE_1),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
     else
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDDINFOUNK1),
+                            MUIGetString(STRING_HDINFOPARTCREATE_2),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
-                            DiskEntry->Id);
+                            DiskEntry->Id,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
     CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
 
 #if 0
     CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
-                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
+                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
 #endif
 
     CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
@@ -2036,7 +2011,7 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
     PartEntry = PartitionList->CurrentPartition;
     while (TRUE)
     {
-        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576;  /* in MBytes (rounded) */
+        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB;  /* in MBytes (rounded) */
 
         if (MaxSize > PARTITION_MAXSIZE)
             MaxSize = PARTITION_MAXSIZE;
@@ -2044,14 +2019,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;
         }
@@ -2080,7 +2055,7 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
             else
             {
                 /* Calculate the sector count from the size in MB */
-                SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
+                SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
 
                 /* But never get larger than the unpartitioned disk space */
                 if (SectorCount > PartEntry->SectorCount.QuadPart)
@@ -2142,15 +2117,15 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
 
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         if (DiskSize == 0)
             DiskSize = 1;
 
@@ -2160,32 +2135,34 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
     if (DiskEntry->DriverName.Length > 0)
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDINFOPARTCREATE),
+                            MUIGetString(STRING_HDINFOPARTCREATE_1),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
     else
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDDINFOUNK1),
+                            MUIGetString(STRING_HDINFOPARTCREATE_2),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
-                            DiskEntry->Id);
+                            DiskEntry->Id,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
     CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
 
 #if 0
     CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
-                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
+                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
 #endif
 
     CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
@@ -2193,7 +2170,7 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
     PartEntry = PartitionList->CurrentPartition;
     while (TRUE)
     {
-        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576;  /* in MBytes (rounded) */
+        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB;  /* in MBytes (rounded) */
 
         if (MaxSize > PARTITION_MAXSIZE)
             MaxSize = PARTITION_MAXSIZE;
@@ -2201,14 +2178,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;
         }
@@ -2237,7 +2214,7 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
             else
             {
                 /* Calculate the sector count from the size in MB */
-                SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
+                SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
 
                 /* But never get larger than the unpartitioned disk space */
                 if (SectorCount > PartEntry->SectorCount.QuadPart)
@@ -2298,15 +2275,15 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
 
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         if (DiskSize == 0)
             DiskSize = 1;
 
@@ -2316,32 +2293,34 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
     if (DiskEntry->DriverName.Length > 0)
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDINFOPARTCREATE),
+                            MUIGetString(STRING_HDINFOPARTCREATE_1),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
     else
     {
         CONSOLE_PrintTextXY(6, 10,
-                            MUIGetString(STRING_HDDINFOUNK1),
+                            MUIGetString(STRING_HDINFOPARTCREATE_2),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
-                            DiskEntry->Id);
+                            DiskEntry->Id,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
     CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
 
 #if 0
     CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
-                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / 1048576);
+                        PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
 #endif
 
     CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
@@ -2349,7 +2328,7 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
     PartEntry = PartitionList->CurrentPartition;
     while (TRUE)
     {
-        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / 1048576;  /* in MBytes (rounded) */
+        MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB;  /* in MBytes (rounded) */
 
         if (MaxSize > PARTITION_MAXSIZE)
             MaxSize = PARTITION_MAXSIZE;
@@ -2357,14 +2336,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;
         }
@@ -2393,7 +2372,7 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
             else
             {
                 /* Calculate the sector count from the size in MB */
-                SectorCount = PartSize * 1048576 / DiskEntry->BytesPerSector;
+                SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
 
                 /* But never get larger than the unpartitioned disk space */
                 if (SectorCount > PartEntry->SectorCount.QuadPart)
@@ -2436,7 +2415,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;
@@ -2494,21 +2473,21 @@ DeletePartitionPage(PINPUT_RECORD Ir)
 
     PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (PartSize >= 10737418240) /* 10 GB */
+    if (PartSize >= 10 * GB) /* 10 GB */
     {
-        PartSize = PartSize / 1073741824;
+        PartSize = PartSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
-    if (PartSize >= 10485760) /* 10 MB */
+    if (PartSize >= 10 * MB) /* 10 MB */
     {
-        PartSize = PartSize / 1048576;
+        PartSize = PartSize / MB;
         Unit = MUIGetString(STRING_MB);
     }
     else
     {
-        PartSize = PartSize / 1024;
+        PartSize = PartSize / KB;
         Unit = MUIGetString(STRING_KB);
     }
 
@@ -2535,15 +2514,15 @@ DeletePartitionPage(PINPUT_RECORD Ir)
 
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         Unit = MUIGetString(STRING_GB);
     }
     else
 #endif
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         if (DiskSize == 0)
             DiskSize = 1;
 
@@ -2553,25 +2532,27 @@ DeletePartitionPage(PINPUT_RECORD Ir)
     if (DiskEntry->DriverName.Length > 0)
     {
         CONSOLE_PrintTextXY(6, 12,
-                            MUIGetString(STRING_HDINFOPARTDELETE),
+                            MUIGetString(STRING_HDINFOPARTDELETE_1),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
     else
     {
         CONSOLE_PrintTextXY(6, 12,
-                            MUIGetString(STRING_HDDINFOUNK3),
+                            MUIGetString(STRING_HDINFOPARTDELETE_2),
                             DiskSize,
                             Unit,
                             DiskEntry->DiskNumber,
                             DiskEntry->Port,
                             DiskEntry->Bus,
-                            DiskEntry->Id);
+                            DiskEntry->Id,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
     while (TRUE)
@@ -2581,7 +2562,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;
@@ -2607,8 +2588,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
@@ -2642,128 +2623,127 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
         return QUIT_PAGE;
     }
 
-    /*** HACK! ***/
-    if (FileSystemList == NULL)
-    {
-        FileSystemList = CreateFileSystemList(6, 26, PartitionList->CurrentPartition->New, L"FAT");
-        if (FileSystemList == NULL)
-        {
-            /* FIXME: show an error dialog */
-            return QUIT_PAGE;
-        }
-
-        /* FIXME: Add file systems to list */
-    }
-
     /* Find or set the active system partition */
-    CheckActiveSystemPartition(PartitionList, FileSystemList);
-
-    if (PartitionList->SystemDisk == NULL ||
-        PartitionList->SystemPartition == NULL)
+    CheckActiveSystemPartition(PartitionList);
+    if (PartitionList->SystemPartition == NULL)
     {
         /* FIXME: show an error dialog */
+        //
+        // Error dialog should say that we cannot find a suitable
+        // system partition and create one on the system. At this point,
+        // it may be nice to ask the user whether he wants to continue,
+        // or use an external drive as the system drive/partition
+        // (e.g. floppy, USB drive, etc...)
+        //
         return QUIT_PAGE;
     }
 
-    PreviousFormatState = PartitionList->FormatState;
-    switch (PartitionList->FormatState)
+    PreviousFormatState = FormatState;
+    switch (FormatState)
     {
         case Start:
+        {
             if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
             {
-                PartitionList->TempDisk = PartitionList->SystemDisk;
-                PartitionList->TempPartition = PartitionList->SystemPartition;
-                PartitionList->TempPartition->NeedsCheck = TRUE;
+                TempPartition = PartitionList->SystemPartition;
+                TempPartition->NeedsCheck = TRUE;
 
-                PartitionList->FormatState = FormatSystemPartition;
+                FormatState = FormatSystemPartition;
                 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
             }
             else
             {
-                PartitionList->TempDisk = PartitionList->CurrentDisk;
-                PartitionList->TempPartition = PartitionList->CurrentPartition;
-                PartitionList->TempPartition->NeedsCheck = TRUE;
+                TempPartition = PartitionList->CurrentPartition;
+                TempPartition->NeedsCheck = TRUE;
 
-                PartitionList->FormatState = FormatInstallPartition;
+                FormatState = FormatInstallPartition;
                 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
             }
             break;
+        }
 
         case FormatSystemPartition:
-            PartitionList->TempDisk = PartitionList->CurrentDisk;
-            PartitionList->TempPartition = PartitionList->CurrentPartition;
-            PartitionList->TempPartition->NeedsCheck = TRUE;
+        {
+            TempPartition = PartitionList->CurrentPartition;
+            TempPartition->NeedsCheck = TRUE;
 
-            PartitionList->FormatState = FormatInstallPartition;
+            FormatState = FormatInstallPartition;
             DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
             break;
+        }
 
         case FormatInstallPartition:
+        {
             if (GetNextUnformattedPartition(PartitionList,
-                                            &PartitionList->TempDisk,
-                                            &PartitionList->TempPartition))
+                                            NULL,
+                                            &TempPartition))
             {
-                PartitionList->FormatState = FormatOtherPartition;
-                PartitionList->TempPartition->NeedsCheck = TRUE;
+                FormatState = FormatOtherPartition;
+                TempPartition->NeedsCheck = TRUE;
                 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
             }
             else
             {
-                PartitionList->FormatState = FormatDone;
+                FormatState = FormatDone;
                 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
                 return CHECK_FILE_SYSTEM_PAGE;
             }
             break;
+        }
 
         case FormatOtherPartition:
+        {
             if (GetNextUnformattedPartition(PartitionList,
-                                            &PartitionList->TempDisk,
-                                            &PartitionList->TempPartition))
+                                            NULL,
+                                            &TempPartition))
             {
-                PartitionList->FormatState = FormatOtherPartition;
-                PartitionList->TempPartition->NeedsCheck = TRUE;
+                FormatState = FormatOtherPartition;
+                TempPartition->NeedsCheck = TRUE;
                 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
             }
             else
             {
-                PartitionList->FormatState = FormatDone;
+                FormatState = FormatDone;
                 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
                 return CHECK_FILE_SYSTEM_PAGE;
             }
             break;
+        }
 
         default:
-            DPRINT1("FormatState: Invalid value %ld\n", PartitionList->FormatState);
+        {
+            DPRINT1("FormatState: Invalid value %ld\n", FormatState);
             /* FIXME: show an error dialog */
             return QUIT_PAGE;
+        }
     }
 
-    DiskEntry = PartitionList->TempDisk;
-    PartEntry = PartitionList->TempPartition;
+    PartEntry = TempPartition;
+    DiskEntry = PartEntry->DiskEntry;
 
     /* Adjust disk size */
     DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
-    if (DiskSize >= 10737418240) /* 10 GB */
+    if (DiskSize >= 10 * GB) /* 10 GB */
     {
-        DiskSize = DiskSize / 1073741824;
+        DiskSize = DiskSize / GB;
         DiskUnit = MUIGetString(STRING_GB);
     }
     else
     {
-        DiskSize = DiskSize / 1048576;
+        DiskSize = DiskSize / MB;
         DiskUnit = MUIGetString(STRING_MB);
     }
 
     /* Adjust partition size */
     PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
-    if (PartSize >= 10737418240) /* 10 GB */
+    if (PartSize >= 10 * GB) /* 10 GB */
     {
-        PartSize = PartSize / 1073741824;
+        PartSize = PartSize / GB;
         PartUnit = MUIGetString(STRING_GB);
     }
     else
     {
-        PartSize = PartSize / 1048576;
+        PartSize = PartSize / MB;
         PartUnit = MUIGetString(STRING_MB);
     }
 
@@ -2772,7 +2752,9 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                                        PartTypeString,
                                        ARRAYSIZE(PartTypeString));
 
-    if (PartEntry->AutoCreate != FALSE)
+    MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
+
+    if (PartEntry->AutoCreate)
     {
         CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
 
@@ -2784,22 +2766,23 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                             PartTypeString);
 #endif
 
-        CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED),
+        CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
                             DiskEntry->DiskNumber,
                             DiskSize,
                             DiskUnit,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
 
         CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
 
         PartEntry->AutoCreate = FALSE;
     }
-    else if (PartEntry->New != FALSE)
+    else if (PartEntry->New)
     {
-        switch (PartitionList->FormatState)
+        switch (FormatState)
         {
             case FormatSystemPartition:
                 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
@@ -2844,32 +2827,28 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                                 PartUnit);
         }
 
-        CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS),
+        CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
                             DiskEntry->DiskNumber,
                             DiskSize,
                             DiskUnit,
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            &DiskEntry->DriverName);
+                            &DiskEntry->DriverName,
+                            DiskEntry->NoMbr ? "GPT" : "MBR");
     }
 
-    MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
-
     if (FileSystemList == NULL)
     {
+        /* Create the file system list, and by default select the "FAT" file system */
         FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
         if (FileSystemList == NULL)
         {
             /* FIXME: show an error dialog */
             return QUIT_PAGE;
         }
-
-        /* FIXME: Add file systems to list */
     }
 
-    DrawFileSystemList(FileSystemList);
-
     if (RepairUpdateFlag)
     {
         return CHECK_FILE_SYSTEM_PAGE;
@@ -2878,15 +2857,23 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
 
     if (IsUnattendedSetup)
     {
-        if (UnattendFormatPartition)
+        if (USetupData.FormatPartition)
         {
-            PartEntry->FileSystem = GetFileSystemByName(FileSystemList, L"FAT");
+            /*
+             * We use whatever currently selected file system we have
+             * (by default, this is "FAT", as per the initialization
+             * performed above). Note that it may be interesting to specify
+             * which file system to use in unattended installations, in the
+             * txtsetup.sif file.
+             */
             return FORMAT_PARTITION_PAGE;
         }
 
         return CHECK_FILE_SYSTEM_PAGE;
     }
 
+    DrawFileSystemList(FileSystemList);
+
     while (TRUE)
     {
         CONSOLE_ConInKey(Ir);
@@ -2894,7 +2881,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;
@@ -2902,7 +2889,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE))  /* ESC */
         {
-            PartitionList->FormatState = Start;
+            FormatState = Start;
             return SELECT_PARTITION_PAGE;
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
@@ -2917,19 +2904,14 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
         {
-            if (!FileSystemList->Selected->FormatFunc)
-            {
+            if (!FileSystemList->Selected->FileSystem)
                 return SELECT_FILE_SYSTEM_PAGE;
-            }
             else
-            {
-                PartEntry->FileSystem = FileSystemList->Selected;
                 return FORMAT_PARTITION_PAGE;
-            }
         }
     }
 
-    PartitionList->FormatState = PreviousFormatState;
+    FormatState = PreviousFormatState;
 
     return SELECT_FILE_SYSTEM_PAGE;
 }
@@ -2945,19 +2927,21 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
  *
  * SIDEEFFECTS
  *  Sets PartitionList->CurrentPartition->FormatState
- *  Sets DestinationRootPath
+ *  Sets USetupData.DestinationRootPath
  *
  * RETURNS
  *   Number of the next page.
  */
-static ULONG
+static PAGE_NUMBER
 FormatPartitionPage(PINPUT_RECORD Ir)
 {
-    UNICODE_STRING PartitionRootPath;
-    WCHAR PathBuffer[MAX_PATH];
+    NTSTATUS Status;
     PDISKENTRY DiskEntry;
     PPARTENTRY PartEntry;
-    NTSTATUS Status;
+    PFILE_SYSTEM_ITEM SelectedFileSystem;
+    UNICODE_STRING PartitionRootPath;
+    WCHAR PathBuffer[MAX_PATH];
+    CHAR Buffer[MAX_PATH];
 
 #ifndef NDEBUG
     ULONG Line;
@@ -2969,16 +2953,16 @@ FormatPartitionPage(PINPUT_RECORD Ir)
 
     MUIDisplayPage(FORMAT_PARTITION_PAGE);
 
-    if (PartitionList == NULL ||
-        PartitionList->TempDisk == NULL ||
-        PartitionList->TempPartition == NULL)
+    if (PartitionList == NULL || TempPartition == NULL)
     {
         /* FIXME: show an error dialog */
         return QUIT_PAGE;
     }
 
-    DiskEntry = PartitionList->TempDisk;
-    PartEntry = PartitionList->TempPartition;
+    PartEntry = TempPartition;
+    DiskEntry = PartEntry->DiskEntry;
+
+    SelectedFileSystem = FileSystemList->Selected;
 
     while (TRUE)
     {
@@ -2990,7 +2974,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;
@@ -2999,72 +2983,7 @@ FormatPartitionPage(PINPUT_RECORD Ir)
         {
             CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
-            if (wcscmp(PartEntry->FileSystem->FileSystemName, L"FAT") == 0)
-            {
-                if (PartEntry->SectorCount.QuadPart < 8192)
-                {
-                    /* FAT12 CHS partition (disk is smaller than 4.1MB) */
-                    PartEntry->PartitionType = PARTITION_FAT_12;
-                }
-                else if (PartEntry->StartSector.QuadPart < 1450560)
-                {
-                    /* Partition starts below the 8.4GB boundary ==> CHS partition */
-
-                    if (PartEntry->SectorCount.QuadPart < 65536)
-                    {
-                        /* FAT16 CHS partition (partition size < 32MB) */
-                        PartEntry->PartitionType = PARTITION_FAT_16;
-                    }
-                    else if (PartEntry->SectorCount.QuadPart < 1048576)
-                    {
-                        /* FAT16 CHS partition (partition size < 512MB) */
-                        PartEntry->PartitionType = PARTITION_HUGE;
-                    }
-                    else
-                    {
-                        /* FAT32 CHS partition (partition size >= 512MB) */
-                        PartEntry->PartitionType = PARTITION_FAT32;
-                    }
-                }
-                else
-                {
-                    /* Partition starts above the 8.4GB boundary ==> LBA partition */
-
-                    if (PartEntry->SectorCount.QuadPart < 1048576)
-                    {
-                        /* FAT16 LBA partition (partition size < 512MB) */
-                        PartEntry->PartitionType = PARTITION_XINT13;
-                    }
-                    else
-                    {
-                        /* FAT32 LBA partition (partition size >= 512MB) */
-                        PartEntry->PartitionType = PARTITION_FAT32_XINT13;
-                    }
-                }
-
-                DiskEntry->Dirty = TRUE;
-                DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
-                DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
-            }
-#if 0
-            else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"EXT2") == 0)
-            {
-                PartEntry->PartitionType = PARTITION_EXT2;
-
-                DiskEntry->Dirty = TRUE;
-                DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
-                DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
-            }
-            else if (wcscmp(PartEntry->FileSystem->FileSystemName, L"NTFS") == 0)
-            {
-                PartEntry->PartitionType = PARTITION_IFS;
-
-                DiskEntry->Dirty = TRUE;
-                DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartEntry->PartitionType;
-                DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
-            }
-#endif
-            else if (!PartEntry->FileSystem->FormatFunc)
+            if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
             {
                 /* FIXME: show an error dialog */
                 return QUIT_PAGE;
@@ -3097,7 +3016,8 @@ FormatPartitionPage(PINPUT_RECORD Ir)
             }
 #endif
 
-            if (WritePartitionsToDisk(PartitionList) == FALSE)
+            /* Commit the partition changes to the disk */
+            if (!WritePartitionsToDisk(PartitionList))
             {
                 DPRINT("WritePartitionsToDisk() failed\n");
                 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
@@ -3105,25 +3025,58 @@ FormatPartitionPage(PINPUT_RECORD Ir)
             }
 
             /* Set PartitionRootPath */
-            swprintf(PathBuffer,
-                     L"\\Device\\Harddisk%lu\\Partition%lu",
-                     DiskEntry->DiskNumber,
-                     PartEntry->PartitionNumber);
-            RtlInitUnicodeString(&PartitionRootPath,
-                                 PathBuffer);
+            RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+                    L"\\Device\\Harddisk%lu\\Partition%lu",
+                    DiskEntry->DiskNumber,
+                    PartEntry->PartitionNumber);
+            RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
             DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
 
-            if (PartEntry->FileSystem->FormatFunc)
+            /* Format the partition */
+            if (SelectedFileSystem->FileSystem)
             {
                 Status = FormatPartition(&PartitionRootPath,
-                                         PartEntry->FileSystem);
-                if (!NT_SUCCESS(Status))
+                                         SelectedFileSystem);
+                if (Status == STATUS_NOT_SUPPORTED)
+                {
+                    sprintf(Buffer,
+                            "Setup is currently unable to format a partition in %S.\n"
+                            "\n"
+                            "  \x07  Press ENTER to continue Setup.\n"
+                            "  \x07  Press F3 to quit Setup.",
+                            SelectedFileSystem->FileSystem->FileSystemName);
+
+                    PopupError(Buffer,
+                               MUIGetString(STRING_QUITCONTINUE),
+                               NULL, POPUP_WAIT_NONE);
+
+                    while (TRUE)
+                    {
+                        CONSOLE_ConInKey(Ir);
+
+                        if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
+                            Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)  /* F3 */
+                        {
+                            if (ConfirmQuit(Ir))
+                                return QUIT_PAGE;
+                            else
+                                return SELECT_FILE_SYSTEM_PAGE;
+                        }
+                        else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
+                        {
+                            return SELECT_FILE_SYSTEM_PAGE;
+                        }
+                    }
+                }
+                else if (!NT_SUCCESS(Status))
                 {
                     DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
                     MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
                     return QUIT_PAGE;
                 }
 
+                PartEntry->FormatState = Formatted;
+                // PartEntry->FileSystem  = FileSystem;
                 PartEntry->New = FALSE;
             }
 
@@ -3153,16 +3106,16 @@ FormatPartitionPage(PINPUT_RECORD Ir)
  * RETURNS
  *   Number of the next page.
  */
-static ULONG
+static PAGE_NUMBER
 CheckFileSystemPage(PINPUT_RECORD Ir)
 {
-    PFILE_SYSTEM_ITEM CurrentFileSystem;
+    NTSTATUS Status;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PFILE_SYSTEM CurrentFileSystem;
     UNICODE_STRING PartitionRootPath;
     WCHAR PathBuffer[MAX_PATH];
     CHAR Buffer[MAX_PATH];
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-    NTSTATUS Status;
 
     if (PartitionList == NULL)
     {
@@ -3176,10 +3129,10 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
     }
 
     /* Set PartitionRootPath */
-    swprintf(PathBuffer,
-             L"\\Device\\Harddisk%lu\\Partition%lu",
-             DiskEntry->DiskNumber,
-             PartEntry->PartitionNumber);
+    RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+            L"\\Device\\Harddisk%lu\\Partition%lu",
+            DiskEntry->DiskNumber,
+            PartEntry->PartitionNumber);
     RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
     DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
 
@@ -3187,7 +3140,7 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
 
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
-    CurrentFileSystem = GetFileSystem(FileSystemList, PartEntry);
+    CurrentFileSystem = PartEntry->FileSystem;
     DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
             PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
 
@@ -3198,7 +3151,8 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
         return CHECK_FILE_SYSTEM_PAGE;
     }
 
-    if (CurrentFileSystem->ChkdskFunc == NULL)
+    Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
+    if (Status == STATUS_NOT_SUPPORTED)
     {
         sprintf(Buffer,
                 "Setup is currently unable to check a partition formatted in %S.\n"
@@ -3230,98 +3184,110 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
             }
         }
     }
-    else
+    else if (!NT_SUCCESS(Status))
     {
-        Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
-            // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
-            sprintf(Buffer, "ChkDsk detected some disk errors.\n"
-                    "(Status 0x%08lx).\n", Status);
-            PopupError(Buffer,
-                       // MUIGetString(STRING_REBOOTCOMPUTER),
-                       MUIGetString(STRING_CONTINUE),
-                       Ir, POPUP_WAIT_ENTER);
-
-            // return QUIT_PAGE;
-        }
+        DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
+        // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
+        sprintf(Buffer, "ChkDsk detected some disk errors.\n"
+                "(Status 0x%08lx).\n", Status);
+        PopupError(Buffer,
+                   // MUIGetString(STRING_REBOOTCOMPUTER),
+                   MUIGetString(STRING_CONTINUE),
+                   Ir, POPUP_WAIT_ENTER);
 
-        PartEntry->NeedsCheck = FALSE;
-        return CHECK_FILE_SYSTEM_PAGE;
+        // return QUIT_PAGE;
     }
+
+    PartEntry->NeedsCheck = FALSE;
+    return CHECK_FILE_SYSTEM_PAGE;
 }
 
 
-static
-VOID
-BuildInstallPaths(PWCHAR InstallDir,
+static VOID
+BuildInstallPaths(PWSTR InstallDir,
                   PDISKENTRY DiskEntry,
                   PPARTENTRY PartEntry)
 {
-    WCHAR PathBuffer[MAX_PATH];
+    NTSTATUS Status;
 
-    /* Create 'InstallPath' string */
-    RtlFreeUnicodeString(&InstallPath);
-    RtlCreateUnicodeString(&InstallPath, InstallDir);
-
-    /* Create 'DestinationRootPath' string */
-    RtlFreeUnicodeString(&DestinationRootPath);
-    swprintf(PathBuffer,
-             L"\\Device\\Harddisk%lu\\Partition%lu",
-             DiskEntry->DiskNumber,
-             PartEntry->PartitionNumber);
-    RtlCreateUnicodeString(&DestinationRootPath, PathBuffer);
-    DPRINT("DestinationRootPath: %wZ\n", &DestinationRootPath);
-
-    /* Create 'DestinationPath' string */
-    RtlFreeUnicodeString(&DestinationPath);
-    wcscpy(PathBuffer, DestinationRootPath.Buffer);
-
-    if (InstallDir[0] != L'\\')
-        wcscat(PathBuffer, L"\\");
-
-    wcscat(PathBuffer, InstallDir);
-    RtlCreateUnicodeString(&DestinationPath, PathBuffer);
-
-    /* Create 'DestinationArcPath' */
-    RtlFreeUnicodeString(&DestinationArcPath);
-    swprintf(PathBuffer,
-             L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
-             DiskEntry->BiosDiskNumber,
-             PartEntry->PartitionNumber);
-
-    if (InstallDir[0] != L'\\')
-        wcscat(PathBuffer, L"\\");
-
-    wcscat(PathBuffer, InstallDir);
-    RtlCreateUnicodeString(&DestinationArcPath, PathBuffer);
+    Status = InitDestinationPaths(&USetupData, InstallDir, DiskEntry, PartEntry);
+    // TODO: Check Status
+    UNREFERENCED_PARAMETER(Status);
+
+    /* Initialize DestinationDriveLetter */
+    DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
 }
 
 
-/*
- * Displays the InstallDirectoryPage.
- *
- * Next pages:
- *  PrepareCopyPage (As the direct result of InstallDirectoryPage1)
- *  QuitPage
- *
- * RETURNS
- *   Number of the next page.
- */
-static PAGE_NUMBER
-InstallDirectoryPage(PINPUT_RECORD Ir)
+static BOOLEAN
+IsValidPath(
+    IN PCWSTR InstallDir)
 {
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-    WCHAR InstallDir[51];
-    WCHAR c;
-    ULONG Length, Pos;
+    UINT i, Length;
 
-    /* We do not need the filesystem list any more */
-    if (FileSystemList != NULL)
-    {
-        DestroyFileSystemList(FileSystemList);
+    Length = wcslen(InstallDir);
+
+    // TODO: Add check for 8.3 too.
+
+    /* Path must be at least 2 characters long */
+//    if (Length < 2)
+//        return FALSE;
+
+    /* Path must start with a backslash */
+//    if (InstallDir[0] != L'\\')
+//        return FALSE;
+
+    /* Path must not end with a backslash */
+    if (InstallDir[Length - 1] == L'\\')
+        return FALSE;
+
+    /* Path must not contain whitespace characters */
+    for (i = 0; i < Length; i++)
+    {
+        if (iswspace(InstallDir[i]))
+            return FALSE;
+    }
+
+    /* Path component must not end with a dot */
+    for (i = 0; i < Length; i++)
+    {
+        if (InstallDir[i] == L'\\' && i > 0)
+        {
+            if (InstallDir[i - 1] == L'.')
+                return FALSE;
+        }
+    }
+
+    if (InstallDir[Length - 1] == L'.')
+        return FALSE;
+
+    return TRUE;
+}
+
+
+/*
+ * Displays the InstallDirectoryPage.
+ *
+ * Next pages:
+ *  PrepareCopyPage
+ *  QuitPage
+ *
+ * RETURNS
+ *   Number of the next page.
+ */
+static PAGE_NUMBER
+InstallDirectoryPage(PINPUT_RECORD Ir)
+{
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    WCHAR InstallDir[MAX_PATH];
+    WCHAR c;
+    ULONG Length, Pos;
+
+    /* We do not need the filesystem list anymore */
+    if (FileSystemList != NULL)
+    {
+        DestroyFileSystemList(FileSystemList);
         FileSystemList = NULL;
     }
 
@@ -3336,29 +3302,50 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
     DiskEntry = PartitionList->CurrentDisk;
     PartEntry = PartitionList->CurrentPartition;
 
-    if (IsUnattendedSetup)
-    {
-        if (!IsValidPath(UnattendInstallationDirectory))
-        {
-            /* FIXME: Log the error? */
-            return QUIT_PAGE;
-        }
+    // if (IsUnattendedSetup)
+    if (RepairUpdateFlag)
+        wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
+    else if (USetupData.InstallationDirectory[0])
+        wcscpy(InstallDir, USetupData.InstallationDirectory);
+    else
+        wcscpy(InstallDir, L"\\ReactOS");
 
-        BuildInstallPaths(UnattendInstallationDirectory,
+    /*
+     * Check the validity of the predefined 'InstallDir'. If we are either
+     * in unattended setup or in update/repair mode, and the installation path
+     * is valid, just perform the installation. Otherwise (either in the case
+     * of an invalid path, or we are in regular setup), display the UI and allow
+     * the user to specify a new installation path.
+     */
+    if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
+    {
+        BuildInstallPaths(InstallDir,
                           DiskEntry,
                           PartEntry);
 
+        /*
+         * Check whether the user attempts to install ReactOS within the
+         * installation source directory, or in a subdirectory thereof.
+         * If so, fail with an error.
+         */
+        if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
+        {
+            PopupError("You cannot install ReactOS within the installation source directory!",
+                       MUIGetString(STRING_CONTINUE),
+                       Ir, POPUP_WAIT_ENTER);
+            return INSTALL_DIRECTORY_PAGE;
+        }
+
         return PREPARE_COPY_PAGE;
     }
 
-    wcscpy(InstallDir, L"\\ReactOS");
-
     Length = wcslen(InstallDir);
     Pos = Length;
+
+    MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
     CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
     CONSOLE_SetCursorXY(8 + Pos, 11);
     CONSOLE_SetCursorType(TRUE, TRUE);
-    MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
 
     while (TRUE)
     {
@@ -3369,7 +3356,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
         {
             CONSOLE_SetCursorType(TRUE, FALSE);
 
-            if (ConfirmQuit(Ir) != FALSE)
+            if (ConfirmQuit(Ir))
                 return QUIT_PAGE;
 
             CONSOLE_SetCursorType(TRUE, TRUE);
@@ -3438,6 +3425,19 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
                               DiskEntry,
                               PartEntry);
 
+            /*
+             * Check whether the user attempts to install ReactOS within the
+             * installation source directory, or in a subdirectory thereof.
+             * If so, fail with an error.
+             */
+            if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
+            {
+                PopupError("You cannot install ReactOS within the installation source directory!",
+                           MUIGetString(STRING_CONTINUE),
+                           Ir, POPUP_WAIT_ENTER);
+                return INSTALL_DIRECTORY_PAGE;
+            }
+
             return PREPARE_COPY_PAGE;
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
@@ -3496,19 +3496,23 @@ AddSectionToCopyQueueCab(HINF InfFile,
     PWCHAR FileKeyValue;
     PWCHAR DirKeyValue;
     PWCHAR TargetFileName;
+    WCHAR FileDstPath[MAX_PATH];
+
+    /*
+     * This code enumerates the list of files in reactos.dff / reactos.inf
+     * that need to be extracted from reactos.cab and be installed in their
+     * respective directories.
+     */
 
     /* Search for the SectionName section */
     if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
     {
-        char Buffer[128];
-        sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
-        PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
+        MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, SectionName);
         return FALSE;
     }
 
     /*
-     * Enumerate the files in the section
-     * and add them to the file queue.
+     * Enumerate the files in the section and add them to the file queue.
      */
     do
     {
@@ -3531,27 +3535,72 @@ AddSectionToCopyQueueCab(HINF InfFile,
         {
             /* FIXME: Handle error! */
             DPRINT1("SetupFindFirstLine() failed\n");
+            INF_FreeData(FileKeyName);
+            INF_FreeData(FileKeyValue);
+            INF_FreeData(TargetFileName);
             break;
         }
 
+        INF_FreeData(FileKeyValue);
+
         if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
+            INF_FreeData(FileKeyName);
+            INF_FreeData(TargetFileName);
             break;
         }
 
-        if (!SetupQueueCopy(SetupFileQueue,
+#if 1 // HACK moved! (r66604)
+        {
+        ULONG Length = wcslen(DirKeyValue);
+        if ((Length > 0) && (DirKeyValue[Length - 1] == L'\\'))
+            Length--;
+        DirKeyValue[Length] = UNICODE_NULL;
+        }
+
+        /* Build the full target path */
+        RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath),
+                          USetupData.DestinationRootPath.Buffer);
+        if (DirKeyValue[0] == UNICODE_NULL)
+        {
+            /* Installation path */
+
+            /* Add the installation path */
+            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, USetupData.InstallPath.Buffer);
+        }
+        else if (DirKeyValue[0] == L'\\')
+        {
+            /* Absolute path */
+            // if (DirKeyValue[1] != UNICODE_NULL)
+                ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, DirKeyValue);
+        }
+        else // if (DirKeyValue[0] != L'\\')
+        {
+            /* Path relative to the installation path */
+
+            /* Add the installation path */
+            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
+                        USetupData.InstallPath.Buffer, DirKeyValue);
+        }
+#endif
+
+        if (!SetupQueueCopy(USetupData.SetupFileQueue,
                             SourceCabinet,
-                            SourceRootPath.Buffer,
-                            SourceRootDir.Buffer,
+                            USetupData.SourceRootPath.Buffer,
+                            USetupData.SourceRootDir.Buffer,
                             FileKeyName,
-                            DirKeyValue,
+                            FileDstPath,
                             TargetFileName))
         {
             /* FIXME: Handle error! */
             DPRINT1("SetupQueueCopy() failed\n");
         }
+
+        INF_FreeData(FileKeyName);
+        INF_FreeData(TargetFileName);
+        INF_FreeData(DirKeyValue);
     } while (SetupFindNextLine(&FilesContext, &FilesContext));
 
     return TRUE;
@@ -3571,29 +3620,31 @@ AddSectionToCopyQueue(HINF InfFile,
     PWCHAR FileKeyValue;
     PWCHAR DirKeyValue;
     PWCHAR TargetFileName;
-    ULONG Length;
-    WCHAR CompleteOrigDirName[512];
+    WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
+    WCHAR FileDstPath[MAX_PATH];
 
     if (SourceCabinet)
         return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
 
+    /*
+     * This code enumerates the list of files in txtsetup.sif
+     * that need to be installed in their respective directories.
+     */
+
     /* Search for the SectionName section */
     if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
     {
-        char Buffer[128];
-        sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
-        PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
+        MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, SectionName);
         return FALSE;
     }
 
     /*
-     * Enumerate the files in the section
-     * and add them to the file queue.
+     * Enumerate the files in the section and add them to the file queue.
      */
     do
     {
-        /* Get source file name and target directory id */
-        if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
+        /* Get source file name */
+        if (!INF_GetDataField(&FilesContext, 0, &FileKeyName))
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
@@ -3605,6 +3656,7 @@ AddSectionToCopyQueue(HINF InfFile,
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
+            INF_FreeData(FileKeyName);
             break;
         }
 
@@ -3621,52 +3673,103 @@ AddSectionToCopyQueue(HINF InfFile,
         {
             /* FIXME: Handle error! */
             DPRINT1("SetupFindFirstLine() failed\n");
+            INF_FreeData(FileKeyName);
+            INF_FreeData(FileKeyValue);
+            INF_FreeData(TargetFileName);
             break;
         }
 
+        INF_FreeData(FileKeyValue);
+
         if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
+            INF_FreeData(FileKeyName);
+            INF_FreeData(TargetFileName);
             break;
         }
 
-        if ((DirKeyValue[0] == 0) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == 0))
+        if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
         {
             /* Installation path */
-            wcscpy(CompleteOrigDirName, SourceRootDir.Buffer);
+            DPRINT("InstallationPath: '%S'\n", DirKeyValue);
+
+            RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
+                              USetupData.SourceRootDir.Buffer);
+
+            DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
         }
         else if (DirKeyValue[0] == L'\\')
         {
             /* Absolute path */
-            wcscpy(CompleteOrigDirName, DirKeyValue);
+            DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
+
+            RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
+                              DirKeyValue);
+
+            DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName);
         }
         else // if (DirKeyValue[0] != L'\\')
         {
             /* Path relative to the installation path */
-            wcscpy(CompleteOrigDirName, SourceRootDir.Buffer);
-            wcscat(CompleteOrigDirName, L"\\");
-            wcscat(CompleteOrigDirName, DirKeyValue);
+            DPRINT("RelativePath: '%S'\n", DirKeyValue);
+
+            CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
+                         USetupData.SourceRootDir.Buffer, DirKeyValue);
+
+            DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
         }
 
-        /* Remove trailing backslash */
-        Length = wcslen(CompleteOrigDirName);
-        if ((Length > 0) && (CompleteOrigDirName[Length - 1] == L'\\'))
+#if 1 // HACK moved! (r66604)
         {
-            CompleteOrigDirName[Length - 1] = 0;
+        ULONG Length = wcslen(DirKeyValue);
+        if ((Length > 0) && (DirKeyValue[Length - 1] == L'\\'))
+            Length--;
+        DirKeyValue[Length] = UNICODE_NULL;
         }
 
-        if (!SetupQueueCopy(SetupFileQueue,
+        /* Build the full target path */
+        RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath),
+                          USetupData.DestinationRootPath.Buffer);
+        if (DirKeyValue[0] == UNICODE_NULL)
+        {
+            /* Installation path */
+
+            /* Add the installation path */
+            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, USetupData.InstallPath.Buffer);
+        }
+        else if (DirKeyValue[0] == L'\\')
+        {
+            /* Absolute path */
+            // if (DirKeyValue[1] != UNICODE_NULL)
+                ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, DirKeyValue);
+        }
+        else // if (DirKeyValue[0] != L'\\')
+        {
+            /* Path relative to the installation path */
+
+            /* Add the installation path */
+            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
+                        USetupData.InstallPath.Buffer, DirKeyValue);
+        }
+#endif
+
+        if (!SetupQueueCopy(USetupData.SetupFileQueue,
                             SourceCabinet,
-                            SourceRootPath.Buffer,
+                            USetupData.SourceRootPath.Buffer,
                             CompleteOrigDirName,
                             FileKeyName,
-                            DirKeyValue,
+                            FileDstPath,
                             TargetFileName))
         {
             /* FIXME: Handle error! */
             DPRINT1("SetupQueueCopy() failed\n");
         }
+
+        INF_FreeData(FileKeyName);
+        INF_FreeData(TargetFileName);
+        INF_FreeData(DirKeyValue);
     } while (SetupFindNextLine(&FilesContext, &FilesContext));
 
     return TRUE;
@@ -3678,26 +3781,25 @@ PrepareCopyPageInfFile(HINF InfFile,
                        PWCHAR SourceCabinet,
                        PINPUT_RECORD Ir)
 {
-    WCHAR PathBuffer[MAX_PATH];
+    NTSTATUS Status;
     INFCONTEXT DirContext;
     PWCHAR AdditionalSectionName = NULL;
     PWCHAR DirKeyValue;
-    ULONG Length;
-    NTSTATUS Status;
+    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 */
     if (SourceCabinet == NULL)
     {
-        if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
+        if (!ProcessComputerFiles(InfFile, USetupData.ComputerList, &AdditionalSectionName))
             return FALSE;
 
         if (AdditionalSectionName)
         {
-            if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &DestinationPath, Ir))
+            if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &USetupData.DestinationPath, Ir))
                 return FALSE;
         }
     }
@@ -3706,28 +3808,22 @@ PrepareCopyPageInfFile(HINF InfFile,
 
     /*
      * FIXME:
-     * - Install directories like '\reactos\test' are not handled yet.
-     * - Copying files to 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 '\' .
+     * 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 USetupData.DestinationPath specify just '\' .
      */
 
     /* Get destination path */
-    wcscpy(PathBuffer, DestinationPath.Buffer);
+    RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), USetupData.DestinationPath.Buffer);
 
-    /* Remove trailing backslash */
-    Length = wcslen(PathBuffer);
-    if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
-    {
-        PathBuffer[Length - 1] = 0;
-    }
+    DPRINT("FullPath(1): '%S'\n", PathBuffer);
 
     /* Create the install directory */
     Status = SetupCreateDirectory(PathBuffer);
     if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
     {
-        DPRINT1("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
+        DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
         MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
         return FALSE;
     }
@@ -3736,13 +3832,9 @@ PrepareCopyPageInfFile(HINF InfFile,
     if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
     {
         if (SourceCabinet)
-        {
-            MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER);
-        }
+            MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER, L"Directories");
         else
-        {
-            MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER);
-        }
+            MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, L"Directories");
 
         return FALSE;
     }
@@ -3756,35 +3848,30 @@ PrepareCopyPageInfFile(HINF InfFile,
             break;
         }
 
-        if ((DirKeyValue[0] == 0) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == 0))
+        if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
         {
             /* Installation path */
             DPRINT("InstallationPath: '%S'\n", DirKeyValue);
 
-            wcscpy(PathBuffer, DestinationPath.Buffer);
+            RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
+                              USetupData.DestinationPath.Buffer);
 
-            DPRINT("FullPath: '%S'\n", PathBuffer);
+            DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
         }
         else if (DirKeyValue[0] == L'\\')
         {
             /* Absolute path */
-            DPRINT("Absolute Path: '%S'\n", DirKeyValue);
+            DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
 
-            wcscpy(PathBuffer, DestinationRootPath.Buffer);
-            wcscat(PathBuffer, DirKeyValue);
+            CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
+                         USetupData.DestinationRootPath.Buffer, DirKeyValue);
 
-            /* Remove trailing backslash */
-            Length = wcslen(PathBuffer);
-            if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
-            {
-                PathBuffer[Length - 1] = 0;
-            }
-
-            DPRINT("FullPath: '%S'\n", PathBuffer);
+            DPRINT("AbsolutePath(2): '%S'\n", PathBuffer);
 
             Status = SetupCreateDirectory(PathBuffer);
             if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
             {
+                INF_FreeData(DirKeyValue);
                 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
                 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
                 return FALSE;
@@ -3795,27 +3882,22 @@ PrepareCopyPageInfFile(HINF InfFile,
             /* Path relative to the installation path */
             DPRINT("RelativePath: '%S'\n", DirKeyValue);
 
-            wcscpy(PathBuffer, DestinationPath.Buffer);
-            wcscat(PathBuffer, L"\\");
-            wcscat(PathBuffer, DirKeyValue);
+            CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
+                         USetupData.DestinationPath.Buffer, DirKeyValue);
 
-            /* Remove trailing backslash */
-            Length = wcslen(PathBuffer);
-            if ((Length > 0) && (PathBuffer[Length - 1] == L'\\'))
-            {
-                PathBuffer[Length - 1] = 0;
-            }
-
-            DPRINT("FullPath: '%S'\n", PathBuffer);
+            DPRINT("RelativePath(2): '%S'\n", PathBuffer);
 
             Status = SetupCreateDirectory(PathBuffer);
             if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
             {
+                INF_FreeData(DirKeyValue);
                 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
                 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
                 return FALSE;
             }
         }
+
+        INF_FreeData(DirKeyValue);
     } while (SetupFindNextLine(&DirContext, &DirContext));
 
     return TRUE;
@@ -3850,21 +3932,21 @@ PrepareCopyPage(PINPUT_RECORD Ir)
     MUIDisplayPage(PREPARE_COPY_PAGE);
 
     /* Create the file queue */
-    SetupFileQueue = SetupOpenFileQueue();
-    if (SetupFileQueue == NULL)
+    USetupData.SetupFileQueue = SetupOpenFileQueue();
+    if (USetupData.SetupFileQueue == NULL)
     {
         MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
 
-    if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
+    if (!PrepareCopyPageInfFile(USetupData.SetupInf, NULL, Ir))
     {
         /* FIXME: show an error dialog */
         return QUIT_PAGE;
     }
 
     /* Search for the 'Cabinets' section */
-    if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
+    if (!SetupFindFirstLineW(USetupData.SetupInf, L"Cabinets", NULL, &CabinetsContext))
     {
         return FILE_COPY_PAGE;
     }
@@ -3878,9 +3960,8 @@ PrepareCopyPage(PINPUT_RECORD Ir)
         if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
             break;
 
-        wcscpy(PathBuffer, SourcePath.Buffer);
-        wcscat(PathBuffer, L"\\");
-        wcscat(PathBuffer, KeyValue);
+        CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
+                     USetupData.SourcePath.Buffer, KeyValue);
 
         CabinetInitialize();
         CabinetSetEventHandlers(NULL, NULL, NULL);
@@ -3904,11 +3985,11 @@ PrepareCopyPage(PINPUT_RECORD Ir)
             return QUIT_PAGE;
         }
 
-        InfHandle = INF_OpenBufferedFileA((CHAR*) InfFileData,
+        InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData,
                                           InfFileSize,
-                                          (const CHAR*) NULL,
+                                          NULL,
                                           INF_STYLE_WIN4,
-                                          LanguageId,
+                                          USetupData.LanguageId,
                                           &ErrorLine);
 
         if (InfHandle == INVALID_HANDLE_VALUE)
@@ -3929,9 +4010,15 @@ PrepareCopyPage(PINPUT_RECORD Ir)
     return FILE_COPY_PAGE;
 }
 
+typedef struct _COPYCONTEXT
+{
+    ULONG TotalOperations;
+    ULONG CompletedOperations;
+    PPROGRESSBAR ProgressBar;
+    PPROGRESSBAR MemoryBars[4];
+} COPYCONTEXT, *PCOPYCONTEXT;
 
-VOID
-NTAPI
+static VOID
 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
                       IN BOOLEAN First)
 {
@@ -3958,7 +4045,6 @@ SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
     ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
 }
 
-
 static UINT
 CALLBACK
 FileCopyCallback(PVOID Context,
@@ -3966,26 +4052,78 @@ FileCopyCallback(PVOID Context,
                  UINT_PTR Param1,
                  UINT_PTR Param2)
 {
-    PCOPYCONTEXT CopyContext;
-
-    CopyContext = (PCOPYCONTEXT)Context;
+    PCOPYCONTEXT CopyContext = (PCOPYCONTEXT)Context;
+    PFILEPATHS_W FilePathInfo;
+    PCWSTR SrcFileName, DstFileName;
 
     switch (Notification)
     {
         case SPFILENOTIFY_STARTSUBQUEUE:
+        {
             CopyContext->TotalOperations = (ULONG)Param2;
+            CopyContext->CompletedOperations = 0;
             ProgressSetStepCount(CopyContext->ProgressBar,
                                  CopyContext->TotalOperations);
             SetupUpdateMemoryInfo(CopyContext, TRUE);
             break;
+        }
 
+        case SPFILENOTIFY_STARTDELETE:
+        case SPFILENOTIFY_STARTRENAME:
         case SPFILENOTIFY_STARTCOPY:
-            /* Display copy message */
-            CONSOLE_SetStatusText(MUIGetString(STRING_COPYING), (PWSTR)Param1);
+        {
+            FilePathInfo = (PFILEPATHS_W)Param1;
+
+            if (Notification == SPFILENOTIFY_STARTDELETE)
+            {
+                /* Display delete message */
+                ASSERT(Param2 == FILEOP_DELETE);
+
+                DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
+                if (DstFileName) ++DstFileName;
+                else DstFileName = FilePathInfo->Target;
+
+                CONSOLE_SetStatusText(MUIGetString(STRING_DELETING),
+                                      DstFileName);
+            }
+            else if (Notification == SPFILENOTIFY_STARTRENAME)
+            {
+                /* Display move/rename message */
+                ASSERT(Param2 == FILEOP_RENAME);
+
+                SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
+                if (SrcFileName) ++SrcFileName;
+                else SrcFileName = FilePathInfo->Source;
+
+                DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
+                if (DstFileName) ++DstFileName;
+                else DstFileName = FilePathInfo->Target;
+
+                // TODO: Determine whether using STRING_RENAMING or STRING_MOVING
+                CONSOLE_SetStatusText(MUIGetString(STRING_MOVING),
+                                      SrcFileName, DstFileName);
+            }
+            else if (Notification == SPFILENOTIFY_STARTCOPY)
+            {
+                /* Display copy message */
+                ASSERT(Param2 == FILEOP_COPY);
+
+                SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
+                if (SrcFileName) ++SrcFileName;
+                else SrcFileName = FilePathInfo->Source;
+
+                CONSOLE_SetStatusText(MUIGetString(STRING_COPYING),
+                                      SrcFileName);
+            }
+
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
+        }
 
+        case SPFILENOTIFY_ENDDELETE:
+        case SPFILENOTIFY_ENDRENAME:
         case SPFILENOTIFY_ENDCOPY:
+        {
             CopyContext->CompletedOperations++;
 
             /* SYSREG checkpoint */
@@ -3995,9 +4133,10 @@ FileCopyCallback(PVOID Context,
             ProgressNextStep(CopyContext->ProgressBar);
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
+        }
     }
 
-    return 0;
+    return FILEOP_DOIT;
 }
 
 
@@ -4014,18 +4153,15 @@ FileCopyCallback(PVOID Context,
  * RETURNS
  *   Number of the next page.
  */
-static
-PAGE_NUMBER
+static PAGE_NUMBER
 FileCopyPage(PINPUT_RECORD Ir)
 {
     COPYCONTEXT CopyContext;
-    unsigned int mem_bar_width;
+    UINT MemBarWidth;
 
     MUIDisplayPage(FILE_COPY_PAGE);
 
     /* Create context for the copy process */
-    CopyContext.DestinationRootPath = DestinationRootPath.Buffer;
-    CopyContext.InstallPath = InstallPath.Buffer;
     CopyContext.TotalOperations = 0;
     CopyContext.CompletedOperations = 0;
 
@@ -4040,13 +4176,13 @@ FileCopyPage(PINPUT_RECORD Ir)
                                                 MUIGetString(STRING_SETUPCOPYINGFILES));
 
     // fit memory bars to screen width, distribute them uniform
-    mem_bar_width = (xScreen - 26) / 5;
-    mem_bar_width -= mem_bar_width % 2;  // make even
+    MemBarWidth = (xScreen - 26) / 5;
+    MemBarWidth -= MemBarWidth % 2;  // make even
     /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
     /* Create the paged pool progress bar */
     CopyContext.MemoryBars[0] = CreateProgressBar(13,
                                                   40,
-                                                  13 + mem_bar_width,
+                                                  13 + MemBarWidth,
                                                   43,
                                                   13,
                                                   44,
@@ -4054,43 +4190,77 @@ FileCopyPage(PINPUT_RECORD Ir)
                                                   "Kernel Pool");
 
     /* Create the non paged pool progress bar */
-    CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (mem_bar_width / 2),
+    CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (MemBarWidth / 2),
                                                   40,
-                                                  (xScreen / 2) + (mem_bar_width / 2),
+                                                  (xScreen / 2) + (MemBarWidth / 2),
                                                   43,
-                                                  (xScreen / 2)- (mem_bar_width / 2),
+                                                  (xScreen / 2)- (MemBarWidth / 2),
                                                   44,
                                                   FALSE,
                                                   "Kernel Cache");
 
     /* Create the global memory progress bar */
-    CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - mem_bar_width,
+    CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - MemBarWidth,
                                                   40,
                                                   xScreen - 13,
                                                   43,
-                                                  xScreen - 13 - mem_bar_width,
+                                                  xScreen - 13 - MemBarWidth,
                                                   44,
                                                   FALSE,
                                                   "Free Memory");
 
     /* Do the file copying */
     SetupCommitFileQueueW(NULL,
-                          SetupFileQueue,
+                          USetupData.SetupFileQueue,
                           FileCopyCallback,
                           &CopyContext);
 
     /* If we get here, we're done, so cleanup the queue and progress bar */
-    SetupCloseFileQueue(SetupFileQueue);
+    SetupCloseFileQueue(USetupData.SetupFileQueue);
     DestroyProgressBar(CopyContext.ProgressBar);
     DestroyProgressBar(CopyContext.MemoryBars[0]);
     DestroyProgressBar(CopyContext.MemoryBars[1]);
     DestroyProgressBar(CopyContext.MemoryBars[2]);
 
+    /* Create the $winnt$.inf file */
+    InstallSetupInfFile(&USetupData);
+
     /* Go display the next page */
     return REGISTRY_PAGE;
 }
 
 
+static VOID
+__cdecl
+RegistryStatus(IN REGISTRY_STATUS RegStatus, ...)
+{
+    /* WARNING: Please keep this lookup table in sync with the resources! */
+    static const UINT StringIDs[] =
+    {
+        STRING_DONE,                    /* Success */
+        STRING_REGHIVEUPDATE,           /* RegHiveUpdate */
+        STRING_IMPORTFILE,              /* ImportRegHive */
+        STRING_DISPLAYSETTINGSUPDATE,   /* DisplaySettingsUpdate */
+        STRING_LOCALESETTINGSUPDATE,    /* LocaleSettingsUpdate */
+        STRING_ADDKBLAYOUTS,            /* KeybLayouts */
+        STRING_KEYBOARDSETTINGSUPDATE,  /* KeybSettingsUpdate */
+        STRING_CODEPAGEINFOUPDATE,      /* CodePageInfoUpdate */
+    };
+
+    va_list args;
+
+    if (RegStatus < ARRAYSIZE(StringIDs))
+    {
+        va_start(args, RegStatus);
+        CONSOLE_SetStatusTextV(MUIGetString(StringIDs[RegStatus]), args);
+        va_end(args);
+    }
+    else
+    {
+        CONSOLE_SetStatusText("Unknown status %d", RegStatus);
+    }
+}
+
 /*
  * Displays the RegistryPage.
  *
@@ -4100,11 +4270,7 @@ FileCopyPage(PINPUT_RECORD Ir)
  *  QuitPage
  *
  * SIDEEFFECTS
- *  Calls SetInstallPathValue
- *  Calls NtInitializeRegistry
- *  Calls ImportRegistryFile
- *  Calls SetDefaultPagefile
- *  Calls SetMountedDeviceValues
+ *  Calls UpdateRegistry
  *
  * RETURNS
  *   Number of the next page.
@@ -4112,141 +4278,30 @@ FileCopyPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 RegistryPage(PINPUT_RECORD Ir)
 {
-    INFCONTEXT InfContext;
-    PWSTR Action;
-    PWSTR File;
-    PWSTR Section;
-    BOOLEAN Delete;
-    NTSTATUS Status;
+    ULONG Error;
 
     MUIDisplayPage(REGISTRY_PAGE);
 
-    if (RepairUpdateFlag)
-    {
-        return SUCCESS_PAGE;
-    }
-
-    if (!SetInstallPathValue(&DestinationPath))
-    {
-        DPRINT1("SetInstallPathValue() failed\n");
-        MUIDisplayError(ERROR_INITIALIZE_REGISTRY, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Create the default hives */
-    Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("NtInitializeRegistry() failed (Status %lx)\n", Status);
-        MUIDisplayError(ERROR_CREATE_HIVE, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Update registry */
-    CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));
-
-    if (!SetupFindFirstLineW(SetupInf, L"HiveInfs.Install", NULL, &InfContext))
-    {
-        DPRINT1("SetupFindFirstLine() failed\n");
-        MUIDisplayError(ERROR_FIND_REGISTRY, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    do
-    {
-        INF_GetDataField(&InfContext, 0, &Action);
-        INF_GetDataField(&InfContext, 1, &File);
-        INF_GetDataField(&InfContext, 2, &Section);
-
-        DPRINT("Action: %S  File: %S  Section %S\n", Action, File, Section);
-
-        if (Action == NULL)
-            break; // Hackfix
-
-        if (!_wcsicmp(Action, L"AddReg"))
-        {
-            Delete = FALSE;
-        }
-        else if (!_wcsicmp(Action, L"DelReg"))
-        {
-            Delete = TRUE;
-        }
-        else
-        {
-            continue;
-        }
-
-        CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE), File);
-
-        if (!ImportRegistryFile(File, Section, LanguageId, Delete))
-        {
-            DPRINT1("Importing %S failed\n", File);
-
-            MUIDisplayError(ERROR_IMPORT_HIVE, Ir, POPUP_WAIT_ENTER);
-            return QUIT_PAGE;
-        }
-    } while (SetupFindNextLine(&InfContext, &InfContext));
-
-    /* Update display registry settings */
-    CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE));
-    if (!ProcessDisplayRegistry(SetupInf, DisplayList))
-    {
-        MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Set the locale */
-    CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE));
-    if (!ProcessLocaleRegistry(LanguageList))
-    {
-        MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Add keyboard layouts */
-    CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS));
-    if (!AddKeyboardLayouts())
-    {
-        MUIDisplayError(ERROR_ADDING_KBLAYOUTS, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    /* Set GeoID */
-
-    if (!SetGeoID(MUIGetGeoID()))
-    {
-        MUIDisplayError(ERROR_UPDATE_GEOID, Ir, POPUP_WAIT_ENTER);
+    Error = UpdateRegistry(USetupData.SetupInf,
+                           &USetupData,
+                           RepairUpdateFlag,
+                           PartitionList,
+                           DestinationDriveLetter,
+                           SelectedLanguageId,
+                           USetupData.DisplayList,
+                           USetupData.LayoutList,
+                           USetupData.LanguageList,
+                           RegistryStatus);
+    if (Error != ERROR_SUCCESS)
+    {
+        MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
-
-    if (!IsUnattendedSetup)
-    {
-        /* Update keyboard layout settings */
-        CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE));
-        if (!ProcessKeyboardLayoutRegistry(LayoutList))
-        {
-            MUIDisplayError(ERROR_UPDATE_KBSETTINGS, Ir, POPUP_WAIT_ENTER);
-            return QUIT_PAGE;
-        }
-    }
-
-    /* Add codepage information to registry */
-    CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE));
-    if (!AddCodePage())
+    else
     {
-        MUIDisplayError(ERROR_ADDING_CODEPAGE, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
+        CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
+        return BOOT_LOADER_PAGE;
     }
-
-    /* Set the default pagefile entry */
-    SetDefaultPagefile(DestinationDriveLetter);
-
-    /* Update the mounted devices list */
-    SetMountedDeviceValues(PartitionList);
-
-    CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
-
-    return BOOT_LOADER_PAGE;
 }
 
 
@@ -4262,8 +4317,7 @@ RegistryPage(PINPUT_RECORD Ir)
  *  QuitPage
  *
  * SIDEEFFECTS
- *  Calls SetInstallPathValue
- *  Calls NtInitializeRegistry
+ *  Calls RegInitializeRegistry
  *  Calls ImportRegistryFile
  *  Calls SetDefaultPagefile
  *  Calls SetMountedDeviceValues
@@ -4281,28 +4335,30 @@ BootLoaderPage(PINPUT_RECORD Ir)
 
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
-    RtlFreeUnicodeString(&SystemRootPath);
-    swprintf(PathBuffer,
-             L"\\Device\\Harddisk%lu\\Partition%lu",
-             PartitionList->SystemDisk->DiskNumber,
-             PartitionList->SystemPartition->PartitionNumber);
-    RtlCreateUnicodeString(&SystemRootPath, PathBuffer);
-    DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath);
+    RtlFreeUnicodeString(&USetupData.SystemRootPath);
+    RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+            L"\\Device\\Harddisk%lu\\Partition%lu\\",
+            PartitionList->SystemPartition->DiskEntry->DiskNumber,
+            PartitionList->SystemPartition->PartitionNumber);
+    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 */
+        if ((USetupData.MBRInstallType == 0) ||
+            (USetupData.MBRInstallType == 1))
         {
-            return SUCCESS_PAGE;
-        }
-        else if (UnattendMBRInstallType == 1) /* install on floppy */
-        {
-            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");
@@ -4330,9 +4386,9 @@ BootLoaderPage(PINPUT_RECORD Ir)
     }
     else if ((PartitionType == PARTITION_FAT_12) ||
              (PartitionType == PARTITION_FAT_16) ||
-             (PartitionType == PARTITION_HUGE) ||
+             (PartitionType == PARTITION_HUGE)   ||
              (PartitionType == PARTITION_XINT13) ||
-             (PartitionType == PARTITION_FAT32) ||
+             (PartitionType == PARTITION_FAT32)  ||
              (PartitionType == PARTITION_FAT32_XINT13))
     {
         DPRINT("Found FAT partition\n");
@@ -4345,15 +4401,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);
@@ -4369,11 +4431,11 @@ BootLoaderPage(PINPUT_RECORD Ir)
             CONSOLE_NormalTextXY(8, Line, 60, 1);
 
             Line++;
-            if (Line<12)
-                Line=15;
+            if (Line < 12)
+                Line = 15;
 
-            if (Line>15)
-                Line=12;
+            if (Line > 15)
+                Line = 12;
 
             CONSOLE_InvertTextXY(8, Line, 60, 1);
         }
@@ -4383,18 +4445,18 @@ BootLoaderPage(PINPUT_RECORD Ir)
             CONSOLE_NormalTextXY(8, Line, 60, 1);
 
             Line--;
-            if (Line<12)
-                Line=15;
+            if (Line < 12)
+                Line = 15;
 
-            if (Line>15)
-                Line=12;
+            if (Line > 15)
+                Line = 12;
 
             CONSOLE_InvertTextXY(8, Line, 60, 1);
         }
         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;
@@ -4403,25 +4465,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;
 }
 
@@ -4446,7 +4536,7 @@ BootLoaderFloppyPage(PINPUT_RECORD Ir)
 
     MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE);
 
-//  SetStatusText("   Please wait...");
+//  CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
     while (TRUE)
     {
@@ -4455,23 +4545,21 @@ 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;
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)    /* ENTER */
         {
-            if (DoesFileExist(NULL, L"\\Device\\Floppy0", L"\\") == FALSE)
-            {
-                MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
-                return BOOT_LOADER_FLOPPY_PAGE;
-            }
-
-            Status = InstallFatBootcodeToFloppy(&SourceRootPath, &DestinationArcPath);
+            Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath,
+                                                &USetupData.DestinationArcPath);
             if (!NT_SUCCESS(Status))
             {
-                /* Print error message */
+                if (Status == STATUS_DEVICE_NOT_READY)
+                    MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
+
+                /* TODO: Print error message */
                 return BOOT_LOADER_FLOPPY_PAGE;
             }
 
@@ -4499,15 +4587,12 @@ BootLoaderFloppyPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
 {
-    UCHAR PartitionType;
     NTSTATUS Status;
 
-    PartitionType = PartitionList->SystemPartition->PartitionType;
-
-    Status = InstallVBRToPartition(&SystemRootPath,
-                                   &SourceRootPath,
-                                   &DestinationArcPath,
-                                   PartitionType);
+    Status = InstallVBRToPartition(&USetupData.SystemRootPath,
+                                   &USetupData.SourceRootPath,
+                                   &USetupData.DestinationArcPath,
+                                   PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
         MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
@@ -4527,7 +4612,7 @@ BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
  *
  * SIDEEFFECTS
  *  Calls InstallVBRToPartition()
- *  CallsInstallMbrBootCodeToDisk()
+ *  Calls InstallMbrBootCodeToDisk()
  *
  * RETURNS
  *   Number of the next page.
@@ -4535,19 +4620,14 @@ BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
 {
-    UCHAR PartitionType;
     NTSTATUS Status;
     WCHAR DestinationDevicePathBuffer[MAX_PATH];
-    WCHAR SourceMbrPathBuffer[MAX_PATH];
-    WCHAR DstPath[MAX_PATH];
 
     /* Step 1: Write the VBR */
-    PartitionType = PartitionList->SystemPartition->PartitionType;
-
-    Status = InstallVBRToPartition(&SystemRootPath,
-                                   &SourceRootPath,
-                                   &DestinationArcPath,
-                                   PartitionType);
+    Status = InstallVBRToPartition(&USetupData.SystemRootPath,
+                                   &USetupData.SourceRootPath,
+                                   &USetupData.DestinationArcPath,
+                                   PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
         MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
@@ -4555,41 +4635,215 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
     }
 
     /* Step 2: Write the MBR */
-    swprintf(DestinationDevicePathBuffer,
-             L"\\Device\\Harddisk%d\\Partition0",
-             PartitionList->SystemDisk->DiskNumber);
+    RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
+            L"\\Device\\Harddisk%d\\Partition0",
+            PartitionList->SystemPartition->DiskEntry->DiskNumber);
+    Status = InstallMbrBootCodeToDisk(&USetupData.SystemRootPath,
+                                      &USetupData.SourceRootPath,
+                                      DestinationDevicePathBuffer);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status);
+        MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER);
+        return QUIT_PAGE;
+    }
+
+    return SUCCESS_PAGE;
+}
 
-    wcscpy(SourceMbrPathBuffer, SourceRootPath.Buffer);
-    wcscat(SourceMbrPathBuffer, L"\\loader\\dosmbr.bin");
 
-    if (IsThereAValidBootSector(DestinationDevicePathBuffer))
+/**
+ * @name ProgressTimeOutStringHandler
+ *
+ * Handles the generation (displaying) of the timeout
+ * countdown to the screen dynamically.
+ *
+ * @param   Bar
+ *     A pointer to a progress bar.
+ *
+ * @param   AlwaysUpdate
+ *     Constantly update the progress bar (boolean type).
+ *
+ * @param   Buffer
+ *     A pointer to a string buffer.
+ *
+ * @param   cchBufferSize
+ *     The buffer's size in number of characters.
+ *
+ * @return
+ *     TRUE or FALSE on function termination.
+ *
+ */
+static
+BOOLEAN NTAPI
+ProgressTimeOutStringHandler(
+    IN PPROGRESSBAR Bar,
+    IN BOOLEAN AlwaysUpdate,
+    OUT PSTR Buffer,
+    IN SIZE_T cchBufferSize)
+{
+    ULONG OldProgress = Bar->Progress;
+
+    if (Bar->StepCount == 0)
+    {
+        Bar->Progress = 0;
+    }
+    else
     {
-        /* Save current MBR */
-        wcscpy(DstPath, SystemRootPath.Buffer);
-        wcscat(DstPath, L"\\mbr.old");
+        Bar->Progress = Bar->StepCount - Bar->CurrentStep;
+    }
 
-        DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
-        Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
-            // Don't care if we succeeded or not saving the old MBR, just go ahead.
-        }
+    /* Build the progress string if it has changed */
+    if (Bar->ProgressFormatText &&
+        (AlwaysUpdate || (Bar->Progress != OldProgress)))
+    {
+        RtlStringCchPrintfA(Buffer, cchBufferSize,
+                            Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1);
+
+        return TRUE;
     }
 
-    DPRINT1("Install MBR bootcode: %S ==> %S\n",
-            SourceMbrPathBuffer, DestinationDevicePathBuffer);
-    Status = InstallMbrBootCodeToDisk(SourceMbrPathBuffer,
-                                      DestinationDevicePathBuffer);
-    if (!NT_SUCCESS(Status))
+    return FALSE;
+}
+
+/**
+ * @name ProgressCountdown
+ *
+ * Displays and draws a red-coloured progress bar with a countdown.
+ * When the timeout is reached, the flush page is displayed for reboot.
+ *
+ * @param   Ir
+ *     A pointer to an input keyboard record.
+ *
+ * @param   TimeOut
+ *     Initial countdown value in seconds.
+ *
+ * @return
+ *     Nothing.
+ *
+ */
+static VOID
+ProgressCountdown(
+    IN PINPUT_RECORD Ir,
+    IN LONG TimeOut)
+{
+    NTSTATUS Status;
+    ULONG StartTime, BarWidth, TimerDiv;
+    LONG TimeElapsed;
+    LONG TimerValue, OldTimerValue;
+    LARGE_INTEGER Timeout;
+    PPROGRESSBAR ProgressBar;
+    BOOLEAN RefreshProgress = TRUE;
+
+    /* Bail out if the timeout is already zero */
+    if (TimeOut <= 0)
+        return;
+
+    /* Create the timeout progress bar and set it up */
+    ProgressBar = CreateProgressBarEx(13,
+                                      26,
+                                      xScreen - 13,
+                                      yScreen - 20,
+                                      10,
+                                      24,
+                                      TRUE,
+                                      FOREGROUND_RED | BACKGROUND_BLUE,
+                                      0,
+                                      NULL,
+                                      MUIGetString(STRING_REBOOTPROGRESSBAR),
+                                      ProgressTimeOutStringHandler);
+
+    BarWidth = max(1, ProgressBar->Width);
+    TimerValue = TimeOut * BarWidth;
+    ProgressSetStepCount(ProgressBar, TimerValue);
+
+    StartTime = NtGetTickCount();
+    CONSOLE_Flush();
+
+    TimerDiv = 1000 / BarWidth;
+    TimerDiv = max(1, TimerDiv);
+    OldTimerValue = TimerValue;
+    while (TRUE)
     {
-        DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
-                Status);
-        MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
+        /* Decrease the timer */
+
+        /*
+         * Compute how much time the previous operations took.
+         * This allows us in particular to take account for any time
+         * elapsed if something slowed down.
+         */
+        TimeElapsed = NtGetTickCount() - StartTime;
+        if (TimeElapsed >= TimerDiv)
+        {
+            /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
+            TimeElapsed /= TimerDiv;
+            StartTime += (TimerDiv * TimeElapsed);
+
+            if (TimeElapsed <= TimerValue)
+                TimerValue -= TimeElapsed;
+            else
+                TimerValue = 0;
+
+            RefreshProgress = TRUE;
+        }
+
+        if (RefreshProgress)
+        {
+            ProgressSetStep(ProgressBar, OldTimerValue - TimerValue);
+            RefreshProgress = FALSE;
+        }
+
+        /* Stop when the timer reaches zero */
+        if (TimerValue <= 0)
+            break;
+
+        /* Check for user key presses */
+
+        /*
+         * If the timer is used, use a passive wait of maximum 1 second
+         * while monitoring for incoming console input events, so that
+         * we are still able to display the timing count.
+         */
+
+        /* Wait a maximum of 1 second for input events */
+        TimeElapsed = NtGetTickCount() - StartTime;
+        if (TimeElapsed < TimerDiv)
+        {
+            /* Convert the time to NT Format */
+            Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL;
+            Status = NtWaitForSingleObject(StdInput, FALSE, &Timeout);
+        }
+        else
+        {
+            Status = STATUS_TIMEOUT;
+        }
+
+        /* Check whether the input event has been signaled, or a timeout happened */
+        if (Status == STATUS_TIMEOUT)
+        {
+            continue;
+        }
+        if (Status != STATUS_WAIT_0)
+        {
+            /* An error happened, bail out */
+            DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status);
+            break;
+        }
+
+        /* Check for an ENTER key press */
+        while (CONSOLE_ConInKeyPeek(Ir))
+        {
+            if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
+            {
+                /* Found it, stop waiting */
+                goto Exit;
+            }
+        }
     }
 
-    return SUCCESS_PAGE;
+Exit:
+    /* Destroy the progress bar and quit */
+    DestroyProgressBar(ProgressBar);
 }
 
 
@@ -4610,65 +4864,35 @@ QuitPage(PINPUT_RECORD Ir)
 {
     MUIDisplayPage(QUIT_PAGE);
 
-    /* Destroy partition list */
+    /* Destroy the NTOS installations list */
+    if (NtOsInstallsList != NULL)
+    {
+        DestroyGenericList(NtOsInstallsList, TRUE);
+        NtOsInstallsList = NULL;
+    }
+
+    /* Destroy the partition list */
     if (PartitionList != NULL)
     {
         DestroyPartitionList(PartitionList);
         PartitionList = NULL;
     }
 
-    /* Destroy filesystem list */
+    TempPartition = NULL;
+    FormatState = Start;
+
+    /* Destroy the filesystem list */
     if (FileSystemList != NULL)
     {
         DestroyFileSystemList(FileSystemList);
         FileSystemList = NULL;
     }
 
-    /* Destroy computer settings list */
-    if (ComputerList != NULL)
-    {
-        DestroyGenericList(ComputerList, TRUE);
-        ComputerList = NULL;
-    }
-
-    /* Destroy display settings list */
-    if (DisplayList != NULL)
-    {
-        DestroyGenericList(DisplayList, TRUE);
-        DisplayList = NULL;
-    }
-
-    /* Destroy keyboard settings list */
-    if (KeyboardList != NULL)
-    {
-        DestroyGenericList(KeyboardList, TRUE);
-        KeyboardList = NULL;
-    }
-
-    /* Destroy keyboard layout list */
-    if (LayoutList != NULL)
-    {
-        DestroyGenericList(LayoutList, TRUE);
-        LayoutList = NULL;
-    }
-
-    if (LanguageList != NULL)
-    {
-        DestroyGenericList(LanguageList, FALSE);
-        LanguageList = NULL;
-    }
-
     CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2));
 
-    while (TRUE)
-    {
-        CONSOLE_ConInKey(Ir);
-
-        if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
-        {
-            return FLUSH_PAGE;
-        }
-    }
+    /* Wait for maximum 15 seconds or an ENTER key before quitting */
+    ProgressCountdown(Ir, 15);
+    return FLUSH_PAGE;
 }
 
 
@@ -4690,19 +4914,11 @@ SuccessPage(PINPUT_RECORD Ir)
     MUIDisplayPage(SUCCESS_PAGE);
 
     if (IsUnattendedSetup)
-    {
         return FLUSH_PAGE;
-    }
-
-    while (TRUE)
-    {
-        CONSOLE_ConInKey(Ir);
 
-        if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
-        {
-            return FLUSH_PAGE;
-        }
-    }
+    /* Wait for maximum 15 seconds or an ENTER key before quitting */
+    ProgressCountdown(Ir, 15);
+    return FLUSH_PAGE;
 }
 
 
@@ -4730,17 +4946,22 @@ PnpEventThread(IN LPVOID lpParameter);
 /*
  * The start routine and page management
  */
-VOID
+NTSTATUS
 RunUSetup(VOID)
 {
+    NTSTATUS Status;
     INPUT_RECORD Ir;
     PAGE_NUMBER Page;
-    LARGE_INTEGER Time;
-    NTSTATUS Status;
     BOOLEAN Old;
 
-    NtQuerySystemTime(&Time);
+    InfSetHeap(ProcessHeap);
+
+    /* Tell the Cm this is a setup boot, and it has to behave accordingly */
+    Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
+    if (!NT_SUCCESS(Status))
+        DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status);
 
+    /* Create the PnP thread in suspended state */
     Status = RtlCreateUserThread(NtCurrentProcess(),
                                  NULL,
                                  TRUE,
@@ -4748,11 +4969,11 @@ RunUSetup(VOID)
                                  0,
                                  0,
                                  PnpEventThread,
-                                 &SetupInf,
+                                 &USetupData.SetupInf,
                                  &hPnpThread,
                                  NULL);
     if (!NT_SUCCESS(Status))
-        hPnpThread = INVALID_HANDLE_VALUE;
+        hPnpThread = NULL;
 
     if (!CONSOLE_Init())
     {
@@ -4760,55 +4981,46 @@ RunUSetup(VOID)
         PrintString(MUIGetString(STRING_CONSOLEFAIL2));
         PrintString(MUIGetString(STRING_CONSOLEFAIL3));
 
-        /* Raise a hard error (crash the system/BSOD) */
-        NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
-                         0,0,0,0,0);
+        /* We failed to initialize the video, just quit the installer */
+        return STATUS_APP_INIT_FAILURE;
     }
 
-    /* Initialize global unicode strings */
-    RtlInitUnicodeString(&SourcePath, NULL);
-    RtlInitUnicodeString(&SourceRootPath, NULL);
-    RtlInitUnicodeString(&SourceRootDir, NULL);
-    RtlInitUnicodeString(&InstallPath, NULL);
-    RtlInitUnicodeString(&DestinationPath, NULL);
-    RtlInitUnicodeString(&DestinationArcPath, NULL);
-    RtlInitUnicodeString(&DestinationRootPath, NULL);
-    RtlInitUnicodeString(&SystemRootPath, NULL);
+    /* Initialize Setup, phase 0 */
+    InitializeSetup(&USetupData, 0);
 
     /* Hide the cursor */
     CONSOLE_SetCursorType(TRUE, FALSE);
 
-    Page = START_PAGE;
+    /* Global Initialization page */
+    CONSOLE_ClearScreen();
+    CONSOLE_Flush();
+    Page = SetupStartPage(&Ir);
+
     while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
     {
         CONSOLE_ClearScreen();
         CONSOLE_Flush();
 
-        //CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
-        //CONSOLE_Flush();
+        // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
+        // CONSOLE_Flush();
 
         switch (Page)
         {
-            /* Start page */
-            case START_PAGE:
-                Page = SetupStartPage(&Ir);
-                break;
-
             /* Language page */
             case LANGUAGE_PAGE:
                 Page = LanguagePage(&Ir);
                 break;
 
+            /* Welcome page */
+            case WELCOME_PAGE:
+                Page = WelcomePage(&Ir);
+                break;
+
             /* License page */
             case LICENSE_PAGE:
                 Page = LicensePage(&Ir);
                 break;
 
-            /* Intro page */
-            case INTRO_PAGE:
-                Page = IntroPage(&Ir);
-                break;
-
             /* Install pages */
             case INSTALL_INTRO_PAGE:
                 Page = InstallIntroPage(&Ir);
@@ -4818,9 +5030,7 @@ RunUSetup(VOID)
             case SCSI_CONTROLLER_PAGE:
                 Page = ScsiControllerPage(&Ir);
                 break;
-#endif
 
-#if 0
             case OEM_DRIVER_PAGE:
                 Page = OemDriverPage(&Ir);
                 break;
@@ -4875,11 +5085,11 @@ RunUSetup(VOID)
                 break;
 
             case FORMAT_PARTITION_PAGE:
-                Page = (PAGE_NUMBER) FormatPartitionPage(&Ir);
+                Page = FormatPartitionPage(&Ir);
                 break;
 
             case CHECK_FILE_SYSTEM_PAGE:
-                Page = (PAGE_NUMBER) CheckFileSystemPage(&Ir);
+                Page = CheckFileSystemPage(&Ir);
                 break;
 
             case INSTALL_DIRECTORY_PAGE:
@@ -4919,6 +5129,10 @@ RunUSetup(VOID)
                 Page = RepairIntroPage(&Ir);
                 break;
 
+            case UPGRADE_REPAIR_PAGE:
+                Page = UpgradeRepairPage(&Ir);
+                break;
+
             case SUCCESS_PAGE:
                 Page = SuccessPage(&Ir);
                 break;
@@ -4937,31 +5151,58 @@ RunUSetup(VOID)
         }
     }
 
+    /* Setup has finished */
+    FinishSetup(&USetupData);
+
     if (Page == RECOVERY_PAGE)
         RecoveryConsole();
 
     FreeConsole();
 
-    /* Avoid bugcheck */
-    Time.QuadPart += 50000000;
-    NtDelayExecution(FALSE, &Time);
-
     /* Reboot */
     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
     NtShutdownSystem(ShutdownReboot);
     RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
-    NtTerminateProcess(NtCurrentProcess(), 0);
+
+    return STATUS_SUCCESS;
 }
 
 
 VOID NTAPI
 NtProcessStartup(PPEB Peb)
 {
+    NTSTATUS Status;
+    LARGE_INTEGER Time;
+
     RtlNormalizeProcessParams(Peb->ProcessParameters);
 
     ProcessHeap = Peb->ProcessHeap;
-    InfSetHeap(ProcessHeap);
-    RunUSetup();
+
+    NtQuerySystemTime(&Time);
+
+    Status = RunUSetup();
+
+    if (NT_SUCCESS(Status))
+    {
+        /*
+         * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
+         * a protective waiting.
+         * This wait is needed because, since we are started as SMSS.EXE,
+         * the NT kernel explicitly waits 5 seconds for the initial process
+         * SMSS.EXE to initialize (as a protective measure), and otherwise
+         * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
+         */
+        Time.QuadPart += 50000000;
+        NtDelayExecution(FALSE, &Time);
+    }
+    else
+    {
+        /* The installer failed to start: raise a hard error (crash the system/BSOD) */
+        Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
+                                  0, 0, NULL, 0, NULL);
+    }
+
+    NtTerminateProcess(NtCurrentProcess(), Status);
 }
 
 /* EOF */