branch update for HEAD-2003050101
[reactos.git] / subsys / system / usetup / usetup.c
index 1704d6e..96620cf 100644 (file)
  * FILE:            subsys/system/usetup/usetup.c
  * PURPOSE:         Text-mode setup
  * PROGRAMMER:      Eric Kohl
+ *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
  */
 
 #include <ddk/ntddk.h>
 #include <ntdll/rtl.h>
 
+#include <ntos/minmax.h>
+#include <reactos/resource.h>
+
 #include "usetup.h"
 #include "console.h"
 #include "partlist.h"
+#include "inicache.h"
+#include "infcache.h"
+#include "filequeue.h"
+#include "progress.h"
+#include "bootsup.h"
+#include "registry.h"
+#include "format.h"
+
+#define NDEBUG
+#include <debug.h>
+
+typedef enum _PAGE_NUMBER
+{
+  START_PAGE,
+  INTRO_PAGE,
+  INSTALL_INTRO_PAGE,
+
+  SELECT_PARTITION_PAGE,
+  CREATE_PARTITION_PAGE,
+  SELECT_FILE_SYSTEM_PAGE,
+  FORMAT_PARTITION_PAGE,
+  CHECK_FILE_SYSTEM_PAGE,
+  PREPARE_COPY_PAGE,
+  INSTALL_DIRECTORY_PAGE,
+  FILE_COPY_PAGE,
+  REGISTRY_PAGE,
+  BOOT_LOADER_PAGE,
+
+  REPAIR_INTRO_PAGE,
+
+  SUCCESS_PAGE,
+  QUIT_PAGE,
+  REBOOT_PAGE,                 /* virtual page */
+} PAGE_NUMBER, *PPAGE_NUMBER;
+
+typedef struct _COPYCONTEXT
+{
+  ULONG TotalOperations;
+  ULONG CompletedOperations;
+  PPROGRESS ProgressBar;
+} COPYCONTEXT, *PCOPYCONTEXT;
 
 
+/* GLOBALS ******************************************************************/
 
-#define START_PAGE                     0
-#define INTRO_PAGE                     1
-#define INSTALL_INTRO_PAGE             2
+HANDLE ProcessHeap;
+UNICODE_STRING SourceRootPath;
 
-#define SELECT_PARTITION_PAGE          4
-#define SELECT_FILE_SYSTEM_PAGE                5
-#define CHECK_FILE_SYSTEM_PAGE         6
-#define PREPARE_COPY_PAGE              7
-#define INSTALL_DIRECTORY_PAGE         8
-#define FILE_COPY_PAGE                 9
-#define INIT_SYSTEM_PAGE               10
+/* LOCALS *******************************************************************/
 
-#define REPAIR_INTRO_PAGE              20
+static BOOLEAN PartDataValid;
+static PARTDATA PartData;
 
-#define SUCCESS_PAGE                   100
-#define QUIT_PAGE                      101
-#define REBOOT_PAGE                    102
+static BOOLEAN ActivePartitionValid;
+static PARTDATA ActivePartition;
 
+static UNICODE_STRING SourcePath;
 
-/* GLOBALS ******************************************************************/
+static UNICODE_STRING InstallPath;
+static UNICODE_STRING DestinationPath;
+static UNICODE_STRING DestinationArcPath;
+static UNICODE_STRING DestinationRootPath;
 
-HANDLE ProcessHeap;
+static UNICODE_STRING SystemRootPath; /* Path to the active partition */
 
-BOOL PartDataValid = FALSE;
-PARTDATA PartData;
+static HINF SetupInf;
 
-CHAR InstallDir[51];
+static HSPFILEQ SetupFileQueue = NULL;
 
-UNICODE_STRING SourcePath;
-UNICODE_STRING SourceRootPath;
+static PPARTLIST CurrentPartitionList = NULL;
+static PFILE_SYSTEM_LIST CurrentFileSystemList;
 
 
 /* FUNCTIONS ****************************************************************/
@@ -88,6 +130,215 @@ PrintString(char* fmt,...)
 }
 
 
+static VOID
+PopupError(PCHAR Text,
+          PCHAR Status)
+{
+  SHORT xScreen;
+  SHORT yScreen;
+  SHORT yTop;
+  SHORT xLeft;
+  COORD coPos;
+  ULONG Written;
+  ULONG Length;
+  ULONG MaxLength;
+  ULONG Lines;
+  PCHAR p;
+  PCHAR pnext;
+  BOOLEAN LastLine;
+  SHORT Width;
+  SHORT Height;
+
+  /* Count text lines and longest line */
+  MaxLength = 0;
+  Lines = 0;
+  pnext = Text;
+  while (TRUE)
+    {
+      p = strchr(pnext, '\n');
+      if (p == NULL)
+       {
+         Length = strlen(pnext);
+         LastLine = TRUE;
+       }
+      else
+       {
+         Length = (ULONG)(p - pnext);
+         LastLine = FALSE;
+       }
+
+      Lines++;
+      if (Length > MaxLength)
+       MaxLength = Length;
+
+      if (LastLine == TRUE)
+       break;
+
+      pnext = p + 1;
+    }
+
+  /* Check length of status line */
+  if (Status != NULL)
+    {
+      Length = strlen(Status);
+      if (Length > MaxLength)
+       MaxLength = Length;
+    }
+
+  GetScreenSize(&xScreen, &yScreen);
+
+  Width = MaxLength + 4;
+  Height = Lines + 2;
+  if (Status != NULL)
+    Height += 2;
+
+  yTop = (yScreen - Height) / 2;
+  xLeft = (xScreen - Width) / 2;
+
+
+  /* Set screen attributes */
+  coPos.X = xLeft;
+  for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
+    {
+      FillConsoleOutputAttribute(0x74,
+                                Width,
+                                coPos,
+                                &Written);
+    }
+
+  /* draw upper left corner */
+  coPos.X = xLeft;
+  coPos.Y = yTop;
+  FillConsoleOutputCharacter(0xDA, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* draw upper edge */
+  coPos.X = xLeft + 1;
+  coPos.Y = yTop;
+  FillConsoleOutputCharacter(0xC4, // '-',
+                            Width - 2,
+                            coPos,
+                            &Written);
+
+  /* draw upper right corner */
+  coPos.X = xLeft + Width - 1;
+  coPos.Y = yTop;
+  FillConsoleOutputCharacter(0xBF, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* Draw right edge, inner space and left edge */
+  for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
+    {
+      coPos.X = xLeft;
+      FillConsoleOutputCharacter(0xB3, // '|',
+                                1,
+                                coPos,
+                                &Written);
+
+      coPos.X = xLeft + 1;
+      FillConsoleOutputCharacter(' ',
+                                Width - 2,
+                                coPos,
+                                &Written);
+
+      coPos.X = xLeft + Width - 1;
+      FillConsoleOutputCharacter(0xB3, // '|',
+                                1,
+                                coPos,
+                                &Written);
+    }
+
+  /* draw lower left corner */
+  coPos.X = xLeft;
+  coPos.Y = yTop + Height - 1;
+  FillConsoleOutputCharacter(0xC0, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* draw lower edge */
+  coPos.X = xLeft + 1;
+  coPos.Y = yTop + Height - 1;
+  FillConsoleOutputCharacter(0xC4, // '-',
+                            Width - 2,
+                            coPos,
+                            &Written);
+
+  /* draw lower right corner */
+  coPos.X = xLeft + Width - 1;
+  coPos.Y = yTop + Height - 1;
+  FillConsoleOutputCharacter(0xD9, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* Print message text */
+  coPos.Y = yTop + 1;
+  pnext = Text;
+  while (TRUE)
+    {
+      p = strchr(pnext, '\n');
+      if (p == NULL)
+       {
+         Length = strlen(pnext);
+         LastLine = TRUE;
+       }
+      else
+       {
+         Length = (ULONG)(p - pnext);
+         LastLine = FALSE;
+       }
+
+      if (Length != 0)
+       {
+         coPos.X = xLeft + 2;
+         WriteConsoleOutputCharacters(pnext,
+                                      Length,
+                                      coPos);
+       }
+
+      if (LastLine == TRUE)
+       break;
+
+      coPos.Y++;
+      pnext = p + 1;
+    }
+
+  /* Print separator line and status text */
+  if (Status != NULL)
+    {
+      coPos.Y = yTop + Height - 3;
+      coPos.X = xLeft;
+      FillConsoleOutputCharacter(0xC3, // '+',
+                                1,
+                                coPos,
+                                &Written);
+
+      coPos.X = xLeft + 1;
+      FillConsoleOutputCharacter(0xC4, // '-',
+                                Width - 2,
+                                coPos,
+                                &Written);
+
+      coPos.X = xLeft + Width - 1;
+      FillConsoleOutputCharacter(0xB4, // '+',
+                                1,
+                                coPos,
+                                &Written);
+
+      coPos.Y++;
+      coPos.X = xLeft + 2;
+      WriteConsoleOutputCharacters(Status,
+                                  min(strlen(Status), Width - 4),
+                                  coPos);
+    }
+}
+
+
 /*
  * Confirm quit setup
  * RETURNS
@@ -97,65 +348,15 @@ PrintString(char* fmt,...)
 static BOOL
 ConfirmQuit(PINPUT_RECORD Ir)
 {
-  SHORT xScreen;
-  SHORT yScreen;
-  SHORT yTop;
-  SHORT xLeft;
   BOOL Result = FALSE;
-  PUSHORT pAttributes = NULL;
-  PUCHAR pCharacters = NULL;
-  COORD Pos;
-
-  GetScreenSize(&xScreen, &yScreen);
-  yTop = (yScreen - 10) / 2;
-  xLeft = (xScreen - 52) / 2;
-
-  /* Save screen */
-#if 0
-  Pos.X = 0;
-  Pos.Y = 0;
-  pAttributes = (PUSHORT)RtlAllocateHeap(ProcessHeap,
-                                        0,
-                                        xScreen * yScreen * sizeof(USHORT));
-CHECKPOINT1;
-DPRINT1("pAttributes %p\n", pAttributes);
-  ReadConsoleOutputAttributes(pAttributes,
-                             xScreen * yScreen,
-                             Pos,
-                             NULL);
-CHECKPOINT1;
-  pCharacters = (PUCHAR)RtlAllocateHeap(ProcessHeap,
-                                       0,
-                                       xScreen * yScreen * sizeof(UCHAR));
-CHECKPOINT1;
-  ReadConsoleOutputCharacters(pCharacters,
-                             xScreen * yScreen,
-                             Pos,
-                             NULL);
-CHECKPOINT1;
-#endif
 
-  /* Draw popup window */
-  SetTextXY(xLeft, yTop,
-           "+----------------------------------------------------+");
-  SetTextXY(xLeft, yTop + 1,
-           "| ReactOS 0.0.20 is not completely installed on your |");
-  SetTextXY(xLeft, yTop + 2,
-           "| computer. If you quit Setup now, you will need to  |");
-  SetTextXY(xLeft, yTop + 3,
-           "| run Setup again to install ReactOS.                |");
-  SetTextXY(xLeft, yTop + 4,
-           "|                                                    |");
-  SetTextXY(xLeft, yTop + 5,
-           "|   * Press ENTER to continue Setup.                 |");
-  SetTextXY(xLeft, yTop + 6,
-           "|   * Press F3 to quit Setup.                        |");
-  SetTextXY(xLeft, yTop + 7,
-           "+----------------------------------------------------+");
-  SetTextXY(xLeft, yTop + 8,
-           "| F3= Quit  ENTER = Continue                         |");
-  SetTextXY(xLeft, yTop + 9,
-           "+----------------------------------------------------+");
+  PopupError("ReactOS is not completely installed on your\n"
+            "computer. If you quit Setup now, you will need to\n"
+            "run Setup again to install ReactOS.\n"
+            "\n"
+            "  * Press ENTER to continue Setup.\n"
+            "  * Press F3 to quit Setup.",
+            "F3= Quit  ENTER = Continue");
 
   while(TRUE)
     {
@@ -174,44 +375,27 @@ CHECKPOINT1;
        }
     }
 
-  /* Restore screen */
-#if 0
-CHECKPOINT1;
-  WriteConsoleOutputAttributes(pAttributes,
-                              xScreen * yScreen,
-                              Pos,
-                              NULL);
-CHECKPOINT1;
-
-  WriteConsoleOutputCharacters(pCharacters,
-                              xScreen * yScreen,
-                              Pos);
-CHECKPOINT1;
-
-  RtlFreeHeap(ProcessHeap,
-             0,
-             pAttributes);
-  RtlFreeHeap(ProcessHeap,
-             0,
-             pCharacters);
-#endif
-
   return(Result);
 }
 
 
 
-
 /*
- * First setup page
+ * Start page
  * RETURNS
- *     TRUE: setup/repair completed successfully
- *     FALSE: setup/repair terminated by user
+ *     Number of the next page.
  */
-static ULONG
+static PAGE_NUMBER
 StartPage(PINPUT_RECORD Ir)
 {
   NTSTATUS Status;
+  WCHAR FileNameBuffer[MAX_PATH];
+  UNICODE_STRING FileName;
+
+  INFCONTEXT Context;
+  PWCHAR Value;
+  ULONG ErrorLine;
+
 
   SetStatusText("   Please wait...");
 
@@ -227,31 +411,90 @@ StartPage(PINPUT_RECORD Ir)
       PrintTextXY(6, 16, "SourceRootPath: '%wZ'", &SourceRootPath);
     }
 
-  /*
-   * FIXME: Open and load txtsetup.sif here. A pointer (or handle) to the
-   * ini data should be stored in a global variable.
-   * The full path to txtsetup.sif is created by appending '\txtsetup.sif'
-   * to the unicode string SourceRootPath.
-   */
 
-  SetStatusText("   ENTER = Continue");
+  /* Load txtsetup.sif from install media. */
+  wcscpy(FileNameBuffer, SourceRootPath.Buffer);
+  wcscat(FileNameBuffer, L"\\install\\txtsetup.sif");
+  RtlInitUnicodeString(&FileName,
+                      FileNameBuffer);
 
-  while(TRUE)
+  Status = InfOpenFile(&SetupInf,
+                      &FileName,
+                      &ErrorLine);
+  if (!NT_SUCCESS(Status))
     {
-      ConInKey(Ir);
+      PopupError("Setup failed to load the file TXTSETUP.SIF.\n",
+                "ENTER = Reboot computer");
 
-      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)  /* ENTER */
+      while(TRUE)
        {
-         return(INTRO_PAGE);
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
+
+  /* Open 'Version' section */
+  if (!InfFindFirstLine (SetupInf, L"Version", L"Signature", &Context))
+    {
+      PopupError("Setup found a corrupt TXTSETUP.SIF.\n",
+                "ENTER = Reboot computer");
+
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
+
+
+  /* Get pointer 'Signature' key */
+  if (!InfGetData (&Context, NULL, &Value))
+    {
+      PopupError("Setup found a corrupt TXTSETUP.SIF.\n",
+                "ENTER = Reboot computer");
+
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
+
+  /* Check 'Signature' string */
+  if (_wcsicmp(Value, L"$ReactOS$") != 0)
+    {
+      PopupError("Setup found an invalid signature in TXTSETUP.SIF.\n",
+                "ENTER = Reboot computer");
+
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
        }
     }
 
-  return(START_PAGE);
+  return(INTRO_PAGE);
 }
 
 
 
-static ULONG
+static PAGE_NUMBER
 RepairIntroPage(PINPUT_RECORD Ir)
 {
   SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet");
@@ -259,9 +502,9 @@ RepairIntroPage(PINPUT_RECORD Ir)
 
   SetTextXY(6, 12, "The repair functions are not implemented yet.");
 
-  SetTextXY(8, 15, "\xf9  Press ESC to return to the main page.");
+  SetTextXY(8, 15, "\xfa  Press ESC to return to the main page.");
 
-  SetTextXY(8, 17, "\xf9  Press ENTER to reboot your computer.");
+  SetTextXY(8, 17, "\xfa  Press ENTER to reboot your computer.");
 
   SetStatusText("   ESC = Main page  ENTER = Reboot");
 
@@ -269,12 +512,12 @@ RepairIntroPage(PINPUT_RECORD Ir)
     {
       ConInKey(Ir);
 
-      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)          /* ENTER */
+      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
          return(REBOOT_PAGE);
        }
       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE))       /* ESC */
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
        {
          return(INTRO_PAGE);
        }
@@ -290,7 +533,7 @@ RepairIntroPage(PINPUT_RECORD Ir)
  *     TRUE: setup/repair completed successfully
  *     FALSE: setup/repair terminated by user
  */
-static ULONG
+static PAGE_NUMBER
 IntroPage(PINPUT_RECORD Ir)
 {
   SetHighlightedTextXY(6, 8, "Welcome to ReactOS Setup");
@@ -298,11 +541,13 @@ IntroPage(PINPUT_RECORD Ir)
   SetTextXY(6, 11, "This part of the setup copies the ReactOS Operating System to your");
   SetTextXY(6, 12, "computer and prepares the second part of the setup.");
 
-  SetTextXY(8, 15, "\xf9  Press ENTER to install ReactOS.");
+  SetTextXY(8, 15, "\xfa  Press ENTER to install ReactOS.");
 
-  SetTextXY(8, 17, "\xf9  Press R to repair ReactOS.");
+  SetTextXY(8, 17, "\xfa  Press E to start the emergency repair console.");
 
-  SetTextXY(8, 19, "\xf9  Press F3 to quit without installing ReactOS.");
+  SetTextXY(8, 19, "\xfa  Press R to repair ReactOS.");
+
+  SetTextXY(8, 21, "\xfa  Press F3 to quit without installing ReactOS.");
 
 
   SetStatusText("   ENTER = Continue   F3 = Quit");
@@ -312,17 +557,23 @@ IntroPage(PINPUT_RECORD Ir)
       ConInKey(Ir);
 
       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))        /* F3 */
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
          if (ConfirmQuit(Ir) == TRUE)
            return(QUIT_PAGE);
          break;
        }
-      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
          return(INSTALL_INTRO_PAGE);
        }
-      else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R')     /* R */
+#if 0
+      else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'E') /* E */
+       {
+         return(RepairConsole());
+       }
+#endif
+      else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
        {
          return(REPAIR_INTRO_PAGE);
        }
@@ -332,7 +583,7 @@ IntroPage(PINPUT_RECORD Ir)
 }
 
 
-static ULONG
+static PAGE_NUMBER
 InstallIntroPage(PINPUT_RECORD Ir)
 {
   SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet");
@@ -343,13 +594,12 @@ InstallIntroPage(PINPUT_RECORD Ir)
   SetTextXY(8, 14, "- Formatting partitions.");
   SetTextXY(8, 15, "- Support for non-FAT file systems.");
   SetTextXY(8, 16, "- Checking file systems.");
-  SetTextXY(8, 17, "- Installing the bootloader.");
 
 
 
-  SetTextXY(8, 21, "\xf9  Press ENTER to install ReactOS.");
+  SetTextXY(8, 21, "\xfa  Press ENTER to install ReactOS.");
 
-  SetTextXY(8, 23, "\xf9  Press F3 to quit without installing ReactOS.");
+  SetTextXY(8, 23, "\xfa  Press F3 to quit without installing ReactOS.");
 
 
   SetStatusText("   ENTER = Continue   F3 = Quit");
@@ -359,13 +609,13 @@ InstallIntroPage(PINPUT_RECORD Ir)
       ConInKey(Ir);
 
       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
          if (ConfirmQuit(Ir) == TRUE)
            return(QUIT_PAGE);
          break;
        }
-      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
+      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
          return(SELECT_PARTITION_PAGE);
        }
@@ -375,9 +625,47 @@ InstallIntroPage(PINPUT_RECORD Ir)
 }
 
 
-static ULONG
+/*
+ * Confirm delete partition
+ * RETURNS
+ *   TRUE: Delete currently selected partition.
+ *   FALSE: Don't delete currently selected partition.
+ */
+static BOOL
+ConfirmDeletePartition(PINPUT_RECORD Ir)
+{
+  BOOL Result = FALSE;
+
+  PopupError("Are you sure you want to delete this partition?\n"
+            "\n"
+            "  * Press ENTER to delete the partition.\n"
+            "  * Press ESC to NOT delete the partition.",
+            "ESC = Cancel  ENTER = Delete partition");
+
+  while(TRUE)
+    {
+      ConInKey(Ir);
+
+      if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)  /* ESC */
+       {
+         Result = FALSE;
+         break;
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN)        /* ENTER */
+       {
+         Result = TRUE;
+         break;
+       }
+    }
+
+  return(Result);
+}
+
+
+static PAGE_NUMBER
 SelectPartitionPage(PINPUT_RECORD Ir)
 {
+  WCHAR PathBuffer[MAX_PATH];
   PPARTLIST PartList;
   SHORT xScreen;
   SHORT yScreen;
@@ -385,13 +673,16 @@ SelectPartitionPage(PINPUT_RECORD Ir)
   SetTextXY(6, 8, "The list below shows existing partitions and unused disk");
   SetTextXY(6, 9, "space for new partitions.");
 
-  SetTextXY(8, 11, "\xf9  Press UP or DOWN to select a list entry.");
-  SetTextXY(8, 13, "\xf9  Press ENTER to install ReactOS onto the selected partition.");
-  SetTextXY(8, 15, "\xf9  Press C to create a new partition.");
-  SetTextXY(8, 17, "\xf9  Press D to delete an existing partition.");
+  SetTextXY(8, 11, "\xfa  Press UP or DOWN to select a list entry.");
+  SetTextXY(8, 13, "\xfa  Press ENTER to install ReactOS onto the selected partition.");
+  SetTextXY(8, 15, "\xfa  Press C to create a new partition.");
+  SetTextXY(8, 17, "\xfa  Press D to delete an existing partition.");
 
   SetStatusText("   Please wait...");
 
+  RtlFreeUnicodeString(&DestinationPath);
+  RtlFreeUnicodeString(&DestinationRootPath);
+
   GetScreenSize(&xScreen, &yScreen);
 
   PartList = CreatePartitionList(2, 19, xScreen - 3, yScreen - 3);
@@ -401,6 +692,12 @@ SelectPartitionPage(PINPUT_RECORD Ir)
       return(QUIT_PAGE);
     }
 
+  if (CurrentPartitionList != NULL)
+    {
+      DestroyPartitionList(CurrentPartitionList);
+    }
+  CurrentPartitionList = PartList;
+
   SetStatusText("   ENTER = Continue   F3 = Quit");
 
   while(TRUE)
@@ -408,7 +705,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
       ConInKey(Ir);
 
       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
          if (ConfirmQuit(Ir) == TRUE)
            {
@@ -418,81 +715,552 @@ SelectPartitionPage(PINPUT_RECORD Ir)
          break;
        }
       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN))
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
        {
          ScrollDownPartitionList(PartList);
        }
       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP))
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
        {
          ScrollUpPartitionList(PartList);
        }
-      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
+       {
+         PartDataValid = GetSelectedPartition(PartList,
+                                              &PartData);
+    if (PartDataValid)
+      {
+         ActivePartitionValid = GetActiveBootPartition(PartList,
+                                                       &ActivePartition);
+    
+         RtlFreeUnicodeString(&DestinationRootPath);
+         swprintf(PathBuffer,
+                  L"\\Device\\Harddisk%lu\\Partition%lu",
+                  PartData.DiskNumber,
+                  PartData.PartNumber);
+         RtlCreateUnicodeString(&DestinationRootPath,
+                                PathBuffer);
+    
+         RtlFreeUnicodeString(&SystemRootPath);
+    
+          if (ActivePartitionValid)
+            {
+             swprintf(PathBuffer,
+                   L"\\Device\\Harddisk%lu\\Partition%lu",
+                   ActivePartition.DiskNumber,
+                   ActivePartition.PartNumber);
+            }
+          else
+            {
+              /* We mark the selected partition as bootable */
+             swprintf(PathBuffer,
+                   L"\\Device\\Harddisk%lu\\Partition%lu",
+                   PartData.DiskNumber,
+                   PartData.PartNumber);
+            }
+         RtlCreateUnicodeString(&SystemRootPath,
+                                PathBuffer);
+    
+         return(SELECT_FILE_SYSTEM_PAGE);
+      }
+    else
+      {
+        /* FIXME: show an error dialog */
+        return(SELECT_PARTITION_PAGE);
+      }
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_C) /* C */
        {
-         PartDataValid = GetPartitionData(PartList, &PartData);
-         DestroyPartitionList(PartList);
-         return(SELECT_FILE_SYSTEM_PAGE);
+#ifdef ENABLE_FORMAT
+    /* Don't destroy the parition list here */;
+    return(CREATE_PARTITION_PAGE);
+#endif
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_D) /* D */
+       {
+#ifdef ENABLE_FORMAT
+         if (ConfirmDeletePartition(Ir) == TRUE)
+      {
+        (BOOLEAN) DeleteSelectedPartition(CurrentPartitionList);
+      }
+    return(SELECT_PARTITION_PAGE);
+#endif
        }
 
       /* FIXME: Update status text */
 
     }
 
-  DestroyPartitionList(PartList);
-
   return(SELECT_PARTITION_PAGE);
 }
 
+static VOID
+DrawInputField(ULONG FieldLength,
+  SHORT Left,
+  SHORT Top,
+  PCHAR FieldContent)
+{
+  CHAR buf[100];
+  COORD coPos;
+
+  coPos.X = Left;
+  coPos.Y = Top;
+  memset(buf, '_', sizeof(buf));
+  buf[FieldLength - strlen(FieldContent)] = 0;
+  strcat(buf, FieldContent);
+  WriteConsoleOutputCharacters(buf,
+              strlen(buf),
+              coPos);
+}
+
+#define PARTITION_SIZE_INPUT_FIELD_LENGTH 6
 
-static ULONG
-SelectFileSystemPage(PINPUT_RECORD Ir)
+static VOID
+ShowPartitionSizeInputBox(ULONG MaxSize,
+  PCHAR InputBuffer,
+  PBOOLEAN Quit,
+  PBOOLEAN Cancel)
 {
-  ULONGLONG DiskSize;
+  SHORT Left;
+  SHORT Top;
+  SHORT Right;
+  SHORT Bottom;
+  INPUT_RECORD Ir;
+  COORD coPos;
+  ULONG Written;
+  SHORT i;
+  CHAR buf[100];
+  ULONG index;
+  CHAR ch;
+  SHORT iLeft;
+  SHORT iTop;
+  SHORT xScreen;
+  SHORT yScreen;
+
+  if (Quit != NULL)
+    *Quit = FALSE;
+  if (Cancel != NULL)
+    *Cancel = FALSE;
+
+  GetScreenSize(&xScreen, &yScreen);
+  Left = 12;
+  Top = 11;
+  Right = xScreen - 12;
+  Bottom = 15;
+
+  /* draw upper left corner */
+  coPos.X = Left;
+  coPos.Y = Top;
+  FillConsoleOutputCharacter(0xDA, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* draw upper edge */
+  coPos.X = Left + 1;
+  coPos.Y = Top;
+  FillConsoleOutputCharacter(0xC4, // '-',
+                            Right - Left - 1,
+                            coPos,
+                            &Written);
+
+  /* draw upper right corner */
+  coPos.X = Right;
+  coPos.Y = Top;
+  FillConsoleOutputCharacter(0xBF, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* draw left and right edge */
+  for (i = Top + 1; i < Bottom; i++)
+    {
+      coPos.X = Left;
+      coPos.Y = i;
+      FillConsoleOutputCharacter(0xB3, // '|',
+                                1,
+                                coPos,
+                                &Written);
+
+      coPos.X = Right;
+      FillConsoleOutputCharacter(0xB3, //'|',
+                                1,
+                                coPos,
+                                &Written);
+    }
+
+  /* draw lower left corner */
+  coPos.X = Left;
+  coPos.Y = Bottom;
+  FillConsoleOutputCharacter(0xC0, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* draw lower edge */
+  coPos.X = Left + 1;
+  coPos.Y = Bottom;
+  FillConsoleOutputCharacter(0xC4, // '-',
+                            Right - Left - 1,
+                            coPos,
+                            &Written);
+
+  /* draw lower right corner */
+  coPos.X = Right;
+  coPos.Y = Bottom;
+  FillConsoleOutputCharacter(0xD9, // '+',
+                            1,
+                            coPos,
+                            &Written);
+
+  /* Print message */
+  coPos.X = Left + 2;
+  coPos.Y = Top + 2;
+  strcpy(buf, "Size of new partition:");
+  iLeft = coPos.X + strlen(buf) + 1;
+  iTop = coPos.Y;
+  WriteConsoleOutputCharacters(buf,
+                      strlen(buf),
+                      coPos);
+
+  sprintf(buf, "MB (max. %d MB)", MaxSize / (1024 * 1024));
+  coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
+  coPos.Y = iTop;
+  WriteConsoleOutputCharacters(buf,
+                      strlen(buf),
+                      coPos);
+
+  buf[0] = 0;
+  index = 0;
+  DrawInputField(PARTITION_SIZE_INPUT_FIELD_LENGTH, iLeft, iTop, buf);
+
+  while(TRUE)
+    {
+      ConInKey(&Ir);
+      if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+           (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3))       /* F3 */
+       {
+          if (Quit != NULL)
+            *Quit = TRUE;
+          buf[0] = 0;
+         break;
+       }
+      else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
+       {
+                 break;
+       }
+      else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
+       {
+          if (Cancel != NULL)
+            *Cancel = FALSE;
+          buf[0] = 0;
+                 break;
+       }
+      else if ((Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) && (index > 0)) /* BACKSPACE */
+       {
+          index--;
+          buf[index] = 0;
+          DrawInputField(PARTITION_SIZE_INPUT_FIELD_LENGTH, iLeft, iTop, buf);
+       }
+      else if ((Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
+        && (index < PARTITION_SIZE_INPUT_FIELD_LENGTH))
+        {
+          ch = Ir.Event.KeyEvent.uChar.AsciiChar;
+          if ((ch >= '0') && (ch <= '9'))
+            {
+              buf[index] = ch;
+              index++;
+              buf[index] = 0;
+              DrawInputField(PARTITION_SIZE_INPUT_FIELD_LENGTH, iLeft, iTop, buf);
+            }
+        }
+    }
+  strcpy(InputBuffer, buf);
+}
+
+
+static PAGE_NUMBER
+CreatePartitionPage(PINPUT_RECORD Ir)
+{
+  BOOLEAN Valid;
+  WCHAR PathBuffer[MAX_PATH];
+  PPARTLIST PartList;
+  PPARTENTRY PartEntry;
+  SHORT xScreen;
+  SHORT yScreen;
+  BOOLEAN Quit;
+  BOOLEAN Cancel;
+  CHAR InputBuffer[50];
+  ULONG MaxSize;
   ULONGLONG PartSize;
-  PCHAR DiskUnit;
-  PCHAR PartUnit;
-  PCHAR PartType;
 
-  if (PartDataValid == FALSE)
+  SetTextXY(6, 8, "You have chosen to create a new partition in the unused disk space.");
+  SetTextXY(6, 9, "Please enter the size of the new partition in megabytes.");
+
+  SetStatusText("   Please wait...");
+
+  GetScreenSize(&xScreen, &yScreen);
+
+  PartList = CurrentPartitionList;
+
+  SetStatusText("   ENTER = Continue   ESC = Cancel   F3 = Quit");
+
+  PartEntry = &PartList->DiskArray[PartList->CurrentDisk].PartArray[PartList->CurrentPartition];
+  while (TRUE)
     {
-      /* FIXME: show an error dialog */
-      return(QUIT_PAGE);
+      MaxSize = PartEntry->PartSize;
+      ShowPartitionSizeInputBox(MaxSize, InputBuffer, &Quit, &Cancel);
+      if (Quit == TRUE)
+        {
+         if (ConfirmQuit(Ir) == TRUE)
+           {
+             DestroyPartitionList(PartList);
+             return(QUIT_PAGE);
+           }
+        }
+      else if (Cancel == TRUE)
+        {
+          break;
+        }
+      else
+        {
+          PartSize = atoi(InputBuffer);
+          if (PartSize < 1)
+            {
+              // Too small
+              continue;
+            }
+          /* Convert to bytes */
+          PartSize *= 1024 * 1024;
+
+          if (PartSize > PartEntry->PartSize)
+            {
+              // Too large
+              continue;
+            }
+
+          assert(PartEntry->Unpartitioned == TRUE);
+          PartEntry->PartType = PARTITION_ENTRY_UNUSED;
+          PartEntry->Used = TRUE;
+
+         PartDataValid = GetSelectedPartition(PartList,
+                                              &PartData);
+          if (PartDataValid)
+            {
+              PartData.CreatePartition = TRUE;
+              PartData.NewPartSize = PartSize;
+
+                 ActivePartitionValid = GetActiveBootPartition(PartList,
+                                                               &ActivePartition);
+
+                 RtlFreeUnicodeString(&DestinationRootPath);
+                 swprintf(PathBuffer,
+                          L"\\Device\\Harddisk%lu\\Partition%lu",
+                          PartData.DiskNumber,
+                          PartData.PartNumber);
+                 RtlCreateUnicodeString(&DestinationRootPath,
+                                        PathBuffer);
+
+                 RtlFreeUnicodeString(&SystemRootPath);
+
+              if (ActivePartitionValid)
+                {
+                     swprintf(PathBuffer,
+                           L"\\Device\\Harddisk%lu\\Partition%lu",
+                           ActivePartition.DiskNumber,
+                           ActivePartition.PartNumber);
+                }
+              else
+                {
+                  /* We mark the selected partition as bootable */
+                     swprintf(PathBuffer,
+                           L"\\Device\\Harddisk%lu\\Partition%lu",
+                           PartData.DiskNumber,
+                           PartData.PartNumber);
+                }
+                 RtlCreateUnicodeString(&SystemRootPath,
+                                        PathBuffer);
+
+                 return(SELECT_FILE_SYSTEM_PAGE);
+            }
+          else
+            {
+              /* FIXME: show an error dialog */
+              return(SELECT_PARTITION_PAGE);
+            }
+        }
     }
 
-  /* adjust disk size */
-  if (PartData.DiskSize >= 0x280000000ULL) /* 10 GB */
+  return(SELECT_PARTITION_PAGE);
+}
+
+
+static PFILE_SYSTEM_LIST
+CreateFileSystemList(SHORT Left,
+  SHORT Top,
+  BOOLEAN ForceFormat,
+  FILE_SYSTEM ForceFileSystem)
+{
+  PFILE_SYSTEM_LIST List;
+
+  List = (PFILE_SYSTEM_LIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(FILE_SYSTEM_LIST));
+  if (List == NULL)
+    return(NULL);
+
+  List->Left = Left;
+  List->Top = Top;
+
+#ifdef ENABLE_FORMAT
+  List->FileSystemCount = 1;
+#else
+  List->FileSystemCount = 0;
+#endif
+  if (ForceFormat)
     {
-      DiskSize = (PartData.DiskSize + (1 << 29)) >> 30;
-      DiskUnit = "GB";
+      List->CurrentFileSystem = ForceFileSystem;
     }
   else
     {
-      DiskSize = (PartData.DiskSize + (1 << 19)) >> 20;
-      DiskUnit = "MB";
+      List->FileSystemCount++;
+      List->CurrentFileSystem = FsKeep;
     }
+  return(List);
+}
 
-  /* adjust partition size */
-  if (PartData.PartSize >= 0x280000000ULL) /* 10 GB */
+
+static VOID
+DestroyFileSystemList(PFILE_SYSTEM_LIST List)
+{
+  RtlFreeHeap(ProcessHeap, 0, List);
+}
+
+
+static VOID
+DrawFileSystemList(PFILE_SYSTEM_LIST List)
+{
+  COORD coPos;
+  ULONG Written;
+  ULONG index;
+
+  index = 0;
+
+#ifdef ENABLE_FORMAT
+  coPos.X = List->Left;
+  coPos.Y = List->Top + index;
+  FillConsoleOutputAttribute(0x17,
+                            50,
+                            coPos,
+                            &Written);
+  FillConsoleOutputCharacter(' ',
+                            50,
+                            coPos,
+                            &Written);
+
+  if (List->CurrentFileSystem == FsFat)
     {
-      PartSize = (PartData.PartSize + (1 << 29)) >> 30;
-      PartUnit = "GB";
+      SetInvertedTextXY(List->Left, List->Top + index, " Format partition as FAT file system ");
     }
   else
     {
-      PartSize = (PartData.PartSize + (1 << 19)) >> 20;
-      PartUnit = "MB";
+      SetTextXY(List->Left, List->Top + index, " Format partition as FAT file system ");
     }
+  index++;
+#endif
 
-  /* adjust partition type */
-  if ((PartData.PartType == PARTITION_FAT_12) ||
-      (PartData.PartType == PARTITION_FAT_16) ||
-      (PartData.PartType == PARTITION_HUGE) ||
-      (PartData.PartType == PARTITION_XINT13))
+  coPos.X = List->Left;
+  coPos.Y = List->Top + index;
+  FillConsoleOutputAttribute(0x17,
+                            50,
+                            coPos,
+                            &Written);
+  FillConsoleOutputCharacter(' ',
+                            50,
+                            coPos,
+                            &Written);
+
+  if (List->CurrentFileSystem == FsKeep)
     {
-      PartType = "FAT";
+      SetInvertedTextXY(List->Left, List->Top + index, " Keep current file system (no changes) ");
     }
-  else if ((PartData.PartType == PARTITION_FAT32) ||
-          (PartData.PartType == PARTITION_FAT32_XINT13))
+  else
+    {
+      SetTextXY(List->Left, List->Top + index, " Keep current file system (no changes) ");
+    }
+}
+
+
+static VOID
+ScrollDownFileSystemList(PFILE_SYSTEM_LIST List)
+{
+  if ((ULONG) List->CurrentFileSystem < List->FileSystemCount - 1)
+    {
+      (ULONG) List->CurrentFileSystem++;
+      DrawFileSystemList(List);
+    }
+}
+
+
+static VOID
+ScrollUpFileSystemList(PFILE_SYSTEM_LIST List)
+{
+  if ((ULONG) List->CurrentFileSystem > 0)
+    {
+      (ULONG) List->CurrentFileSystem--;
+      DrawFileSystemList(List);
+    }
+}
+
+
+static PAGE_NUMBER
+SelectFileSystemPage(PINPUT_RECORD Ir)
+{
+  PFILE_SYSTEM_LIST FileSystemList;
+  ULONGLONG DiskSize;
+  ULONGLONG PartSize;
+  PCHAR DiskUnit;
+  PCHAR PartUnit;
+  PCHAR PartType;
+
+  if (PartDataValid == FALSE)
+    {
+      /* FIXME: show an error dialog */
+      return(QUIT_PAGE);
+    }
+
+  /* adjust disk size */
+  if (PartData.DiskSize >= 0x280000000ULL) /* 10 GB */
+    {
+      DiskSize = (PartData.DiskSize + (1 << 29)) >> 30;
+      DiskUnit = "GB";
+    }
+  else
+    {
+      DiskSize = (PartData.DiskSize + (1 << 19)) >> 20;
+      DiskUnit = "MB";
+    }
+
+  /* adjust partition size */
+  if (PartData.PartSize >= 0x280000000ULL) /* 10 GB */
+    {
+      PartSize = (PartData.PartSize + (1 << 29)) >> 30;
+      PartUnit = "GB";
+    }
+  else
+    {
+      PartSize = (PartData.PartSize + (1 << 19)) >> 20;
+      PartUnit = "MB";
+    }
+
+  /* adjust partition type */
+  if ((PartData.PartType == PARTITION_FAT_12) ||
+      (PartData.PartType == PARTITION_FAT_16) ||
+      (PartData.PartType == PARTITION_HUGE) ||
+      (PartData.PartType == PARTITION_XINT13))
+    {
+      PartType = "FAT";
+    }
+  else if ((PartData.PartType == PARTITION_FAT32) ||
+          (PartData.PartType == PARTITION_FAT32_XINT13))
     {
       PartType = "FAT32";
     }
@@ -500,36 +1268,49 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
     {
       PartType = "NTFS"; /* FIXME: Not quite correct! */
     }
+  else if (PartData.PartType == PARTITION_ENTRY_UNUSED)
+    {
+      PartType = "Unused";
+    }
   else
     {
       PartType = "Unknown";
     }
 
-  SetTextXY(6, 8, "ReactOS will be installed");
+  SetTextXY(6, 8, "Setup will install ReactOS on");
 
-  PrintTextXY(8, 9, "on Harddisk %lu (%I64u %s), Port=%hu, Bus=%hu, Id=%hu.",
+  PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
+             PartData.PartNumber,
+             PartSize,
+             PartUnit,
+             PartType);
+
+  PrintTextXY(8, 12, "Harddisk %lu (%I64u %s), Port=%hu, Bus=%hu, Id=%hu (%wZ).",
              PartData.DiskNumber,
              DiskSize,
              DiskUnit,
              PartData.Port,
              PartData.Bus,
-             PartData.Id);
+             PartData.Id,
+             &PartData.DriverName);
 
-  PrintTextXY(8, 10, "on Partition %lu (%I64u %s) %s",
-             PartData.PartNumber,
-             PartSize,
-             PartUnit,
-             PartType);
 
-  SetTextXY(6, 13, "Select a file system for the partition from the list below.");
+  SetTextXY(6, 17, "Select a file system for the partition from the list below.");
+
+  SetTextXY(8, 19, "\xfa  Press UP or DOWN to select a file system.");
+  SetTextXY(8, 21, "\xfa  Press ENTER to format the partition.");
+  SetTextXY(8, 23, "\xfa  Press ESC to select another partition.");
 
-  SetTextXY(8, 15, "\xf9  Press UP or DOWN to select a file system.");
-  SetTextXY(8, 17, "\xf9  Press ENTER to format the partition.");
-  SetTextXY(8, 19, "\xf9  Press ESC to select another partition.");
+  FileSystemList = CreateFileSystemList(6, 26, FALSE, FsKeep);
+  if (FileSystemList == NULL)
+    {
+      /* FIXME: show an error dialog */
+      return(QUIT_PAGE);
+    }
 
-  /* FIXME: use a real list later */
-  SetInvertedTextXY(6, 22, " Keep current file system (no changes) ");
+  CurrentFileSystemList = FileSystemList;
 
+  DrawFileSystemList(FileSystemList);
 
   SetStatusText("   ENTER = Continue   ESC = Cancel   F3 = Quit");
 
@@ -538,26 +1319,120 @@ SelectFileSystemPage(PINPUT_RECORD Ir)
       ConInKey(Ir);
 
       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
          if (ConfirmQuit(Ir) == TRUE)
            return(QUIT_PAGE);
          break;
        }
       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE))       /* ESC */
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
        {
+    DestroyFileSystemList(FileSystemList);
          return(SELECT_PARTITION_PAGE);
        }
-      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
+       {
+         ScrollDownFileSystemList(FileSystemList);
+       }
+      else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+              (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
        {
-         return(CHECK_FILE_SYSTEM_PAGE);
+         ScrollUpFileSystemList(FileSystemList);
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
+       {
+    if (FileSystemList->CurrentFileSystem == FsKeep)
+      {
+        return(CHECK_FILE_SYSTEM_PAGE);
+      }
+    else
+      {
+        return(FORMAT_PARTITION_PAGE);
+      }
        }
     }
-
-  return(SELECT_FILE_SYSTEM_PAGE);
 }
 
+static ULONG
+FormatPartitionPage(PINPUT_RECORD Ir)
+{
+  NTSTATUS Status;
+  ULONG PartType;
+  BOOLEAN Valid;
+
+  SetTextXY(6, 8, "Format partition");
+
+  SetTextXY(6, 10, "Setup will now format the partition. Press ENTER to continue.");
+
+  SetStatusText("   ENTER = Continue   F3 = Quit");
+
+  while(TRUE)
+    {
+      ConInKey(Ir);
+
+      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+       {
+         if (ConfirmQuit(Ir) == TRUE)
+      {
+             return(QUIT_PAGE);
+      }
+         break;
+       }
+      else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
+       {
+    SetStatusText("   Please wait ...");
+
+    switch (CurrentFileSystemList->CurrentFileSystem)
+      {
+#ifdef ENABLE_FORMAT
+        case FsFat:
+          PartType = PARTITION_FAT32_XINT13;
+          break;
+#endif
+        case FsKeep:
+          break;
+        default:
+          return QUIT_PAGE;
+      }
+
+    if (PartData.CreatePartition)
+      {
+         Valid = CreateSelectedPartition(CurrentPartitionList, PartType, PartData.NewPartSize);
+        if (!Valid)
+          {
+            DPRINT("CreateSelectedPartition() failed\n");
+            /* FIXME: show an error dialog */
+            return(QUIT_PAGE);
+          }
+      }
+
+    switch (CurrentFileSystemList->CurrentFileSystem)
+      {
+#ifdef ENABLE_FORMAT
+        case FsFat:
+          Status = FormatPartition(&DestinationRootPath);
+          if (!NT_SUCCESS(Status))
+            {
+              DPRINT1("FormatPartition() failed with status 0x%.08x\n", Status);
+              /* FIXME: show an error dialog */
+              return(QUIT_PAGE);
+            }
+          break;
+#endif
+        case FsKeep:
+          break;
+        default:
+          return QUIT_PAGE;
+      }
+    return(INSTALL_DIRECTORY_PAGE);
+       }
+    }
+
+  return(INSTALL_DIRECTORY_PAGE);
+}
 
 static ULONG
 CheckFileSystemPage(PINPUT_RECORD Ir)
@@ -576,7 +1451,7 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
       ConInKey(Ir);
 
       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
          if (ConfirmQuit(Ir) == TRUE)
            return(QUIT_PAGE);
@@ -592,24 +1467,54 @@ CheckFileSystemPage(PINPUT_RECORD Ir)
 }
 
 
-static ULONG
+static PAGE_NUMBER
 InstallDirectoryPage(PINPUT_RECORD Ir)
 {
+  WCHAR PathBuffer[MAX_PATH];
+  WCHAR InstallDir[51];
+  PWCHAR DefaultPath;
+  INFCONTEXT Context;
   ULONG Length;
+  NTSTATUS Status;
+
+  /* Search for 'DefaultPath' in the 'SetupData' section */
+  if (!InfFindFirstLine (SetupInf, L"SetupData", L"DefaultPath", &Context))
+    {
+      PopupError("Setup failed to find the 'SetupData' section\n"
+                "in TXTSETUP.SIF.\n",
+                "ENTER = Reboot computer");
+
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
+
+  /* Read the 'DefaultPath' data */
+  if (InfGetData (&Context, NULL, &DefaultPath))
+    {
+      wcscpy(InstallDir, DefaultPath);
+    }
+  else
+    {
+      wcscpy(InstallDir, L"\\ReactOS");
+    }
+  Length = wcslen(InstallDir);
 
   SetTextXY(6, 8, "Setup installs ReactOS files onto the selected partition. Choose a");
   SetTextXY(6, 9, "directory where you want ReactOS to be installed:");
 
-  strcpy(InstallDir, "\\reactos");
-  Length = strlen(InstallDir);
-
   SetInputTextXY(8, 11, 51, InstallDir);
 
   SetTextXY(6, 14, "To change the suggested directory, press BACKSPACE to delete");
   SetTextXY(6, 15, "characters and then type the directory where you want ReactOS to");
   SetTextXY(6, 16, "be installed.");
 
-
   SetStatusText("   ENTER = Continue   F3 = Quit");
 
   while(TRUE)
@@ -617,7 +1522,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
       ConInKey(Ir);
 
       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))
+         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
        {
          if (ConfirmQuit(Ir) == TRUE)
            return(QUIT_PAGE);
@@ -625,6 +1530,35 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
        }
       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
+         /* Create 'InstallPath' string */
+         RtlFreeUnicodeString(&InstallPath);
+         RtlCreateUnicodeString(&InstallPath,
+                                InstallDir);
+
+         /* Create 'DestinationPath' string */
+         RtlFreeUnicodeString(&DestinationPath);
+         wcscpy(PathBuffer,
+                DestinationRootPath.Buffer);
+         if (InstallDir[0] != L'\\')
+           wcscat(PathBuffer,
+                  L"\\");
+         wcscat(PathBuffer, InstallDir);
+         RtlCreateUnicodeString(&DestinationPath,
+                                PathBuffer);
+
+         /* Create 'DestinationArcPath' */
+         RtlFreeUnicodeString(&DestinationArcPath);
+         swprintf(PathBuffer,
+                  L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
+                  PartData.DiskNumber,
+                  PartData.PartNumber);
+         if (InstallDir[0] != L'\\')
+           wcscat(PathBuffer,
+                  L"\\");
+         wcscat(PathBuffer, InstallDir);
+         RtlCreateUnicodeString(&DestinationArcPath,
+                                PathBuffer);
+
          return(PREPARE_COPY_PAGE);
        }
       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
@@ -640,7 +1574,7 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
        {
          if (Length < 50)
            {
-             InstallDir[Length] = Ir->Event.KeyEvent.uChar.AsciiChar;
+             InstallDir[Length] = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
              Length++;
              InstallDir[Length] = 0;
              SetInputTextXY(8, 11, 51, InstallDir);
@@ -652,351 +1586,1095 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
 }
 
 
-static ULONG
+static PAGE_NUMBER
 PrepareCopyPage(PINPUT_RECORD Ir)
 {
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  IO_STATUS_BLOCK IoStatusBlock;
-  CHAR PathBuffer[MAX_PATH];
-  UNICODE_STRING PathName;
-  HANDLE DirectoryHandle;
-  NTSTATUS Status;
-  PCHAR End;
+  WCHAR PathBuffer[MAX_PATH];
+  INFCONTEXT FilesContext;
+  INFCONTEXT DirContext;
+  PWCHAR KeyName;
+  PWCHAR KeyValue;
   ULONG Length;
-  ULONG i;
+  NTSTATUS Status;
 
-  PCHAR Dirs[]= {
-    "System32",
-    "System32\\Config",
-    "System32\\Drivers",
-    "Inf",
-    "Help",
-    "Fonts",
-    NULL};
+  PWCHAR FileKeyName;
+  PWCHAR FileKeyValue;
+  PWCHAR DirKeyName;
+  PWCHAR DirKeyValue;
 
   SetTextXY(6, 8, "Setup prepares your computer for copying the ReactOS files. ");
 
 
-  SetTextXY(8, 12, "Build file copy list");
+//  SetTextXY(8, 12, "Build file copy list");
 
-  SetTextXY(8, 14, "Create directories");
+//  SetTextXY(8, 14, "Create directories");
 
-  SetStatusText("   Please wait...");
+//  SetStatusText("   Please wait...");
 
+  /*
+   * Build the file copy list
+   */
+  SetStatusText("   Building the file copy list...");
+//  SetInvertedTextXY(8, 12, "Build file copy list");
 
-  /* build the file copy list */
 
-  SetInvertedTextXY(8, 12, "Build file copy list");
 
-  /* FIXME: build that list */
+  /* Search for the 'SourceFiles' section */
+  if (!InfFindFirstLine (SetupInf, L"SourceFiles", NULL, &FilesContext))
+    {
+      PopupError("Setup failed to find the 'SourceFiles' section\n"
+                "in TXTSETUP.SIF.\n",
+                "ENTER = Reboot computer");
 
-  SetTextXY(8, 12, "Build file copy list");
-  SetHighlightedTextXY(50, 12, "Done");
+      while(TRUE)
+       {
+         ConInKey(Ir);
 
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
 
-  /* create directories */
-  SetInvertedTextXY(8, 14, "Create directories");
 
+  /* Create the file queue */
+  SetupFileQueue = SetupOpenFileQueue();
+  if (SetupFileQueue == NULL)
+    {
+      PopupError("Setup failed to open the copy file queue.\n",
+                "ENTER = Reboot computer");
+
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
 
   /*
-   * FIXME: Enumerate the ini section 'Directories' and create all "relative" directories
+   * Enumerate the files in the 'SourceFiles' section
+   * and add them to the file queue.
    */
+  do
+    {
+      if (!InfGetData (&FilesContext, &FileKeyName, &FileKeyValue))
+       break;
 
+      DPRINT1("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
 
-  /* create the systemroot directory */
-  sprintf(PathBuffer,
-         "\\Device\\Harddisk%lu\\Partition%lu",
-         PartData.DiskNumber,
-         PartData.PartNumber);
-  if (InstallDir[0] != '\\')
-    strcat(PathBuffer, "\\");
-  strcat(PathBuffer, InstallDir);
+      /* Lookup target directory */
+      if (!InfFindFirstLine (SetupInf, L"Directories", FileKeyValue, &DirContext))
+       {
+         /* FIXME: Handle error! */
+         DPRINT1("InfFindFirstLine() failed\n");
+         break;
+       }
 
-  /* remove trailing backslash */
-  Length = strlen(PathBuffer);
-  if ((Length > 0) && (PathBuffer[Length - 1] == '\\'))
-    PathBuffer[Length - 1] = 0;
-
-  RtlCreateUnicodeStringFromAsciiz(&PathName,
-                                  PathBuffer);
-
-  ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
-  ObjectAttributes.RootDirectory = NULL;
-  ObjectAttributes.ObjectName = &PathName;
-  ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE | OBJ_INHERIT;
-  ObjectAttributes.SecurityDescriptor = NULL;
-  ObjectAttributes.SecurityQualityOfService = NULL;
-
-  Status = NtCreateFile(&DirectoryHandle,
-                       DIRECTORY_ALL_ACCESS,
-                       &ObjectAttributes,
-                       &IoStatusBlock,
-                       NULL,
-                       FILE_ATTRIBUTE_DIRECTORY,
-                       0,
-                       FILE_CREATE,
-                       FILE_DIRECTORY_FILE,
-                       NULL,
-                       0);
-  if (!NT_SUCCESS(Status))
-    {
-      PrintTextXY(6, 25, "Creating directory failed: Status = 0x%08lx", Status);
+      if (!InfGetData (&DirContext, NULL, &DirKeyValue))
+       {
+         /* FIXME: Handle error! */
+         DPRINT1("InfGetData() failed\n");
+         break;
+       }
 
+      if (!SetupQueueCopy(SetupFileQueue,
+                         SourceRootPath.Buffer,
+                         L"\\install",
+                         FileKeyName,
+                         DirKeyValue,
+                         NULL))
+       {
+         /* FIXME: Handle error! */
+         DPRINT1("SetupQueueCopy() failed\n");
+       }
     }
-  else
-    {
-      PrintTextXY(6, 25, "Created directory.");
-      NtClose (DirectoryHandle);
-    }
+  while (InfFindNextLine(&FilesContext, &FilesContext));
 
 
-  RtlFreeUnicodeString(&PathName);
+  /* Create directories */
+  SetStatusText("   Creating directories...");
 
+  /*
+   * FIXME:
+   * Install directories like '\reactos\test' are not handled yet.
+   */
 
-  /* create the subdirectories */
+  /* Get destination path */
+  wcscpy(PathBuffer, DestinationPath.Buffer);
 
-  /* append backslash and init end pointer */
-  strcat(PathBuffer, "\\");
-  Length = strlen(PathBuffer);
-  End = &PathBuffer[Length];
+  /* Remove trailing backslash */
+  Length = wcslen(PathBuffer);
+  if ((Length > 0) && (PathBuffer[Length - 1] == '\\'))
+    {
+      PathBuffer[Length - 1] = 0;
+    }
 
-  for (i = 0; Dirs[i] != NULL; i++)
+  /* Create the install directory */
+  Status = CreateDirectory(PathBuffer);
+  if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
     {
-      strcpy(End, Dirs[i]);
+      DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
+      PopupError("Setup could not create the install directory.",
+                "ENTER = Reboot computer");
 
+      while(TRUE)
+       {
+         ConInKey(Ir);
 
-      RtlCreateUnicodeStringFromAsciiz(&PathName,
-                                      PathBuffer);
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
 
 
-      ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
-      ObjectAttributes.RootDirectory = NULL;
-      ObjectAttributes.ObjectName = &PathName;
-      ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE | OBJ_INHERIT;
-      ObjectAttributes.SecurityDescriptor = NULL;
-      ObjectAttributes.SecurityQualityOfService = NULL;
+  /* Search for the 'Directories' section */
+  if (!InfFindFirstLine(SetupInf, L"Directories", NULL, &DirContext))
+    {
+      PopupError("Setup failed to find the 'Directories' section\n"
+                "in TXTSETUP.SIF.\n",
+                "ENTER = Reboot computer");
 
-      Status = NtCreateFile(&DirectoryHandle,
-                           DIRECTORY_ALL_ACCESS,
-                           &ObjectAttributes,
-                           &IoStatusBlock,
-                           NULL,
-                           FILE_ATTRIBUTE_DIRECTORY,
-                           0,
-                           FILE_CREATE,
-                           FILE_DIRECTORY_FILE,
-                           NULL,
-                           0);
-      if (!NT_SUCCESS(Status))
+      while(TRUE)
        {
-         PrintTextXY(6, 25, "Creating directory failed: Status = 0x%08lx", Status);
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
        }
-      else
+    }
+
+  /* Enumerate the directory values and create the subdirectories */
+  do
+    {
+      if (!InfGetData (&DirContext, NULL, &KeyValue))
+       break;
+
+      if (KeyValue[0] == L'\\' && KeyValue[1] != 0)
        {
-         PrintTextXY(6, 25, "Created directory.");
-         NtClose (DirectoryHandle);
+             DPRINT("Absolute Path: '%S'\n", KeyValue);
+
+             wcscpy(PathBuffer, DestinationRootPath.Buffer);
+             wcscat(PathBuffer, KeyValue);
+
+             DPRINT("FullPath: '%S'\n", PathBuffer);
        }
+      else if (KeyValue[0] != L'\\')
+       {
+         DPRINT("RelativePath: '%S'\n", KeyValue);
+         wcscpy(PathBuffer, DestinationPath.Buffer);
+         wcscat(PathBuffer, L"\\");
+         wcscat(PathBuffer, KeyValue);
+
+         DPRINT("FullPath: '%S'\n", PathBuffer);
 
-      RtlFreeUnicodeString(&PathName);
+         Status = CreateDirectory(PathBuffer);
+         if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
+           {
+             DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
+             PopupError("Setup could not create install directories.",
+                        "ENTER = Reboot computer");
+
+             while (TRUE)
+               {
+                 ConInKey(Ir);
+
+                 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+                   {
+                     return(QUIT_PAGE);
+                   }
+               }
+           }
+       }
     }
+  while (InfFindNextLine (&DirContext, &DirContext));
 
+  return(FILE_COPY_PAGE);
+}
 
-  SetTextXY(8, 14, "Create directories");
-  SetHighlightedTextXY(50, 14, "Done");
 
+static ULONG
+FileCopyCallback(PVOID Context,
+                ULONG Notification,
+                PVOID Param1,
+                PVOID Param2)
+{
+  PCOPYCONTEXT CopyContext;
 
-  SetStatusText("   ENTER = Continue   F3 = Quit");
+  CopyContext = (PCOPYCONTEXT)Context;
 
-  while(TRUE)
+  switch (Notification)
     {
-      ConInKey(Ir);
-
-      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
-       {
-         if (ConfirmQuit(Ir) == TRUE)
-           return(QUIT_PAGE);
-         break;
-       }
-      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
-       {
-         return(FILE_COPY_PAGE);
-       }
+      case SPFILENOTIFY_STARTSUBQUEUE:
+       CopyContext->TotalOperations = (ULONG)Param2;
+       ProgressSetStepCount(CopyContext->ProgressBar,
+                            CopyContext->TotalOperations);
+       break;
+
+      case SPFILENOTIFY_STARTCOPY:
+       /* Display copy message */
+       PrintTextXYN(6, 16, 60, "Copying file: %S", (PWSTR)Param1);
+
+       PrintTextXYN(6, 18, 60, "File %lu of %lu",
+                    CopyContext->CompletedOperations + 1,
+                    CopyContext->TotalOperations);
+       break;
+
+      case SPFILENOTIFY_ENDCOPY:
+       CopyContext->CompletedOperations++;
+       ProgressNextStep(CopyContext->ProgressBar);
+       break;
     }
 
-  return(PREPARE_COPY_PAGE);
+  return(0);
 }
 
 
-static ULONG
+static PAGE_NUMBER
 FileCopyPage(PINPUT_RECORD Ir)
 {
+  COPYCONTEXT CopyContext;
+  SHORT xScreen;
+  SHORT yScreen;
+
+  SetStatusText("   Please wait...");
 
   SetTextXY(6, 8, "Copying files");
 
+  GetScreenSize(&xScreen, &yScreen);
 
-  SetStatusText("   ENTER = Continue   F3 = Quit");
+  CopyContext.TotalOperations = 0;
+  CopyContext.CompletedOperations = 0;
+  CopyContext.ProgressBar = CreateProgressBar(6,
+                                             yScreen - 14,
+                                             xScreen - 7,
+                                             yScreen - 10);
 
-  while(TRUE)
+  SetupCommitFileQueue(SetupFileQueue,
+                      DestinationRootPath.Buffer,
+                      InstallPath.Buffer,
+                      (PSP_FILE_CALLBACK)FileCopyCallback,
+                      &CopyContext);
+
+  SetupCloseFileQueue(SetupFileQueue);
+
+  DestroyProgressBar(CopyContext.ProgressBar);
+
+  return(REGISTRY_PAGE);
+}
+
+
+static PAGE_NUMBER
+RegistryPage(PINPUT_RECORD Ir)
+{
+  INFCONTEXT InfContext;
+  NTSTATUS Status;
+
+  PWSTR Action;
+  PWSTR File;
+  PWSTR Section;
+  BOOLEAN Delete;
+
+
+  SetTextXY(6, 8, "Setup is updating the system configuration");
+
+  SetStatusText("   Creating registry hives...");
+
+  if (!SetInstallPathValue(&DestinationPath))
     {
-      ConInKey(Ir);
+      DPRINT("SetInstallPathValue() failed\n");
+      PopupError("Setup failed to set the initialize the registry.",
+                "ENTER = Reboot computer");
 
-      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
+      while(TRUE)
        {
-         if (ConfirmQuit(Ir) == TRUE)
-           return(QUIT_PAGE);
-         break;
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
        }
-      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
+    }
+
+  /* Create the default hives */
+  Status = NtInitializeRegistry(TRUE);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("NtInitializeRegistry() failed (Status %lx)\n", Status);
+      PopupError("Setup failed to create the registry hives.",
+                "ENTER = Reboot computer");
+
+      while(TRUE)
        {
-         return(INIT_SYSTEM_PAGE);
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
        }
     }
 
-  return(FILE_COPY_PAGE);
-}
+  /* Update registry */
+  SetStatusText("   Updating registry hives...");
 
+  if (!InfFindFirstLine(SetupInf, L"HiveInfs.Install", NULL, &InfContext))
+    {
+      DPRINT1("InfFindFirstLine() failed\n");
+      PopupError("Setup failed to find the registry data files.",
+                "ENTER = Reboot computer");
 
-#if 0
-static NTSTATUS
-UpdateSystemRootLink(VOID)
-{
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING LinkName;
-  UNICODE_STRING TargetName;
-  CHAR TargetBuffer[MAX_PATH];
-  HANDLE Handle;
-  NTSTATUS Status;
+      while(TRUE)
+       {
+         ConInKey(Ir);
 
-  RtlInitUnicodeString(&LinkName,
-                      L"\\SystemRoot");
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
 
-  InitializeObjectAttributes(&ObjectAttributes,
-                            &LinkName,
-                            OBJ_OPENLINK,
-                            NULL,
-                            NULL);
+  do
+    {
+      InfGetDataField (&InfContext, 0, &Action);
+      InfGetDataField (&InfContext, 1, &File);
+      InfGetDataField (&InfContext, 2, &Section);
 
-  Status = NtOpenSymbolicLinkObject(&Handle,
-                                   SYMBOLIC_LINK_ALL_ACCESS,
-                                   &ObjectAttributes);
-  if (!NT_SUCCESS(Status))
-    return(Status);
+      DPRINT1("Action: %S  File: %S  Section %S\n", Action, File, Section);
 
-  Status = NtMakeTemporaryObject(Handle);
-  NtClose(Handle);
-  if (!NT_SUCCESS(Status))
-    return(Status);
+      if (!_wcsicmp (Action, L"AddReg"))
+       {
+         Delete = FALSE;
+       }
+      else if (!_wcsicmp (Action, L"DelReg"))
+       {
+         Delete = TRUE;
+       }
+      else
+       {
+         continue;
+       }
 
-  sprintf(TargetBuffer,
-         "\\Device\\Harddisk%lu\\Partition%lu",
-         PartData.DiskNumber,
-         PartData.PartNumber);
-  if (InstallDir[0] != '\\')
-    strcat(TargetBuffer, "\\");
-  strcat(TargetBuffer, InstallDir);
+      SetStatusText("   Importing %S...", File);
 
-  RtlCreateUnicodeStringFromAsciiz(&TargetName,
-                                  TargetBuffer);
+      if (!ImportRegistryFile(File, Section, Delete))
+       {
+         DPRINT1("Importing %S failed\n", File);
 
-  Status = NtCreateSymbolicLinkObject(&Handle,
-                                     SYMBOLIC_LINK_ALL_ACCESS,
-                                     &ObjectAttributes,
-                                     &TargetName);
+         PopupError("Setup failed to import a hive file.",
+                    "ENTER = Reboot computer");
 
-  RtlFreeUnicodeString(&TargetName);
+         while(TRUE)
+           {
+             ConInKey(Ir);
 
-  if (!NT_SUCCESS(Status))
-    return(Status);
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+               {
+                 return(QUIT_PAGE);
+               }
+           }
+       }
+    }
+  while (InfFindNextLine (&InfContext, &InfContext));
 
-  NtClose(Handle);
+  SetStatusText("   Done...");
 
-  return(STATUS_SUCCESS);
+  return(BOOT_LOADER_PAGE);
 }
-#endif
 
 
-static ULONG
-InitSystemPage(PINPUT_RECORD Ir)
+static PAGE_NUMBER
+BootLoaderPage(PINPUT_RECORD Ir)
 {
-#if 0
+  WCHAR SrcPath[MAX_PATH];
+  WCHAR DstPath[MAX_PATH];
+  PINICACHE IniCache;
+  PINICACHESECTION IniSection;
   NTSTATUS Status;
-#endif
+  BOOLEAN InstallMBR = FALSE;
 
-  SetTextXY(6, 8, "Initializing system settings");
+  SetTextXY(6, 8, "Installing the boot loader");
 
+  SetStatusText("   Please wait...");
 
-  SetTextXY(6, 12, "Create registry hives");
+  if (ActivePartitionValid == FALSE)
+    {
+      /* Mark the chosen partition as active since there is no active
+         partition now */
+     
+               if (!MarkPartitionActive(PartData.DiskNumber,
+                       PartData.PartNumber, &ActivePartition))
+               {
+                     PopupError("Setup could not mark the system partiton active\n",
+                                "ENTER = Reboot computer");
+               
+                     while(TRUE)
+                       {
+                         ConInKey(Ir);
+               
+                         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+                           {
+                             return(QUIT_PAGE);
+                           }
+                       }
+               }
+        InstallMBR = TRUE;
+    }
 
-  SetTextXY(6, 14, "Update registry hives");
+  if (InstallMBR)
+    {
+          WCHAR PathBuffer[MAX_PATH];
+             UNICODE_STRING SystemRootMBRPath;
+       
+                 RtlFreeUnicodeString(&SystemRootMBRPath);
+                 swprintf(PathBuffer,
+                          L"\\Device\\Harddisk%lu\\Partition0",
+                          PartData.DiskNumber);
+                 RtlCreateUnicodeString(&SystemRootMBRPath,
+                                        PathBuffer);
+
+                 /* Install MBR bootcode */
+                 wcscpy(SrcPath, SourceRootPath.Buffer);
+                 wcscat(SrcPath, L"\\loader\\dosmbr.bin");
+       
+                 DPRINT1("Install MBR bootcode: %S ==> %S\n", SrcPath, SystemRootMBRPath.Buffer);
+                 Status = InstallMBRBootCodeToDisk(SrcPath,
+                                                     SystemRootMBRPath.Buffer);
+                 if (!NT_SUCCESS(Status))
+                 {
+                   DPRINT1("InstallMBRBootCodeToDisk() failed (Status %lx)\n", Status);
+                   PopupError("Setup failed to install the MBR bootcode.",
+                              "ENTER = Reboot computer");
+       
+                   while(TRUE)
+                   {
+                     ConInKey(Ir);
+       
+                     if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+                     {
+                       return(QUIT_PAGE);
+                     }
+                   }
+                 }
+    }
 
-  SetTextXY(6, 16, "Install/update boot manager");
+  if (ActivePartition.PartType == PARTITION_ENTRY_UNUSED)
+    {
+      DPRINT1("Error: active partition invalid (unused)\n");
+      PopupError("The active partition is unused (invalid).\n",
+                "ENTER = Reboot computer");
 
-  SetStatusText("   Please wait...");
+      while(TRUE)
+       {
+         ConInKey(Ir);
 
-#if 0
-  /*
-   * Initialize registry
-   */
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
 
-  /* Update 'SystemRoot' link */
-  Status = UpdateSystemRootLink();
-  if (!NT_SUCCESS(Status))
+  if (ActivePartition.PartType == 0x0A)
     {
+      /* OS/2 boot manager partition */
+      DPRINT1("Found OS/2 boot manager partition\n");
+      PopupError("Setup found an OS/2 boot manager partiton.\n"
+                "The OS/2 boot manager is not supported yet!",
+                "ENTER = Reboot computer");
+
+      while(TRUE)
+       {
+         ConInKey(Ir);
 
-      PrintTextXY(6, 25, "UpdateSystemRootLink() failed (Status = 0x%08lx)", Status);
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
     }
+  else if (ActivePartition.PartType == 0x83)
+    {
+      /* Linux ext2 partition */
+      DPRINT1("Found Linux ext2 partition\n");
+      PopupError("Setup found a Linux ext2 partiton.\n"
+                "Linux ext2 partitions are not supported yet!",
+                "ENTER = Reboot computer");
 
+      while(TRUE)
+       {
+         ConInKey(Ir);
 
-  Status = NtInitializeRegistry(TRUE);
-  if (!NT_SUCCESS(Status))
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
+    }
+  else if (ActivePartition.PartType == PARTITION_IFS)
     {
+      /* NTFS partition */
+      DPRINT1("Found NTFS partition\n");
+      PopupError("Setup found an NTFS partiton.\n"
+                "NTFS partitions are not supported yet!",
+                "ENTER = Reboot computer");
+
+      while(TRUE)
+       {
+         ConInKey(Ir);
 
-      PrintTextXY(6, 26, "NtInitializeRegistry() failed (Status = 0x%08lx)", Status);
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+       }
     }
-#endif
+  else if ((ActivePartition.PartType == PARTITION_FAT_12) ||
+          (ActivePartition.PartType == PARTITION_FAT_16) ||
+          (ActivePartition.PartType == PARTITION_HUGE) ||
+          (ActivePartition.PartType == PARTITION_XINT13) ||
+          (ActivePartition.PartType == PARTITION_FAT32) ||
+          (ActivePartition.PartType == PARTITION_FAT32_XINT13))
+  {
+    /* FAT or FAT32 partition */
+    DPRINT1("System path: '%wZ'\n", &SystemRootPath);
+
+    if (DoesFileExist(SystemRootPath.Buffer, L"ntldr") == TRUE ||
+       DoesFileExist(SystemRootPath.Buffer, L"boot.ini") == TRUE)
+    {
+      /* Search root directory for 'ntldr' and 'boot.ini'. */
+      DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n");
 
-  /*
-   * Update registry
-   */
+      /* Copy FreeLoader to the boot partition */
+      wcscpy(SrcPath, SourceRootPath.Buffer);
+      wcscat(SrcPath, L"\\loader\\freeldr.sys");
+      wcscpy(DstPath, SystemRootPath.Buffer);
+      wcscat(DstPath, L"\\freeldr.sys");
 
-  /* FIXME: Create key '\Registry\Machine\System\Setup' */
+      DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath);
+      Status = SetupCopyFile(SrcPath, DstPath);
+      if (!NT_SUCCESS(Status))
+      {
+       DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
+       PopupError("Setup failed to copy 'freeldr.sys'.",
+                  "ENTER = Reboot computer");
 
-  /* FIXME: Create value 'SystemSetupInProgress' */
+       while(TRUE)
+       {
+         ConInKey(Ir);
 
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+         {
+           return(QUIT_PAGE);
+         }
+       }
+      }
+
+      /* Create or update freeldr.ini */
+      if (DoesFileExist(SystemRootPath.Buffer, L"freeldr.ini") == FALSE)
+      {
+       /* Create new 'freeldr.ini' */
+       DPRINT1("Create new 'freeldr.ini'\n");
+       wcscpy(DstPath, SystemRootPath.Buffer);
+       wcscat(DstPath, L"\\freeldr.ini");
+
+       Status = CreateFreeLoaderIniForReactos(DstPath,
+                                              DestinationArcPath.Buffer);
+       if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("CreateFreeLoaderIniForReactos() failed (Status %lx)\n", Status);
+         PopupError("Setup failed to create 'freeldr.ini'.",
+                    "ENTER = Reboot computer");
 
+         while(TRUE)
+         {
+           ConInKey(Ir);
 
-  SetStatusText("   ENTER = Continue   F3 = Quit");
+           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+         }
+       }
 
-  while(TRUE)
+       /* Install new bootcode */
+       if ((ActivePartition.PartType == PARTITION_FAT32) ||
+           (ActivePartition.PartType == PARTITION_FAT32_XINT13))
+       {
+         /* Install FAT32 bootcode */
+         wcscpy(SrcPath, SourceRootPath.Buffer);
+         wcscat(SrcPath, L"\\loader\\fat32.bin");
+         wcscpy(DstPath, SystemRootPath.Buffer);
+         wcscat(DstPath, L"\\bootsect.ros");
+
+         DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath);
+         Status = InstallFat32BootCodeToFile(SrcPath,
+                                             DstPath,
+                                             SystemRootPath.Buffer);
+         if (!NT_SUCCESS(Status))
+         {
+           DPRINT1("InstallFat32BootCodeToFile() failed (Status %lx)\n", Status);
+           PopupError("Setup failed to install the FAT32 bootcode.",
+                      "ENTER = Reboot computer");
+
+           while(TRUE)
+           {
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+             {
+               return(QUIT_PAGE);
+             }
+           }
+         }
+       }
+       else
+       {
+         /* Install FAT16 bootcode */
+         wcscpy(SrcPath, SourceRootPath.Buffer);
+         wcscat(SrcPath, L"\\loader\\fat.bin");
+         wcscpy(DstPath, SystemRootPath.Buffer);
+         wcscat(DstPath, L"\\bootsect.ros");
+
+         DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
+         Status = InstallFat16BootCodeToFile(SrcPath,
+                                             DstPath,
+                                             SystemRootPath.Buffer);
+         if (!NT_SUCCESS(Status))
+         {
+           DPRINT1("InstallFat16BootCodeToFile() failed (Status %lx)\n", Status);
+           PopupError("Setup failed to install the FAT bootcode.",
+                      "ENTER = Reboot computer");
+
+           while(TRUE)
+           {
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+             {
+               return(QUIT_PAGE);
+             }
+           }
+         }
+       }
+
+       /* Update 'boot.ini' */
+       wcscpy(DstPath, SystemRootPath.Buffer);
+       wcscat(DstPath, L"\\boot.ini");
+
+       DPRINT1("Update 'boot.ini': %S\n", DstPath);
+       Status = UpdateBootIni(DstPath,
+                              L"C:\\bootsect.ros",
+                              L"\"ReactOS\"");
+       if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status);
+         PopupError("Setup failed to update \'boot.ini\'.",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+         {
+           ConInKey(Ir);
+
+           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+         }
+       }
+      }
+      else
+      {
+       /* Update existing 'freeldr.ini' */
+       DPRINT1("Update existing 'freeldr.ini'\n");
+       wcscpy(DstPath, SystemRootPath.Buffer);
+       wcscat(DstPath, L"\\freeldr.ini");
+
+       Status = UpdateFreeLoaderIni(DstPath,
+                                    DestinationArcPath.Buffer);
+       if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
+         PopupError("Setup failed to update 'freeldr.ini'.",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+         {
+           ConInKey(Ir);
+
+           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+         }
+       }
+      }
+    }
+    else if (DoesFileExist(SystemRootPath.Buffer, L"io.sys") == TRUE ||
+            DoesFileExist(SystemRootPath.Buffer, L"msdos.sys") == TRUE)
     {
-      ConInKey(Ir);
+      /* Search for root directory for 'io.sys' and 'msdos.sys'. */
+      DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n");
 
-      if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
-         (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))
+      /* Copy FreeLoader to the boot partition */
+      wcscpy(SrcPath, SourceRootPath.Buffer);
+      wcscat(SrcPath, L"\\loader\\freeldr.sys");
+      wcscpy(DstPath, SystemRootPath.Buffer);
+      wcscat(DstPath, L"\\freeldr.sys");
+
+      DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
+      Status = SetupCopyFile(SrcPath, DstPath);
+      if (!NT_SUCCESS(Status))
+      {
+       DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
+       PopupError("Setup failed to copy 'freeldr.sys'.",
+                  "ENTER = Reboot computer");
+
+       while(TRUE)
        {
-         if (ConfirmQuit(Ir) == TRUE)
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+         {
            return(QUIT_PAGE);
-         break;
+         }
+       }
+      }
+
+      /* Create or update 'freeldr.ini' */
+      if (DoesFileExist(SystemRootPath.Buffer, L"freeldr.ini") == FALSE)
+      {
+       /* Create new 'freeldr.ini' */
+       DPRINT1("Create new 'freeldr.ini'\n");
+       wcscpy(DstPath, SystemRootPath.Buffer);
+       wcscat(DstPath, L"\\freeldr.ini");
+
+       Status = CreateFreeLoaderIniForDos(DstPath,
+                                          DestinationArcPath.Buffer);
+       if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("CreateFreeLoaderIniForDos() failed (Status %lx)\n", Status);
+         PopupError("Setup failed to create 'freeldr.ini'.",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+         {
+           ConInKey(Ir);
+
+           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+         }
+       }
+
+       /* Save current bootsector as 'BOOTSECT.DOS' */
+       wcscpy(SrcPath, SystemRootPath.Buffer);
+       wcscpy(DstPath, SystemRootPath.Buffer);
+       wcscat(DstPath, L"\\bootsect.dos");
+
+       DPRINT1("Save bootsector: %S ==> %S\n", SrcPath, DstPath);
+       Status = SaveCurrentBootSector(SrcPath,
+                                      DstPath);
+       if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status);
+         PopupError("Setup failed to save the current bootsector.",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+         {
+           ConInKey(Ir);
+
+           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+         }
+       }
+
+       /* Install new bootsector */
+       if ((ActivePartition.PartType == PARTITION_FAT32) ||
+           (ActivePartition.PartType == PARTITION_FAT32_XINT13))
+       {
+         wcscpy(SrcPath, SourceRootPath.Buffer);
+         wcscat(SrcPath, L"\\loader\\fat32.bin");
+
+         DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
+         Status = InstallFat32BootCodeToDisk(SrcPath,
+                                             SystemRootPath.Buffer);
+         if (!NT_SUCCESS(Status))
+         {
+           DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
+           PopupError("Setup failed to install the FAT32 bootcode.",
+                      "ENTER = Reboot computer");
+
+           while(TRUE)
+           {
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+             {
+               return(QUIT_PAGE);
+             }
+           }
+         }
+       }
+       else
+       {
+         wcscpy(SrcPath, SourceRootPath.Buffer);
+         wcscat(SrcPath, L"\\loader\\fat.bin");
+
+         DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
+         Status = InstallFat16BootCodeToDisk(SrcPath,
+                                             SystemRootPath.Buffer);
+         if (!NT_SUCCESS(Status))
+         {
+           DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
+           PopupError("Setup failed to install the FAT bootcode.",
+                      "ENTER = Reboot computer");
+
+           while(TRUE)
+           {
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+             {
+               return(QUIT_PAGE);
+             }
+           }
+         }
+       }
+      }
+      else
+      {
+       /* Update existing 'freeldr.ini' */
+       wcscpy(DstPath, SystemRootPath.Buffer);
+       wcscat(DstPath, L"\\freeldr.ini");
+
+       Status = UpdateFreeLoaderIni(DstPath,
+                                    DestinationArcPath.Buffer);
+       if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
+         PopupError("Setup failed to update 'freeldr.ini'.",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+         {
+           ConInKey(Ir);
+
+           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+         }
+       }
+      }
+    }
+    else
+    {
+      /* No or unknown boot loader */
+      DPRINT1("No or unknown boot loader found\n");
+
+      /* Copy FreeLoader to the boot partition */
+      wcscpy(SrcPath, SourceRootPath.Buffer);
+      wcscat(SrcPath, L"\\loader\\freeldr.sys");
+      wcscpy(DstPath, SystemRootPath.Buffer);
+      wcscat(DstPath, L"\\freeldr.sys");
+
+      DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath);
+      Status = SetupCopyFile(SrcPath, DstPath);
+      if (!NT_SUCCESS(Status))
+      {
+       DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
+       PopupError("Setup failed to copy 'freeldr.sys'.",
+                  "ENTER = Reboot computer");
+
+       while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+         {
+           return(QUIT_PAGE);
+         }
        }
-      else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
+      }
+
+      /* Create or update 'freeldr.ini' */
+      if (DoesFileExist(SystemRootPath.Buffer, L"freeldr.ini") == FALSE)
+      {
+       /* Create new freeldr.ini */
+       wcscpy(DstPath, SystemRootPath.Buffer);
+       wcscat(DstPath, L"\\freeldr.ini");
+
+       DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath);
+       Status = CreateFreeLoaderIniForReactos(DstPath,
+                                              DestinationArcPath.Buffer);
+       if (!NT_SUCCESS(Status))
        {
-         return(SUCCESS_PAGE);
+         DPRINT1("CreateFreeLoaderIniForReactos() failed (Status %lx)\n", Status);
+         PopupError("Setup failed to create \'freeldr.ini\'.",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+         {
+           ConInKey(Ir);
+
+           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+         }
+       }
+
+       /* Save current bootsector as 'BOOTSECT.OLD' */
+       wcscpy(SrcPath, SystemRootPath.Buffer);
+       wcscpy(DstPath, SystemRootPath.Buffer);
+       wcscat(DstPath, L"\\bootsect.old");
+
+       DPRINT1("Save bootsector: %S ==> %S\n", SrcPath, DstPath);
+       Status = SaveCurrentBootSector(SrcPath,
+                                      DstPath);
+       if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status);
+         PopupError("Setup failed save the current bootsector.",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+         {
+           ConInKey(Ir);
+
+           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+         }
+       }
+
+       /* Install new bootsector */
+       if ((ActivePartition.PartType == PARTITION_FAT32) ||
+           (ActivePartition.PartType == PARTITION_FAT32_XINT13))
+       {
+         wcscpy(SrcPath, SourceRootPath.Buffer);
+         wcscat(SrcPath, L"\\loader\\fat32.bin");
+
+         DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
+         Status = InstallFat32BootCodeToDisk(SrcPath,
+                                             SystemRootPath.Buffer);
+         if (!NT_SUCCESS(Status))
+         {
+           DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
+           PopupError("Setup failed to install the FAT32 bootcode.",
+                      "ENTER = Reboot computer");
+
+           while(TRUE)
+           {
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+             {
+               return(QUIT_PAGE);
+             }
+           }
+         }
+       }
+       else
+       {
+         wcscpy(SrcPath, SourceRootPath.Buffer);
+         wcscat(SrcPath, L"\\loader\\fat.bin");
+
+         DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
+         Status = InstallFat16BootCodeToDisk(SrcPath,
+                                             SystemRootPath.Buffer);
+         if (!NT_SUCCESS(Status))
+         {
+           DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
+           PopupError("Setup failed to install the FAT bootcode.",
+                      "ENTER = Reboot computer");
+
+           while(TRUE)
+           {
+             ConInKey(Ir);
+
+             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
+             {
+               return(QUIT_PAGE);
+             }
+           }
+         }
+       }
+      }
+      else
+      {
+       /* Update existing 'freeldr.ini' */
+       wcscpy(DstPath, SystemRootPath.Buffer);
+       wcscat(DstPath, L"\\freeldr.ini");
+
+       Status = UpdateFreeLoaderIni(DstPath,
+                                    DestinationArcPath.Buffer);
+       if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
+         PopupError("Setup failed to update 'freeldr.ini'.",
+                    "ENTER = Reboot computer");
+
+         while(TRUE)
+         {
+           ConInKey(Ir);
+
+           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
+         }
+       }
+      }
+    }
+  }
+  else
+    {
+      /* Unknown partition */
+      DPRINT1("Unknown partition found\n");
+      PopupError("Setup found an unknown partiton type.\n"
+                "This partition type is not supported!",
+                "ENTER = Reboot computer");
+
+      while(TRUE)
+       {
+         ConInKey(Ir);
+
+         if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
+           {
+             return(QUIT_PAGE);
+           }
        }
     }
 
-  return(INIT_SYSTEM_PAGE);
+  return(SUCCESS_PAGE);
 }
 
 
-static ULONG
+
+static PAGE_NUMBER
 QuitPage(PINPUT_RECORD Ir)
 {
   SetTextXY(10, 6, "ReactOS is not completely installed");
 
   SetTextXY(10, 8, "Remove floppy disk from Drive A: and");
-  SetTextXY(10, 9, "all CD-ROMs from CD-Drive.");
+  SetTextXY(10, 9, "all CD-ROMs from CD-Drives.");
 
   SetTextXY(10, 11, "Press ENTER to reboot your computer.");
 
@@ -1006,7 +2684,7 @@ QuitPage(PINPUT_RECORD Ir)
     {
       ConInKey(Ir);
 
-      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
+      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
          return(REBOOT_PAGE);
        }
@@ -1014,7 +2692,7 @@ QuitPage(PINPUT_RECORD Ir)
 }
 
 
-static ULONG
+static PAGE_NUMBER
 SuccessPage(PINPUT_RECORD Ir)
 {
   SetTextXY(10, 6, "The basic components of ReactOS have been installed successfully.");
@@ -1030,7 +2708,7 @@ SuccessPage(PINPUT_RECORD Ir)
     {
       ConInKey(Ir);
 
-      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
+      if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
        {
          return(REBOOT_PAGE);
        }
@@ -1043,7 +2721,7 @@ NtProcessStartup(PPEB Peb)
 {
   NTSTATUS Status;
   INPUT_RECORD Ir;
-  ULONG Page;
+  PAGE_NUMBER Page;
 
   RtlNormalizeProcessParams(Peb->ProcessParameters);
 
@@ -1059,12 +2737,24 @@ NtProcessStartup(PPEB Peb)
                       0,0,0,0,0);
     }
 
+  PartDataValid = FALSE;
+
+  /* Initialize global unicode strings */
+  RtlInitUnicodeString(&SourcePath, NULL);
+  RtlInitUnicodeString(&SourceRootPath, NULL);
+  RtlInitUnicodeString(&InstallPath, NULL);
+  RtlInitUnicodeString(&DestinationPath, NULL);
+  RtlInitUnicodeString(&DestinationArcPath, NULL);
+  RtlInitUnicodeString(&DestinationRootPath, NULL);
+  RtlInitUnicodeString(&SystemRootPath, NULL);
+
+
   Page = START_PAGE;
   while (Page != REBOOT_PAGE)
     {
       ClearScreen();
 
-      SetUnderlinedTextXY(4, 3, " ReactOS 0.0.20 Setup ");
+      SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
 
       switch (Page)
        {
@@ -1097,10 +2787,18 @@ NtProcessStartup(PPEB Peb)
            Page = SelectPartitionPage(&Ir);
            break;
 
+         case CREATE_PARTITION_PAGE:
+           Page = CreatePartitionPage(&Ir);
+           break;
+
          case SELECT_FILE_SYSTEM_PAGE:
            Page = SelectFileSystemPage(&Ir);
            break;
 
+         case FORMAT_PARTITION_PAGE:
+           Page = FormatPartitionPage(&Ir);
+           break;
+
          case CHECK_FILE_SYSTEM_PAGE:
            Page = CheckFileSystemPage(&Ir);
            break;
@@ -1117,8 +2815,12 @@ NtProcessStartup(PPEB Peb)
            Page = FileCopyPage(&Ir);
            break;
 
-         case INIT_SYSTEM_PAGE:
-           Page = InitSystemPage(&Ir);
+         case REGISTRY_PAGE:
+           Page = RegistryPage(&Ir);
+           break;
+
+         case BOOT_LOADER_PAGE:
+           Page = BootLoaderPage(&Ir);
            break;