[SETUP] Add support for selecting FS type in unattended setups
[reactos.git] / base / setup / usetup / usetup.c
index d951a65..6fd68b7 100644 (file)
@@ -31,6 +31,7 @@
 #include "bootsup.h"
 #include "chkdsk.h"
 #include "cmdcons.h"
+#include "devinst.h"
 #include "format.h"
 
 #define NDEBUG
@@ -56,8 +57,6 @@ static WCHAR DefaultKBLayout[20];   // Copy of string inside KeyboardList
 
 static BOOLEAN RepairUpdateFlag = FALSE;
 
-static HANDLE hPnpThread = NULL;
-
 static PPARTLIST PartitionList = NULL;
 static PPARTENTRY TempPartition = NULL;
 static PFILE_SYSTEM_LIST FileSystemList = NULL;
@@ -69,19 +68,6 @@ static PNTOS_INSTALLATION CurrentInstallation = NULL;
 static PGENERIC_LIST NtOsInstallsList = NULL;
 
 
-// HACK: Temporary compatibility code.
-#if 1
-    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
-
-
 /* FUNCTIONS ****************************************************************/
 
 static VOID
@@ -452,7 +438,7 @@ GetNTOSInstallationName(
     {
         /* We have retrieved a partition that is mounted */
         return RtlStringCchPrintfA(Buffer, cchBufferSize,
-                                   "%c:%S  \"%S\"",
+                                   "%C:%S  \"%S\"",
                                    PartEntry->DriveLetter,
                                    NtOsInstall->PathComponent,
                                    NtOsInstall->InstallationName);
@@ -646,7 +632,7 @@ SetupStartPage(PINPUT_RECORD Ir)
     PGENERIC_LIST_ENTRY ListEntry;
     PCWSTR LocaleId;
 
-    CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
+    MUIDisplayPage(SETUP_INIT_PAGE);
 
     /* Initialize Setup, phase 1 */
     Error = InitializeSetup(&USetupData, 1);
@@ -656,12 +642,13 @@ SetupStartPage(PINPUT_RECORD Ir)
         return QUIT_PAGE;
     }
 
-    /* Start the PnP thread */
-    if (hPnpThread != NULL)
-    {
-        NtResumeThread(hPnpThread, NULL);
-        hPnpThread = NULL;
-    }
+    /* Initialize the user-mode PnP manager */
+    if (!EnableUserModePnpManager())
+        DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n");
+
+    /* Wait for any immediate pending installations to finish */
+    if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0)
+        DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n");
 
     CheckUnattendedSetup(&USetupData);
 
@@ -1620,12 +1607,26 @@ SelectPartitionPage(PINPUT_RECORD Ir)
             {
                 if (PartitionList->CurrentPartition->LogicalPartition)
                 {
+                    Error = LogicalPartitionCreationChecks(PartitionList);
+                    if (Error != NOT_AN_ERROR)
+                    {
+                        MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
+                        return SELECT_PARTITION_PAGE;
+                    }
+
                     CreateLogicalPartition(PartitionList,
                                            0ULL,
                                            TRUE);
                 }
                 else
                 {
+                    Error = PrimaryPartitionCreationChecks(PartitionList);
+                    if (Error != NOT_AN_ERROR)
+                    {
+                        MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
+                        return SELECT_PARTITION_PAGE;
+                    }
+
                     CreatePrimaryPartition(PartitionList,
                                            0ULL,
                                            TRUE);
@@ -1982,7 +1983,9 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
                             DiskEntry->Bus,
                             DiskEntry->Id,
                             &DiskEntry->DriverName,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
     }
     else
     {
@@ -1994,7 +1997,9 @@ CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
     }
 
     CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
@@ -2141,7 +2146,9 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
                             DiskEntry->Bus,
                             DiskEntry->Id,
                             &DiskEntry->DriverName,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
     }
     else
     {
@@ -2153,7 +2160,9 @@ CreateExtendedPartitionPage(PINPUT_RECORD Ir)
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
     }
 
     CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
@@ -2299,7 +2308,9 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
                             DiskEntry->Bus,
                             DiskEntry->Id,
                             &DiskEntry->DriverName,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
     }
     else
     {
@@ -2311,7 +2322,9 @@ CreateLogicalPartitionPage(PINPUT_RECORD Ir)
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
     }
 
     CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
@@ -2493,7 +2506,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,
@@ -2503,7 +2516,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,
@@ -2538,7 +2551,9 @@ DeletePartitionPage(PINPUT_RECORD Ir)
                             DiskEntry->Bus,
                             DiskEntry->Id,
                             &DiskEntry->DriverName,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
     }
     else
     {
@@ -2550,7 +2565,9 @@ DeletePartitionPage(PINPUT_RECORD Ir)
                             DiskEntry->Port,
                             DiskEntry->Bus,
                             DiskEntry->Id,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
     }
 
     while (TRUE)
@@ -2593,7 +2610,7 @@ DeletePartitionPage(PINPUT_RECORD Ir)
  *  QuitPage
  *
  * SIDEEFFECTS
- *  Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
+ *  Calls UpdatePartitionType()
  *  Calls CheckActiveSystemPartition()
  *
  * RETURNS
@@ -2772,7 +2789,9 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                             DiskEntry->Bus,
                             DiskEntry->Id,
                             &DiskEntry->DriverName,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
 
         CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
 
@@ -2808,7 +2827,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,
@@ -2818,7 +2837,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,
@@ -2833,13 +2852,38 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
                             DiskEntry->Bus,
                             DiskEntry->Id,
                             &DiskEntry->DriverName,
-                            DiskEntry->NoMbr ? "GPT" : "MBR");
+                            DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? L"MBR" :
+                            DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? L"GPT" :
+                                                                          L"RAW");
     }
 
     if (FileSystemList == NULL)
     {
-        /* Create the file system list, and by default select the "FAT" file system */
-        FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
+        PWSTR DefaultFs;
+
+        if (IsUnattendedSetup)
+        {
+            switch (USetupData.FsType)
+            {
+                /* 1 is for BtrFS */
+                case 1:
+                    DefaultFs = L"BTRFS";
+                    break;
+
+                /* If we don't understand input, default to FAT */
+                default:
+                    DefaultFs = L"FAT";
+                    break;
+            }
+        }
+        else
+        {
+            /* By default select the "FAT" file system */
+            DefaultFs = L"FAT";
+        }
+
+        /* Create the file system list */
+        FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, DefaultFs);
         if (FileSystemList == NULL)
         {
             /* FIXME: show an error dialog */
@@ -2857,13 +2901,6 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
     {
         if (USetupData.FormatPartition)
         {
-            /*
-             * 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;
         }
 
@@ -3213,7 +3250,7 @@ BuildInstallPaths(PWSTR InstallDir,
     UNREFERENCED_PARAMETER(Status);
 
     /* Initialize DestinationDriveLetter */
-    DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
+    DestinationDriveLetter = PartEntry->DriveLetter;
 }
 
 
@@ -3481,433 +3518,28 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
 }
 
 
-static BOOLEAN
-AddSectionToCopyQueueCab(HINF InfFile,
-                         PCWSTR SectionName,
-                         PCWSTR SourceCabinet,
-                         PCUNICODE_STRING DestinationPath,
-                         PINPUT_RECORD Ir)
-{
-    INFCONTEXT FilesContext;
-    INFCONTEXT DirContext;
-    PCWSTR FileKeyName;
-    PCWSTR FileKeyValue;
-    PCWSTR DirKeyValue;
-    PCWSTR 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 (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
-    {
-        MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, SectionName);
-        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 (!SpInfFindFirstLine(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 1 // HACK moved! (r66604)
-        {
-        ULONG Length = wcslen(DirKeyValue);
-        if ((Length > 0) && (DirKeyValue[Length - 1] == L'\\'))
-            Length--;
-        *((PWSTR)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 (!SpFileQueueCopy((HSPFILEQ)USetupData.SetupFileQueue,
-                             USetupData.SourceRootPath.Buffer,
-                             USetupData.SourceRootDir.Buffer,
-                             FileKeyName,
-                             NULL,
-                             SourceCabinet,
-                             NULL,
-                             FileDstPath,
-                             TargetFileName,
-                             0 /* FIXME */))
-        {
-            /* FIXME: Handle error! */
-            DPRINT1("SpFileQueueCopy() failed\n");
-        }
-
-        INF_FreeData(FileKeyName);
-        INF_FreeData(TargetFileName);
-        INF_FreeData(DirKeyValue);
-    } while (SpInfFindNextLine(&FilesContext, &FilesContext));
-
-    return TRUE;
-}
-
-
-static BOOLEAN
-AddSectionToCopyQueue(HINF InfFile,
-                      PCWSTR SectionName,
-                      PCWSTR SourceCabinet,
-                      PCUNICODE_STRING DestinationPath,
-                      PINPUT_RECORD Ir)
-{
-    INFCONTEXT FilesContext;
-    INFCONTEXT DirContext;
-    PCWSTR FileKeyName;
-    PCWSTR FileKeyValue;
-    PCWSTR DirKeyValue;
-    PCWSTR TargetFileName;
-    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 (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
-    {
-        MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, SectionName);
-        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 (!SpInfFindFirstLine(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);
-
-            RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
-                              USetupData.SourceRootDir.Buffer);
-
-            DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
-        }
-        else if (DirKeyValue[0] == L'\\')
-        {
-            /* Absolute path */
-            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 */
-            DPRINT("RelativePath: '%S'\n", DirKeyValue);
-
-            CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
-                         USetupData.SourceRootDir.Buffer, DirKeyValue);
-
-            DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
-        }
-
-#if 1 // HACK moved! (r66604)
-        {
-        ULONG Length = wcslen(DirKeyValue);
-        if ((Length > 0) && (DirKeyValue[Length - 1] == L'\\'))
-            Length--;
-        *((PWSTR)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 (!SpFileQueueCopy((HSPFILEQ)USetupData.SetupFileQueue,
-                             USetupData.SourceRootPath.Buffer,
-                             CompleteOrigDirName,
-                             FileKeyName,
-                             NULL,
-                             SourceCabinet,
-                             NULL,
-                             FileDstPath,
-                             TargetFileName,
-                             0 /* FIXME */))
-        {
-            /* FIXME: Handle error! */
-            DPRINT1("SpFileQueueCopy() failed\n");
-        }
-
-        INF_FreeData(FileKeyName);
-        INF_FreeData(TargetFileName);
-        INF_FreeData(DirKeyValue);
-    } while (SpInfFindNextLine(&FilesContext, &FilesContext));
-
-    return TRUE;
-}
-
-
-static BOOLEAN
-PrepareCopyPageInfFile(HINF InfFile,
-                       PCWSTR SourceCabinet,
-                       PINPUT_RECORD Ir)
+// PSETUP_ERROR_ROUTINE
+static VOID
+__cdecl
+USetupErrorRoutine(
+    IN PUSETUP_DATA pSetupData,
+    ...)
 {
-    NTSTATUS Status;
-    INFCONTEXT DirContext;
-    PWCHAR AdditionalSectionName = NULL;
-    PCWSTR 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, USetupData.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 */
-    RtlStringCchCopyW(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 (!SpInfFindFirstLine(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, L"Directories");
-        else
-            MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, L"Directories");
-
-        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);
-
-            RtlStringCchCopyW(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 (SpInfFindNextLine(&DirContext, &DirContext));
-
-    return TRUE;
+    va_end(arg_ptr);
 }
 
-
 /*
  * Displays the PrepareCopyPage.
  *
@@ -3916,8 +3548,7 @@ PrepareCopyPageInfFile(HINF InfFile,
  *  QuitPage
  *
  * SIDEEFFECTS
- * Inits SetupFileQueue
- * Calls PrepareCopyPageInfFile
+ * Calls PrepareFileCopy
  *
  * RETURNS
  *   Number of the next page.
@@ -3925,92 +3556,18 @@ PrepareCopyPageInfFile(HINF InfFile,
 static PAGE_NUMBER
 PrepareCopyPage(PINPUT_RECORD Ir)
 {
-    HINF InfHandle;
-    WCHAR PathBuffer[MAX_PATH];
-    INFCONTEXT CabinetsContext;
-    ULONG InfFileSize;
-    PCWSTR KeyValue;
-    UINT ErrorLine;
-    PVOID InfFileData;
+    // ERROR_NUMBER ErrorNumber;
+    BOOLEAN Success;
 
     MUIDisplayPage(PREPARE_COPY_PAGE);
 
-    /* Create the file queue */
-    USetupData.SetupFileQueue = SpFileQueueOpen();
-    if (USetupData.SetupFileQueue == NULL)
-    {
-        MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
-        return QUIT_PAGE;
-    }
-
-    if (!PrepareCopyPageInfFile(USetupData.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 (!SpInfFindFirstLine(USetupData.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 (SpInfFindNextLine(&CabinetsContext, &CabinetsContext));
-
     return FILE_COPY_PAGE;
 }
 
@@ -4165,8 +3722,7 @@ FileCopyCallback(PVOID Context,
  *  RegistryPage(At once)
  *
  * SIDEEFFECTS
- *  Calls SetupCommitFileQueueW
- *  Calls SpFileQueueClose
+ *  Calls DoFileCopy
  *
  * RETURNS
  *   Number of the next page.
@@ -4228,13 +3784,9 @@ FileCopyPage(PINPUT_RECORD Ir)
                                                   "Free Memory");
 
     /* Do the file copying */
-    SpFileQueueCommit(NULL,
-                      USetupData.SetupFileQueue,
-                      FileCopyCallback,
-                      &CopyContext);
+    DoFileCopy(&USetupData, FileCopyCallback, &CopyContext);
 
-    /* If we get here, we're done, so cleanup the queue and progress bar */
-    SpFileQueueClose(USetupData.SetupFileQueue);
+    /* If we get here, we're done, so cleanup the progress bar */
     DestroyProgressBar(CopyContext.ProgressBar);
     DestroyProgressBar(CopyContext.MemoryBars[0]);
     DestroyProgressBar(CopyContext.MemoryBars[1]);
@@ -4384,10 +3936,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)
@@ -4603,13 +4155,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;
     }
 
@@ -4638,13 +4192,15 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
     WCHAR DestinationDevicePathBuffer[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;
     }
 
@@ -4658,7 +4214,7 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status);
-        MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER);
+        MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER, L"MBR");
         return QUIT_PAGE;
     }
 
@@ -4953,10 +4509,6 @@ FlushPage(PINPUT_RECORD Ir)
 }
 
 
-DWORD WINAPI
-PnpEventThread(IN LPVOID lpParameter);
-
-
 /*
  * The start routine and page management
  */
@@ -4975,19 +4527,13 @@ RunUSetup(VOID)
     if (!NT_SUCCESS(Status))
         DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status);
 
-    /* Create the PnP thread in suspended state */
-    Status = RtlCreateUserThread(NtCurrentProcess(),
-                                 NULL,
-                                 TRUE,
-                                 0,
-                                 0,
-                                 0,
-                                 PnpEventThread,
-                                 &USetupData.SetupInf,
-                                 &hPnpThread,
-                                 NULL);
+    /* Initialize the user-mode PnP manager */
+    Status = InitializeUserModePnpManager(&USetupData.SetupInf);
     if (!NT_SUCCESS(Status))
-        hPnpThread = NULL;
+    {
+        // PrintString(??);
+        DPRINT1("The user-mode PnP manager could not initialize (Status 0x%08lx), expect unavailable devices!\n", Status);
+    }
 
     if (!CONSOLE_Init())
     {
@@ -5001,13 +4547,14 @@ RunUSetup(VOID)
 
     /* Initialize Setup, phase 0 */
     InitializeSetup(&USetupData, 0);
+    USetupData.ErrorRoutine = USetupErrorRoutine;
 
-    /* Hide the cursor */
+    /* Hide the cursor and clear the screen and keyboard buffer */
     CONSOLE_SetCursorType(TRUE, FALSE);
-
-    /* Global Initialization page */
     CONSOLE_ClearScreen();
     CONSOLE_Flush();
+
+    /* Global Initialization page */
     Page = SetupStartPage(&Ir);
 
     while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
@@ -5159,12 +4706,17 @@ RunUSetup(VOID)
                 Page = QuitPage(&Ir);
                 break;
 
-            case RECOVERY_PAGE:
+            /* Virtual pages */
+            case SETUP_INIT_PAGE:
             case REBOOT_PAGE:
+            case RECOVERY_PAGE:
                 break;
         }
     }
 
+    /* Terminate the user-mode PnP manager */
+    TerminateUserModePnpManager();
+
     /* Setup has finished */
     FinishSetup(&USetupData);