[USETUP] Display the chosen filesystem name in case of bootcode installation failure.
[reactos.git] / base / setup / usetup / usetup.c
index af5708f..f16d651 100644 (file)
@@ -21,7 +21,7 @@
  * PROJECT:         ReactOS text-mode setup
  * FILE:            base/setup/usetup/usetup.c
  * PURPOSE:         Text-mode setup
- * PROGRAMMER     Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
  *                  HervĂ© Poussineau (hpoussin@reactos.org)
  */
 
 #include "chkdsk.h"
 #include "cmdcons.h"
 #include "format.h"
-#include "settings.h"
 
 #define NDEBUG
 #include <debug.h>
 
-// HACK!
-#include <strsafe.h>
-
 
 /* GLOBALS & LOCALS *********************************************************/
 
 HANDLE ProcessHeap;
-
 BOOLEAN IsUnattendedSetup = FALSE;
-static USETUP_DATA USetupData;
 
-/*
- * NOTE: Technically only used for the COPYCONTEXT InstallPath member
- * for the filequeue functionality.
- */
-static UNICODE_STRING InstallPath;
+static USETUP_DATA USetupData;
 
 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
 static WCHAR DestinationDriveLetter;
@@ -60,7 +50,7 @@ static WCHAR DestinationDriveLetter;
 
 /* OTHER Stuff *****/
 
-PWCHAR SelectedLanguageId;
+PCWSTR SelectedLanguageId;
 static WCHAR DefaultLanguage[20];   // Copy of string inside LanguageList
 static WCHAR DefaultKBLayout[20];   // Copy of string inside KeyboardList
 
@@ -75,19 +65,9 @@ static FORMATMACHINESTATE FormatState = Start;
 
 /*****************************************************/
 
-static HINF SetupInf;
-
-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;
-
 
 /* FUNCTIONS ****************************************************************/
 
@@ -404,39 +384,77 @@ static VOID
 UpdateKBLayout(VOID)
 {
     PGENERIC_LIST_ENTRY ListEntry;
-    LPCWSTR pszNewLayout;
+    PCWSTR pszNewLayout;
 
-    pszNewLayout = MUIDefaultKeyboardLayout();
+    pszNewLayout = MUIDefaultKeyboardLayout(SelectedLanguageId);
 
-    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: Handle error! */
             return;
         }
     }
 
-    ListEntry = GetFirstListEntry(LayoutList);
-
     /* Search for default layout (if provided) */
     if (pszNewLayout != NULL)
     {
-        while (ListEntry != NULL)
+        for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
+             ListEntry = GetNextListEntry(ListEntry))
         {
-            if (!wcscmp(pszNewLayout, GetListEntryUserData(ListEntry)))
+            if (!wcscmp(pszNewLayout, ((PGENENTRY)GetListEntryData(ListEntry))->Id))
             {
-                SetCurrentListEntry(LayoutList, ListEntry);
+                SetCurrentListEntry(USetupData.LayoutList, ListEntry);
                 break;
             }
-
-            ListEntry = GetNextListEntry(ListEntry);
         }
     }
 }
 
 
+static NTSTATUS
+NTAPI
+GetSettingDescription(
+    IN PGENERIC_LIST_ENTRY Entry,
+    OUT PSTR Buffer,
+    IN SIZE_T cchBufferSize)
+{
+    return RtlStringCchPrintfA(Buffer, cchBufferSize, "%S",
+                               ((PGENENTRY)GetListEntryData(Entry))->Value);
+}
+
+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 (PartEntry && PartEntry->DriveLetter)
+    {
+        /* We have retrieved a partition that is mounted */
+        return RtlStringCchPrintfA(Buffer, cchBufferSize,
+                                   "%C:%S  \"%S\"",
+                                   PartEntry->DriveLetter,
+                                   NtOsInstall->PathComponent,
+                                   NtOsInstall->InstallationName);
+    }
+    else
+    {
+        /* We failed somewhere, just show the NT path */
+        return RtlStringCchPrintfA(Buffer, cchBufferSize,
+                                   "%wZ  \"%S\"",
+                                   &NtOsInstall->SystemNtPath,
+                                   NtOsInstall->InstallationName);
+    }
+}
+
+
 /*
  * Displays the LanguagePage.
  *
@@ -453,38 +471,40 @@ static PAGE_NUMBER
 LanguagePage(PINPUT_RECORD Ir)
 {
     GENERIC_LIST_UI ListUi;
-    PWCHAR NewLanguageId;
+    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 WELCOME_PAGE;
         }
     }
 
-    /* Load the font */
-    USetupData.LanguageId = 0;
     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)
     {
         USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
         return WELCOME_PAGE;
     }
 
-    InitGenericListUi(&ListUi, LanguageList);
+    InitGenericListUi(&ListUi, USetupData.LanguageList, GetSettingDescription);
     DrawGenericList(&ListUi,
-                    2,
-                    18,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
@@ -530,7 +550,10 @@ LanguagePage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)  /* ENTER */
         {
-            SelectedLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
+            ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
+
+            SelectedLanguageId =
+                ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
 
             USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
 
@@ -553,9 +576,12 @@ LanguagePage(PINPUT_RECORD Ir)
 
         if (RefreshPage)
         {
-            NewLanguageId = (PWCHAR)GetListEntryUserData(GetCurrentListEntry(LanguageList));
+            ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
 
-            if (SelectedLanguageId != NewLanguageId)
+            NewLanguageId =
+                ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
+
+            if (wcscmp(SelectedLanguageId, NewLanguageId))
             {
                 /* Clear the language page */
                 MUIClearPage(LANGUAGE_PAGE);
@@ -590,7 +616,7 @@ LanguagePage(PINPUT_RECORD Ir)
  *  Init USetupData.SourcePath
  *  Init USetupData.SourceRootPath
  *  Init USetupData.SourceRootDir
- *  Init SetupInf
+ *  Init USetupData.SetupInf
  *  Init USetupData.RequiredPartitionDiskSpace
  *  Init IsUnattendedSetup
  *  If unattended, init *List and sets the Codepage
@@ -603,28 +629,14 @@ LanguagePage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 SetupStartPage(PINPUT_RECORD Ir)
 {
-    NTSTATUS Status;
     ULONG Error;
     PGENERIC_LIST_ENTRY ListEntry;
+    PCWSTR LocaleId;
 
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
-    /* Get the source path and source root path */
-    Status = GetSourcePaths(&USetupData.SourcePath,
-                            &USetupData.SourceRootPath,
-                            &USetupData.SourceRootDir);
-    if (!NT_SUCCESS(Status))
-    {
-        CONSOLE_PrintTextXY(6, 15, "GetSourcePaths() failed (Status 0x%08lx)", Status);
-        MUIDisplayError(ERROR_NO_SOURCE_DRIVE, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-    DPRINT1("SourcePath: '%wZ'\n", &USetupData.SourcePath);
-    DPRINT1("SourceRootPath: '%wZ'\n", &USetupData.SourceRootPath);
-    DPRINT1("SourceRootDir: '%wZ'\n", &USetupData.SourceRootDir);
-
-    /* Load 'txtsetup.sif' from the installation media */
-    Error = LoadSetupInf(&SetupInf, &USetupData);
+    /* Initialize Setup, phase 1 */
+    Error = InitializeSetup(&USetupData, 1);
     if (Error != ERROR_SUCCESS)
     {
         MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
@@ -643,42 +655,45 @@ SetupStartPage(PINPUT_RECORD Ir)
     if (IsUnattendedSetup)
     {
         // TODO: Read options from inf
-        ComputerList = CreateComputerTypeList(SetupInf);
-        DisplayList = CreateDisplayDriverList(SetupInf);
-        KeyboardList = CreateKeyboardDriverList(SetupInf);
-        LayoutList = CreateKeyboardLayoutList(SetupInf, DefaultKBLayout);
-        LanguageList = CreateLanguageList(SetupInf, DefaultLanguage);
+        /* 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, USetupData.LocaleID);
+        SelectedLanguageId = DefaultLanguage;
+        wcscpy(DefaultLanguage, USetupData.LocaleID);
         USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
 
+        USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
+
         /* first we hack LanguageList */
-        ListEntry = GetFirstListEntry(LanguageList);
-        while (ListEntry != NULL)
+        for (ListEntry = GetFirstListEntry(USetupData.LanguageList); ListEntry;
+             ListEntry = GetNextListEntry(ListEntry))
         {
-            if (!wcsicmp(USetupData.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(USetupData.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();
@@ -851,6 +866,11 @@ UpgradeRepairPage(PINPUT_RECORD Ir)
     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)
     {
         RepairUpdateFlag = FALSE;
@@ -862,14 +882,12 @@ UpgradeRepairPage(PINPUT_RECORD Ir)
 
     MUIDisplayPage(UPGRADE_REPAIR_PAGE);
 
-    InitGenericListUi(&ListUi, NtOsInstallsList);
+    InitGenericListUi(&ListUi, NtOsInstallsList, GetNTOSInstallationName);
     DrawGenericList(&ListUi,
                     2, 23,
                     xScreen - 3,
                     yScreen - 3);
 
-    SaveGenericListState(NtOsInstallsList);
-
     // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
     while (TRUE)
     {
@@ -901,7 +919,7 @@ UpgradeRepairPage(PINPUT_RECORD Ir)
             }
             case VK_ESCAPE: /* ESC */
             {
-                RestoreGenericListState(NtOsInstallsList);
+                RestoreGenericListUiState(&ListUi);
                 // return nextPage;    // prevPage;
 
                 // return INSTALL_INTRO_PAGE;
@@ -917,7 +935,11 @@ UpgradeRepairPage(PINPUT_RECORD Ir)
             if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U')  /* U */
             {
                 /* Retrieve the current installation */
-                CurrentInstallation = (PNTOS_INSTALLATION)GetListEntryUserData(GetCurrentListEntry(NtOsInstallsList));
+                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);
 
@@ -1078,10 +1100,10 @@ OemDriverPage(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.
@@ -1092,10 +1114,10 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
     static ULONG Line = 16;
 
     /* 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;
@@ -1103,10 +1125,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;
@@ -1114,10 +1136,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;
@@ -1125,10 +1147,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);
@@ -1144,10 +1166,10 @@ DeviceSettingsPage(PINPUT_RECORD Ir)
 
     MUIDisplayPage(DEVICE_SETTINGS_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)));
+    DrawGenericListCurrentItem(USetupData.ComputerList, GetSettingDescription, 25, 11);
+    DrawGenericListCurrentItem(USetupData.DisplayList , GetSettingDescription, 25, 12);
+    DrawGenericListCurrentItem(USetupData.KeyboardList, GetSettingDescription, 25, 13);
+    DrawGenericListCurrentItem(USetupData.LayoutList  , GetSettingDescription, 25, 14);
 
     CONSOLE_InvertTextXY(24, Line, 48, 1);
 
@@ -1258,7 +1280,7 @@ HandleGenericList(PGENERIC_LIST_UI ListUi,
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE))  /* ESC */
         {
-            RestoreGenericListState(ListUi->List);
+            RestoreGenericListUiState(ListUi);
             return nextPage;    // Use some "prevPage;" instead?
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
@@ -1290,15 +1312,12 @@ ComputerSettingsPage(PINPUT_RECORD Ir)
     GENERIC_LIST_UI ListUi;
     MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
 
-    InitGenericListUi(&ListUi, ComputerList);
+    InitGenericListUi(&ListUi, USetupData.ComputerList, GetSettingDescription);
     DrawGenericList(&ListUi,
-                    2,
-                    18,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
-    SaveGenericListState(ComputerList);
-
     return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
 }
 
@@ -1319,15 +1338,12 @@ DisplaySettingsPage(PINPUT_RECORD Ir)
     GENERIC_LIST_UI ListUi;
     MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
 
-    InitGenericListUi(&ListUi, DisplayList);
+    InitGenericListUi(&ListUi, USetupData.DisplayList, GetSettingDescription);
     DrawGenericList(&ListUi,
-                    2,
-                    18,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
-    SaveGenericListState(DisplayList);
-
     return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
 }
 
@@ -1348,15 +1364,12 @@ KeyboardSettingsPage(PINPUT_RECORD Ir)
     GENERIC_LIST_UI ListUi;
     MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
 
-    InitGenericListUi(&ListUi, KeyboardList);
+    InitGenericListUi(&ListUi, USetupData.KeyboardList, GetSettingDescription);
     DrawGenericList(&ListUi,
-                    2,
-                    18,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
-    SaveGenericListState(KeyboardList);
-
     return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
 }
 
@@ -1377,15 +1390,12 @@ LayoutSettingsPage(PINPUT_RECORD Ir)
     GENERIC_LIST_UI ListUi;
     MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
 
-    InitGenericListUi(&ListUi, LayoutList);
+    InitGenericListUi(&ListUi, USetupData.LayoutList, GetSettingDescription);
     DrawGenericList(&ListUi,
-                    2,
-                    18,
+                    2, 18,
                     xScreen - 3,
                     yScreen - 3);
 
-    SaveGenericListState(LayoutList);
-
     return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
 }
 
@@ -1662,12 +1672,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)
             {
@@ -2448,7 +2480,7 @@ DeletePartitionPage(PINPUT_RECORD Ir)
     {
         CONSOLE_PrintTextXY(6, 10,
                             MUIGetString(STRING_HDDINFOUNK2),
-                            (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                            (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
                             (PartEntry->DriveLetter == 0) ? '-' : ':',
                             PartEntry->PartitionType,
                             PartSize,
@@ -2458,7 +2490,7 @@ DeletePartitionPage(PINPUT_RECORD Ir)
     {
         CONSOLE_PrintTextXY(6, 10,
                             "   %c%c  %s    %I64u %s",
-                            (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                            (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
                             (PartEntry->DriveLetter == 0) ? '-' : ':',
                             PartTypeString,
                             PartSize,
@@ -2705,6 +2737,8 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                                        PartTypeString,
                                        ARRAYSIZE(PartTypeString));
 
+    MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
+
     if (PartEntry->AutoCreate)
     {
         CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
@@ -2761,7 +2795,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
         {
             CONSOLE_PrintTextXY(8, 10,
                                 MUIGetString(STRING_HDDINFOUNK4),
-                                (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                                (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
                                 (PartEntry->DriveLetter == 0) ? '-' : ':',
                                 PartEntry->PartitionType,
                                 PartSize,
@@ -2771,7 +2805,7 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
         {
             CONSOLE_PrintTextXY(8, 10,
                                 "%c%c  %s    %I64u %s",
-                                (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                                (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
                                 (PartEntry->DriveLetter == 0) ? '-' : ':',
                                 PartTypeString,
                                 PartSize,
@@ -2789,8 +2823,6 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                             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 */
@@ -2888,12 +2920,13 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 FormatPartitionPage(PINPUT_RECORD Ir)
 {
-    UNICODE_STRING PartitionRootPath;
-    WCHAR PathBuffer[MAX_PATH];
+    NTSTATUS Status;
     PDISKENTRY DiskEntry;
     PPARTENTRY PartEntry;
     PFILE_SYSTEM_ITEM SelectedFileSystem;
-    NTSTATUS Status;
+    UNICODE_STRING PartitionRootPath;
+    WCHAR PathBuffer[MAX_PATH];
+    CHAR Buffer[MAX_PATH];
 
 #ifndef NDEBUG
     ULONG Line;
@@ -2977,7 +3010,7 @@ FormatPartitionPage(PINPUT_RECORD Ir)
             }
 
             /* Set PartitionRootPath */
-            StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+            RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
                     L"\\Device\\Harddisk%lu\\Partition%lu",
                     DiskEntry->DiskNumber,
                     PartEntry->PartitionNumber);
@@ -2989,7 +3022,38 @@ FormatPartitionPage(PINPUT_RECORD Ir)
             {
                 Status = FormatPartition(&PartitionRootPath,
                                          SelectedFileSystem);
-                if (!NT_SUCCESS(Status))
+                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);
@@ -3030,13 +3094,13 @@ FormatPartitionPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 CheckFileSystemPage(PINPUT_RECORD Ir)
 {
+    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)
     {
@@ -3050,7 +3114,7 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
     }
 
     /* Set PartitionRootPath */
-    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+    RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
             L"\\Device\\Harddisk%lu\\Partition%lu",
             DiskEntry->DiskNumber,
             PartEntry->PartitionNumber);
@@ -3072,7 +3136,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"
@@ -3104,26 +3169,22 @@ 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;
 }
 
 
@@ -3132,41 +3193,60 @@ BuildInstallPaths(PWSTR InstallDir,
                   PDISKENTRY DiskEntry,
                   PPARTENTRY PartEntry)
 {
-    WCHAR PathBuffer[MAX_PATH];
-
-/** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
-    /* Create 'InstallPath' string */
-    RtlFreeUnicodeString(&InstallPath);
-    RtlCreateUnicodeString(&InstallPath, InstallDir);
+    NTSTATUS Status;
 
-    /* Create 'USetupData.DestinationRootPath' string */
-    RtlFreeUnicodeString(&USetupData.DestinationRootPath);
-    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
-            L"\\Device\\Harddisk%lu\\Partition%lu\\",
-            DiskEntry->DiskNumber,
-            PartEntry->PartitionNumber);
-    RtlCreateUnicodeString(&USetupData.DestinationRootPath, PathBuffer);
-    DPRINT("DestinationRootPath: %wZ\n", &USetupData.DestinationRootPath);
-
-/** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
-    /* Create 'USetupData.DestinationPath' string */
-    RtlFreeUnicodeString(&USetupData.DestinationPath);
-    CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                 USetupData.DestinationRootPath.Buffer, InstallDir);
-    RtlCreateUnicodeString(&USetupData.DestinationPath, PathBuffer);
-
-/** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
-    /* Create 'USetupData.DestinationArcPath' */
-    RtlFreeUnicodeString(&USetupData.DestinationArcPath);
-    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
-            L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
-            DiskEntry->BiosDiskNumber,
-            PartEntry->PartitionNumber);
-    ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallDir);
-    RtlCreateUnicodeString(&USetupData.DestinationArcPath, PathBuffer);
+    Status = InitDestinationPaths(&USetupData, InstallDir, DiskEntry, PartEntry);
+    // TODO: Check Status
+    UNREFERENCED_PARAMETER(Status);
 
     /* Initialize DestinationDriveLetter */
-    DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
+    DestinationDriveLetter = PartEntry->DriveLetter;
+}
+
+
+static BOOLEAN
+IsValidPath(
+    IN PCWSTR InstallDir)
+{
+    UINT i, Length;
+
+    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;
 }
 
 
@@ -3228,6 +3308,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;
     }
 
@@ -3317,6 +3410,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 */
@@ -3362,365 +3468,28 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
 }
 
 
-static BOOLEAN
-AddSectionToCopyQueueCab(HINF InfFile,
-                         PWCHAR SectionName,
-                         PWCHAR SourceCabinet,
-                         PCUNICODE_STRING DestinationPath,
-                         PINPUT_RECORD Ir)
-{
-    INFCONTEXT FilesContext;
-    INFCONTEXT DirContext;
-    PWCHAR FileKeyName;
-    PWCHAR FileKeyValue;
-    PWCHAR DirKeyValue;
-    PWCHAR TargetFileName;
-
-    /*
-     * 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);
-        return FALSE;
-    }
-
-    /*
-     * 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))
-        {
-            /* FIXME: Handle error! */
-            DPRINT1("INF_GetData() failed\n");
-            break;
-        }
-
-        /* Get optional target file name */
-        if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
-            TargetFileName = NULL;
-
-        DPRINT("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
-
-        /* Lookup target directory */
-        if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
-        {
-            /* 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,
-                            SourceCabinet,
-                            USetupData.SourceRootPath.Buffer,
-                            USetupData.SourceRootDir.Buffer,
-                            FileKeyName,
-                            DirKeyValue,
-                            TargetFileName))
-        {
-            /* FIXME: Handle error! */
-            DPRINT1("SetupQueueCopy() failed\n");
-        }
-
-        INF_FreeData(FileKeyName);
-        INF_FreeData(TargetFileName);
-        INF_FreeData(DirKeyValue);
-    } while (SetupFindNextLine(&FilesContext, &FilesContext));
-
-    return TRUE;
-}
-
-
-static BOOLEAN
-AddSectionToCopyQueue(HINF InfFile,
-                      PWCHAR SectionName,
-                      PWCHAR SourceCabinet,
-                      PCUNICODE_STRING DestinationPath,
-                      PINPUT_RECORD Ir)
-{
-    INFCONTEXT FilesContext;
-    INFCONTEXT DirContext;
-    PWCHAR FileKeyName;
-    PWCHAR FileKeyValue;
-    PWCHAR DirKeyValue;
-    PWCHAR TargetFileName;
-    WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
-
-    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);
-        return FALSE;
-    }
-
-    /*
-     * Enumerate the files in the section and add them to the file queue.
-     */
-    do
-    {
-        /* Get source file name */
-        if (!INF_GetDataField(&FilesContext, 0, &FileKeyName))
-        {
-            /* FIXME: Handle error! */
-            DPRINT1("INF_GetData() failed\n");
-            break;
-        }
-
-        /* Get target directory id */
-        if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
-        {
-            /* FIXME: Handle error! */
-            DPRINT1("INF_GetData() failed\n");
-            INF_FreeData(FileKeyName);
-            break;
-        }
-
-        /* Get optional target file name */
-        if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
-            TargetFileName = NULL;
-        else if (!*TargetFileName)
-            TargetFileName = NULL;
-
-        DPRINT("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
-
-        /* Lookup target directory */
-        if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
-        {
-            /* 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] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
-        {
-            /* Installation path */
-            DPRINT("InstallationPath: '%S'\n", DirKeyValue);
-
-            StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
-                           USetupData.SourceRootDir.Buffer);
-
-            DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
-        }
-        else if (DirKeyValue[0] == L'\\')
-        {
-            /* Absolute path */
-            DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
-
-            StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
-                           DirKeyValue);
-
-            DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName);
-        }
-        else // if (DirKeyValue[0] != L'\\')
-        {
-            /* Path relative to the installation path */
-            DPRINT("RelativePath: '%S'\n", DirKeyValue);
-
-            CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
-                         USetupData.SourceRootDir.Buffer, DirKeyValue);
-
-            DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
-        }
-
-        if (!SetupQueueCopy(SetupFileQueue,
-                            SourceCabinet,
-                            USetupData.SourceRootPath.Buffer,
-                            CompleteOrigDirName,
-                            FileKeyName,
-                            DirKeyValue,
-                            TargetFileName))
-        {
-            /* FIXME: Handle error! */
-            DPRINT1("SetupQueueCopy() failed\n");
-        }
-
-        INF_FreeData(FileKeyName);
-        INF_FreeData(TargetFileName);
-        INF_FreeData(DirKeyValue);
-    } while (SetupFindNextLine(&FilesContext, &FilesContext));
-
-    return TRUE;
-}
-
-
-static BOOLEAN
-PrepareCopyPageInfFile(HINF InfFile,
-                       PWCHAR SourceCabinet,
-                       PINPUT_RECORD Ir)
+// PSETUP_ERROR_ROUTINE
+static VOID
+__cdecl
+USetupErrorRoutine(
+    IN PUSETUP_DATA pSetupData,
+    ...)
 {
-    NTSTATUS Status;
-    INFCONTEXT DirContext;
-    PWCHAR AdditionalSectionName = NULL;
-    PWCHAR DirKeyValue;
-    WCHAR PathBuffer[MAX_PATH];
-
-    /* Add common files */
-    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))
-            return FALSE;
-
-        if (AdditionalSectionName)
-        {
-            if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &USetupData.DestinationPath, Ir))
-                return FALSE;
-        }
-    }
-
-    /* Create directories */
-
-    /*
-     * FIXME:
-     * 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 */
-    StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), USetupData.DestinationPath.Buffer);
-
-    DPRINT("FullPath(1): '%S'\n", PathBuffer);
+    INPUT_RECORD Ir;
+    va_list arg_ptr;
 
-    /* Create the install directory */
-    Status = SetupCreateDirectory(PathBuffer);
-    if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
-    {
-        DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
-        MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
-        return FALSE;
-    }
+    va_start(arg_ptr, pSetupData);
 
-    /* Search for the 'Directories' section */
-    if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
+    if (pSetupData->LastErrorNumber >= ERROR_SUCCESS &&
+        pSetupData->LastErrorNumber <  ERROR_LAST_ERROR_CODE)
     {
-        if (SourceCabinet)
-        {
-            MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER);
-        }
-        else
-        {
-            MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER);
-        }
-
-        return FALSE;
+        // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
+        MUIDisplayErrorV(pSetupData->LastErrorNumber, &Ir, POPUP_WAIT_ENTER, arg_ptr);
     }
 
-    /* Enumerate the directory values and create the subdirectories */
-    do
-    {
-        if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
-        {
-            DPRINT1("break\n");
-            break;
-        }
-
-        if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
-        {
-            /* Installation path */
-            DPRINT("InstallationPath: '%S'\n", DirKeyValue);
-
-            StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
-                           USetupData.DestinationPath.Buffer);
-
-            DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
-        }
-        else if (DirKeyValue[0] == L'\\')
-        {
-            /* Absolute path */
-            DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
-
-            CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                         USetupData.DestinationRootPath.Buffer, DirKeyValue);
-
-            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;
-            }
-        }
-        else // if (DirKeyValue[0] != L'\\')
-        {
-            /* Path relative to the installation path */
-            DPRINT("RelativePath: '%S'\n", DirKeyValue);
-
-            CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                         USetupData.DestinationPath.Buffer, DirKeyValue);
-
-            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;
+    va_end(arg_ptr);
 }
 
-
 /*
  * Displays the PrepareCopyPage.
  *
@@ -3729,8 +3498,7 @@ PrepareCopyPageInfFile(HINF InfFile,
  *  QuitPage
  *
  * SIDEEFFECTS
- * Inits SetupFileQueue
- * Calls PrepareCopyPageInfFile
+ * Calls PrepareFileCopy
  *
  * RETURNS
  *   Number of the next page.
@@ -3738,98 +3506,30 @@ PrepareCopyPageInfFile(HINF InfFile,
 static PAGE_NUMBER
 PrepareCopyPage(PINPUT_RECORD Ir)
 {
-    HINF InfHandle;
-    WCHAR PathBuffer[MAX_PATH];
-    INFCONTEXT CabinetsContext;
-    ULONG InfFileSize;
-    PWCHAR KeyValue;
-    UINT ErrorLine;
-    PVOID InfFileData;
+    // ERROR_NUMBER ErrorNumber;
+    BOOLEAN Success;
 
     MUIDisplayPage(PREPARE_COPY_PAGE);
 
-    /* Create the file queue */
-    SetupFileQueue = SetupOpenFileQueue();
-    if (SetupFileQueue == NULL)
-    {
-        MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
+    /* ErrorNumber = */ Success = PrepareFileCopy(&USetupData, NULL);
+    if (/*ErrorNumber != ERROR_SUCCESS*/ !Success)
     {
-        /* FIXME: show an error dialog */
+        // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
 
-    /* Search for the 'Cabinets' section */
-    if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
-    {
-        return FILE_COPY_PAGE;
-    }
-
-    /*
-     * Enumerate the directory values in the 'Cabinets'
-     * section and parse their inf files.
-     */
-    do
-    {
-        if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
-            break;
-
-        CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                     USetupData.SourcePath.Buffer, KeyValue);
-
-        CabinetInitialize();
-        CabinetSetEventHandlers(NULL, NULL, NULL);
-        CabinetSetCabinetName(PathBuffer);
-
-        if (CabinetOpen() == CAB_STATUS_SUCCESS)
-        {
-            DPRINT("Cabinet %S\n", CabinetGetCabinetName());
-
-            InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
-            if (InfFileData == NULL)
-            {
-                MUIDisplayError(ERROR_CABINET_SCRIPT, Ir, POPUP_WAIT_ENTER);
-                return QUIT_PAGE;
-            }
-        }
-        else
-        {
-            DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
-            MUIDisplayError(ERROR_CABINET_MISSING, Ir, POPUP_WAIT_ENTER);
-            return QUIT_PAGE;
-        }
-
-        InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData,
-                                          InfFileSize,
-                                          NULL,
-                                          INF_STYLE_WIN4,
-                                          USetupData.LanguageId,
-                                          &ErrorLine);
-
-        if (InfHandle == INVALID_HANDLE_VALUE)
-        {
-            MUIDisplayError(ERROR_INVALID_CABINET_INF, Ir, POPUP_WAIT_ENTER);
-            return QUIT_PAGE;
-        }
-
-        CabinetCleanup();
-
-        if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
-        {
-            /* FIXME: show an error dialog */
-            return QUIT_PAGE;
-        }
-    } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
-
     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)
 {
@@ -3856,7 +3556,6 @@ SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
     ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
 }
 
-
 static UINT
 CALLBACK
 FileCopyCallback(PVOID Context,
@@ -3864,26 +3563,92 @@ 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;
+
+                if (!wcsicmp(SrcFileName, DstFileName))
+                    Param2 = STRING_MOVING;
+                else
+                    Param2 = STRING_RENAMING;
+
+                CONSOLE_SetStatusText(MUIGetString(Param2),
+                                      SrcFileName, DstFileName);
+            }
+            else if (Notification == SPFILENOTIFY_STARTCOPY)
+            {
+                /* Display copy message */
+                ASSERT(Param2 == FILEOP_COPY);
+
+                /* NOTE: When extracting from CABs the Source is the CAB name */
+                DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
+                if (DstFileName) ++DstFileName;
+                else DstFileName = FilePathInfo->Target;
+
+                CONSOLE_SetStatusText(MUIGetString(STRING_COPYING),
+                                      DstFileName);
+            }
+
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
+        }
+
+        case SPFILENOTIFY_COPYERROR:
+        {
+            FilePathInfo = (PFILEPATHS_W)Param1;
 
+            DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
+                    FilePathInfo->Target, FilePathInfo->Win32Error);
+            return FILEOP_SKIP;
+        }
+
+        case SPFILENOTIFY_ENDDELETE:
+        case SPFILENOTIFY_ENDRENAME:
         case SPFILENOTIFY_ENDCOPY:
+        {
             CopyContext->CompletedOperations++;
 
             /* SYSREG checkpoint */
@@ -3893,9 +3658,10 @@ FileCopyCallback(PVOID Context,
             ProgressNextStep(CopyContext->ProgressBar);
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
+        }
     }
 
-    return 0;
+    return FILEOP_DOIT;
 }
 
 
@@ -3906,8 +3672,7 @@ FileCopyCallback(PVOID Context,
  *  RegistryPage(At once)
  *
  * SIDEEFFECTS
- *  Calls SetupCommitFileQueueW
- *  Calls SetupCloseFileQueue
+ *  Calls DoFileCopy
  *
  * RETURNS
  *   Number of the next page.
@@ -3916,13 +3681,11 @@ 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 = USetupData.DestinationRootPath.Buffer;
-    CopyContext.InstallPath = InstallPath.Buffer;
     CopyContext.TotalOperations = 0;
     CopyContext.CompletedOperations = 0;
 
@@ -3937,13 +3700,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,
@@ -3951,33 +3714,29 @@ 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,
-                          FileCopyCallback,
-                          &CopyContext);
+    DoFileCopy(&USetupData, FileCopyCallback, &CopyContext);
 
-    /* If we get here, we're done, so cleanup the queue and progress bar */
-    SetupCloseFileQueue(SetupFileQueue);
+    /* If we get here, we're done, so cleanup the progress bar */
     DestroyProgressBar(CopyContext.ProgressBar);
     DestroyProgressBar(CopyContext.MemoryBars[0]);
     DestroyProgressBar(CopyContext.MemoryBars[1]);
@@ -3991,6 +3750,37 @@ FileCopyPage(PINPUT_RECORD Ir)
 }
 
 
+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.
  *
@@ -4000,10 +3790,7 @@ FileCopyPage(PINPUT_RECORD Ir)
  *  QuitPage
  *
  * SIDEEFFECTS
- *  Calls RegInitializeRegistry
- *  Calls ImportRegistryFile
- *  Calls SetDefaultPagefile
- *  Calls SetMountedDeviceValues
+ *  Calls UpdateRegistry
  *
  * RETURNS
  *   Number of the next page.
@@ -4011,226 +3798,26 @@ FileCopyPage(PINPUT_RECORD Ir)
 static PAGE_NUMBER
 RegistryPage(PINPUT_RECORD Ir)
 {
-    NTSTATUS Status;
-    INFCONTEXT InfContext;
-    PWSTR Action;
-    PWSTR File;
-    PWSTR Section;
-    BOOLEAN Success;
-    BOOLEAN ShouldRepairRegistry = FALSE;
-    BOOLEAN Delete;
+    ULONG Error;
 
     MUIDisplayPage(REGISTRY_PAGE);
 
-    if (RepairUpdateFlag)
-    {
-        DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
-
-        /* Verify the registry hives and check whether we need to update or repair any of them */
-        Status = VerifyRegistryHives(&USetupData.DestinationPath, &ShouldRepairRegistry);
-        if (!NT_SUCCESS(Status))
-        {
-            DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status);
-            ShouldRepairRegistry = FALSE;
-        }
-        if (!ShouldRepairRegistry)
-            DPRINT1("No need to repair the registry\n");
-    }
-
-DoUpdate:
-    /* Update the registry */
-    CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));
-
-    /* Initialize the registry and setup the registry hives */
-    Status = RegInitializeRegistry(&USetupData.DestinationPath);
-    if (!NT_SUCCESS(Status))
+    Error = UpdateRegistry(&USetupData,
+                           RepairUpdateFlag,
+                           PartitionList,
+                           DestinationDriveLetter,
+                           SelectedLanguageId,
+                           RegistryStatus);
+    if (Error != ERROR_SUCCESS)
     {
-        DPRINT1("RegInitializeRegistry() failed\n");
-        /********** HACK!!!!!!!!!!! **********/
-        if (Status == STATUS_NOT_IMPLEMENTED)
-        {
-            /* The hack was called, display its corresponding error */
-            MUIDisplayError(ERROR_INITIALIZE_REGISTRY, Ir, POPUP_WAIT_ENTER);
-        }
-        else
-        /*************************************/
-        {
-            /* Something else failed */
-            MUIDisplayError(ERROR_CREATE_HIVE, Ir, POPUP_WAIT_ENTER);
-        }
+        MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
         return QUIT_PAGE;
     }
-
-    if (!RepairUpdateFlag || ShouldRepairRegistry)
-    {
-        /*
-         * We fully setup the hives, in case we are doing a fresh installation
-         * (RepairUpdateFlag == FALSE), or in case we are doing an update
-         * (RepairUpdateFlag == TRUE) BUT we have some registry hives to
-         * "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
-         */
-
-        Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Fresh", NULL, &InfContext);       // Windows-compatible
-        if (!Success)
-            Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Install", NULL, &InfContext); // ReactOS-specific
-
-        if (!Success)
-        {
-            DPRINT1("SetupFindFirstLine() failed\n");
-            MUIDisplayError(ERROR_FIND_REGISTRY, Ir, POPUP_WAIT_ENTER);
-            goto Cleanup;
-        }
-    }
-    else // if (RepairUpdateFlag && !ShouldRepairRegistry)
-    {
-        /*
-         * In case we are doing an update (RepairUpdateFlag == TRUE) and
-         * NO registry hives need a repair (ShouldRepairRegistry == FALSE),
-         * we only update the hives.
-         */
-
-        Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Upgrade", NULL, &InfContext);
-        if (!Success)
-        {
-            /* Nothing to do for update! */
-            DPRINT1("No update needed for the registry!\n");
-            goto Cleanup;
-        }
-    }
-
-    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)
-        {
-            INF_FreeData(Action);
-            INF_FreeData(File);
-            INF_FreeData(Section);
-            break; // Hackfix
-        }
-
-        if (!_wcsicmp(Action, L"AddReg"))
-            Delete = FALSE;
-        else if (!_wcsicmp(Action, L"DelReg"))
-            Delete = TRUE;
-        else
-        {
-            DPRINT1("Unrecognized registry INF action '%S'\n", Action);
-            INF_FreeData(Action);
-            INF_FreeData(File);
-            INF_FreeData(Section);
-            continue;
-        }
-
-        INF_FreeData(Action);
-
-        CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE), File);
-
-        if (!ImportRegistryFile(USetupData.SourcePath.Buffer, File, Section, USetupData.LanguageId, Delete))
-        {
-            DPRINT1("Importing %S failed\n", File);
-            INF_FreeData(File);
-            INF_FreeData(Section);
-            MUIDisplayError(ERROR_IMPORT_HIVE, Ir, POPUP_WAIT_ENTER);
-            goto Cleanup;
-        }
-    } while (SetupFindNextLine(&InfContext, &InfContext));
-
-    if (!RepairUpdateFlag || ShouldRepairRegistry)
-    {
-        /* See the explanation for this test above */
-
-        /* Update display registry settings */
-        CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE));
-        if (!ProcessDisplayRegistry(SetupInf, DisplayList))
-        {
-            MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS, Ir, POPUP_WAIT_ENTER);
-            goto Cleanup;
-        }
-
-        /* Set the locale */
-        CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE));
-        if (!ProcessLocaleRegistry(LanguageList))
-        {
-            MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS, Ir, POPUP_WAIT_ENTER);
-            goto Cleanup;
-        }
-
-        /* Add keyboard layouts */
-        CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS));
-        if (!AddKeyboardLayouts())
-        {
-            MUIDisplayError(ERROR_ADDING_KBLAYOUTS, Ir, POPUP_WAIT_ENTER);
-            goto Cleanup;
-        }
-
-        /* Set GeoID */
-        if (!SetGeoID(MUIGetGeoID()))
-        {
-            MUIDisplayError(ERROR_UPDATE_GEOID, Ir, POPUP_WAIT_ENTER);
-            goto Cleanup;
-        }
-
-        if (!IsUnattendedSetup)
-        {
-            /* Update keyboard layout settings */
-            CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE));
-            if (!ProcessKeyboardLayoutRegistry(LayoutList))
-            {
-                MUIDisplayError(ERROR_UPDATE_KBSETTINGS, Ir, POPUP_WAIT_ENTER);
-                goto Cleanup;
-            }
-        }
-
-        /* Add codepage information to registry */
-        CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE));
-        if (!AddCodePage())
-        {
-            MUIDisplayError(ERROR_ADDING_CODEPAGE, Ir, POPUP_WAIT_ENTER);
-            goto Cleanup;
-        }
-
-        /* Set the default pagefile entry */
-        SetDefaultPagefile(DestinationDriveLetter);
-
-        /* Update the mounted devices list */
-        // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
-        SetMountedDeviceValues(PartitionList);
-    }
-
-Cleanup:
-    //
-    // TODO: Unload all the registry stuff, perform cleanup,
-    // and copy the created hive files into .sav files.
-    //
-    RegCleanupRegistry(&USetupData.DestinationPath);
-
-    /*
-     * Check whether we were in update/repair mode but we were actually
-     * repairing the registry hives. If so, we have finished repairing them,
-     * and we now reset the flag and run the proper registry update.
-     * Otherwise we have finished the registry update!
-     */
-    if (RepairUpdateFlag && ShouldRepairRegistry)
-    {
-        ShouldRepairRegistry = FALSE;
-        goto DoUpdate;
-    }
-
-    if (NT_SUCCESS(Status))
+    else
     {
         CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
         return BOOT_LOADER_PAGE;
     }
-    else
-    {
-        return QUIT_PAGE;
-    }
 }
 
 
@@ -4265,7 +3852,7 @@ BootLoaderPage(PINPUT_RECORD Ir)
     CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
 
     RtlFreeUnicodeString(&USetupData.SystemRootPath);
-    StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+    RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
             L"\\Device\\Harddisk%lu\\Partition%lu\\",
             PartitionList->SystemPartition->DiskEntry->DiskNumber,
             PartitionList->SystemPartition->PartitionNumber);
@@ -4299,10 +3886,10 @@ BootLoaderPage(PINPUT_RECORD Ir)
         DPRINT("Found OS/2 boot manager partition\n");
         InstallOnFloppy = TRUE;
     }
-    else if (PartitionType == PARTITION_EXT2)
+    else if (PartitionType == PARTITION_LINUX)
     {
-        /* Linux EXT2 partition */
-        DPRINT("Found Linux EXT2 partition\n");
+        /* Linux partition */
+        DPRINT("Found Linux native partition (ext2/ext3/ReiserFS/BTRFS/etc)\n");
         InstallOnFloppy = FALSE;
     }
     else if (PartitionType == PARTITION_IFS)
@@ -4481,16 +4068,14 @@ BootLoaderFloppyPage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)    /* ENTER */
         {
-            if (DoesPathExist(NULL, L"\\Device\\Floppy0\\") == FALSE)
-            {
-                MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
-                return BOOT_LOADER_FLOPPY_PAGE;
-            }
-
-            Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath, &USetupData.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;
             }
 
@@ -4520,13 +4105,15 @@ BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
 {
     NTSTATUS Status;
 
+    // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
     Status = InstallVBRToPartition(&USetupData.SystemRootPath,
                                    &USetupData.SourceRootPath,
                                    &USetupData.DestinationArcPath,
                                    PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
-        MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
+        MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER,
+                        PartitionList->SystemPartition->FileSystem->FileSystemName);
         return QUIT_PAGE;
     }
 
@@ -4553,50 +4140,31 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
 {
     NTSTATUS Status;
     WCHAR DestinationDevicePathBuffer[MAX_PATH];
-    WCHAR SourceMbrPathBuffer[MAX_PATH];
-    WCHAR DstPath[MAX_PATH];
 
     /* Step 1: Write the VBR */
+    // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
     Status = InstallVBRToPartition(&USetupData.SystemRootPath,
                                    &USetupData.SourceRootPath,
                                    &USetupData.DestinationArcPath,
                                    PartitionList->SystemPartition->PartitionType);
     if (!NT_SUCCESS(Status))
     {
-        MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
+        MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER,
+                        PartitionList->SystemPartition->FileSystem->FileSystemName);
         return QUIT_PAGE;
     }
 
     /* Step 2: Write the MBR */
-    StringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
+    RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
             L"\\Device\\Harddisk%d\\Partition0",
             PartitionList->SystemPartition->DiskEntry->DiskNumber);
-
-    CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2, USetupData.SourceRootPath.Buffer, L"\\loader\\dosmbr.bin");
-
-    if (IsThereAValidBootSector(DestinationDevicePathBuffer))
-    {
-        /* Save current MBR */
-        CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, USetupData.SystemRootPath.Buffer, L"mbr.old");
-
-        DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
-        Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
-        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.
-        }
-    }
-
-    DPRINT1("Install MBR bootcode: %S ==> %S\n",
-            SourceMbrPathBuffer, DestinationDevicePathBuffer);
-    Status = InstallMbrBootCodeToDisk(SourceMbrPathBuffer,
+    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);
+        DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status);
+        MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER, L"MBR");
         return QUIT_PAGE;
     }
 
@@ -4829,6 +4397,7 @@ QuitPage(PINPUT_RECORD Ir)
         DestroyPartitionList(PartitionList);
         PartitionList = NULL;
     }
+
     TempPartition = NULL;
     FormatState = Start;
 
@@ -4839,41 +4408,6 @@ QuitPage(PINPUT_RECORD Ir)
         FileSystemList = NULL;
     }
 
-    /* Destroy the computer settings list */
-    if (ComputerList != NULL)
-    {
-        DestroyGenericList(ComputerList, TRUE);
-        ComputerList = NULL;
-    }
-
-    /* Destroy the display settings list */
-    if (DisplayList != NULL)
-    {
-        DestroyGenericList(DisplayList, TRUE);
-        DisplayList = NULL;
-    }
-
-    /* Destroy the keyboard settings list */
-    if (KeyboardList != NULL)
-    {
-        DestroyGenericList(KeyboardList, TRUE);
-        KeyboardList = NULL;
-    }
-
-    /* Destroy the keyboard layout list */
-    if (LayoutList != NULL)
-    {
-        DestroyGenericList(LayoutList, TRUE);
-        LayoutList = NULL;
-    }
-
-    /* Destroy the languages list */
-    if (LanguageList != NULL)
-    {
-        DestroyGenericList(LanguageList, FALSE);
-        LanguageList = NULL;
-    }
-
     CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2));
 
     /* Wait for maximum 15 seconds or an ENTER key before quitting */
@@ -4955,7 +4489,7 @@ RunUSetup(VOID)
                                  0,
                                  0,
                                  PnpEventThread,
-                                 &SetupInf,
+                                 &USetupData.SetupInf,
                                  &hPnpThread,
                                  NULL);
     if (!NT_SUCCESS(Status))
@@ -4971,15 +4505,9 @@ RunUSetup(VOID)
         return STATUS_APP_INIT_FAILURE;
     }
 
-    /* Initialize global unicode strings */
-    RtlInitUnicodeString(&USetupData.SourcePath, NULL);
-    RtlInitUnicodeString(&USetupData.SourceRootPath, NULL);
-    RtlInitUnicodeString(&USetupData.SourceRootDir, NULL);
-    RtlInitUnicodeString(&InstallPath, NULL);
-    RtlInitUnicodeString(&USetupData.DestinationPath, NULL);
-    RtlInitUnicodeString(&USetupData.DestinationArcPath, NULL);
-    RtlInitUnicodeString(&USetupData.DestinationRootPath, NULL);
-    RtlInitUnicodeString(&USetupData.SystemRootPath, NULL);
+    /* Initialize Setup, phase 0 */
+    InitializeSetup(&USetupData, 0);
+    USetupData.ErrorRoutine = USetupErrorRoutine;
 
     /* Hide the cursor */
     CONSOLE_SetCursorType(TRUE, FALSE);
@@ -5144,7 +4672,8 @@ RunUSetup(VOID)
         }
     }
 
-    SetupCloseInfFile(SetupInf);
+    /* Setup has finished */
+    FinishSetup(&USetupData);
 
     if (Page == RECOVERY_PAGE)
         RecoveryConsole();