update for HEAD-2003091401
[reactos.git] / subsys / system / usetup / usetup.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 2002, 2003 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /*
20  * COPYRIGHT:       See COPYING in the top level directory
21  * PROJECT:         ReactOS text-mode setup
22  * FILE:            subsys/system/usetup/usetup.c
23  * PURPOSE:         Text-mode setup
24  * PROGRAMMER:      Eric Kohl
25  *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
26  */
27
28 #include <ddk/ntddk.h>
29 #include <ntdll/rtl.h>
30
31 #include <ntos/minmax.h>
32 #include <reactos/resource.h>
33
34 #include "usetup.h"
35 #include "console.h"
36 #include "partlist.h"
37 #include "inicache.h"
38 #include "infcache.h"
39 #include "filequeue.h"
40 #include "progress.h"
41 #include "bootsup.h"
42 #include "registry.h"
43 #include "format.h"
44 #include "fslist.h"
45 #include "cabinet.h"
46
47 #define NDEBUG
48 #include <debug.h>
49
50
51 typedef enum _PAGE_NUMBER
52 {
53   START_PAGE,
54   INTRO_PAGE,
55   INSTALL_INTRO_PAGE,
56
57   SELECT_PARTITION_PAGE,
58   CREATE_PARTITION_PAGE,
59   DELETE_PARTITION_PAGE,
60
61   SELECT_FILE_SYSTEM_PAGE,
62   FORMAT_PARTITION_PAGE,
63   CHECK_FILE_SYSTEM_PAGE,
64
65   PREPARE_COPY_PAGE,
66   INSTALL_DIRECTORY_PAGE,
67   FILE_COPY_PAGE,
68   REGISTRY_PAGE,
69   BOOT_LOADER_PAGE,
70
71   REPAIR_INTRO_PAGE,
72
73   EMERGENCY_INTRO_PAGE,
74
75   SUCCESS_PAGE,
76   QUIT_PAGE,
77   REBOOT_PAGE,                  /* virtual page */
78 } PAGE_NUMBER, *PPAGE_NUMBER;
79
80 typedef struct _COPYCONTEXT
81 {
82   ULONG TotalOperations;
83   ULONG CompletedOperations;
84   PPROGRESS ProgressBar;
85 } COPYCONTEXT, *PCOPYCONTEXT;
86
87
88 /* GLOBALS ******************************************************************/
89
90 HANDLE ProcessHeap;
91 UNICODE_STRING SourceRootPath;
92
93
94 /* LOCALS *******************************************************************/
95
96 static PPARTLIST PartitionList = NULL;
97
98 static PFILE_SYSTEM_LIST FileSystemList = NULL;
99
100
101 static UNICODE_STRING SourcePath;
102
103 static UNICODE_STRING InstallPath;
104
105 /* Path to the install directory */
106 static UNICODE_STRING DestinationPath;
107 static UNICODE_STRING DestinationArcPath;
108 static UNICODE_STRING DestinationRootPath;
109
110 /* Path to the active partition (boot manager) */
111 static UNICODE_STRING SystemRootPath;
112
113 static HINF SetupInf;
114
115 static HSPFILEQ SetupFileQueue = NULL;
116
117 static BOOLEAN WarnLinuxPartitions = TRUE;
118
119
120 /* FUNCTIONS ****************************************************************/
121
122 static VOID
123 PrintString(char* fmt,...)
124 {
125   char buffer[512];
126   va_list ap;
127   UNICODE_STRING UnicodeString;
128   ANSI_STRING AnsiString;
129
130   va_start(ap, fmt);
131   vsprintf(buffer, fmt, ap);
132   va_end(ap);
133
134   RtlInitAnsiString(&AnsiString, buffer);
135   RtlAnsiStringToUnicodeString(&UnicodeString,
136                                &AnsiString,
137                                TRUE);
138   NtDisplayString(&UnicodeString);
139   RtlFreeUnicodeString(&UnicodeString);
140 }
141
142
143 static VOID
144 PopupError(PCHAR Text,
145            PCHAR Status)
146 {
147   SHORT xScreen;
148   SHORT yScreen;
149   SHORT yTop;
150   SHORT xLeft;
151   COORD coPos;
152   ULONG Written;
153   ULONG Length;
154   ULONG MaxLength;
155   ULONG Lines;
156   PCHAR p;
157   PCHAR pnext;
158   BOOLEAN LastLine;
159   SHORT Width;
160   SHORT Height;
161
162   /* Count text lines and longest line */
163   MaxLength = 0;
164   Lines = 0;
165   pnext = Text;
166   while (TRUE)
167     {
168       p = strchr(pnext, '\n');
169       if (p == NULL)
170         {
171           Length = strlen(pnext);
172           LastLine = TRUE;
173         }
174       else
175         {
176           Length = (ULONG)(p - pnext);
177           LastLine = FALSE;
178         }
179
180       Lines++;
181       if (Length > MaxLength)
182         MaxLength = Length;
183
184       if (LastLine == TRUE)
185         break;
186
187       pnext = p + 1;
188     }
189
190   /* Check length of status line */
191   if (Status != NULL)
192     {
193       Length = strlen(Status);
194       if (Length > MaxLength)
195         MaxLength = Length;
196     }
197
198   GetScreenSize(&xScreen, &yScreen);
199
200   Width = MaxLength + 4;
201   Height = Lines + 2;
202   if (Status != NULL)
203     Height += 2;
204
205   yTop = (yScreen - Height) / 2;
206   xLeft = (xScreen - Width) / 2;
207
208
209   /* Set screen attributes */
210   coPos.X = xLeft;
211   for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
212     {
213       FillConsoleOutputAttribute(0x74,
214                                  Width,
215                                  coPos,
216                                  &Written);
217     }
218
219   /* draw upper left corner */
220   coPos.X = xLeft;
221   coPos.Y = yTop;
222   FillConsoleOutputCharacter(0xDA, // '+',
223                              1,
224                              coPos,
225                              &Written);
226
227   /* draw upper edge */
228   coPos.X = xLeft + 1;
229   coPos.Y = yTop;
230   FillConsoleOutputCharacter(0xC4, // '-',
231                              Width - 2,
232                              coPos,
233                              &Written);
234
235   /* draw upper right corner */
236   coPos.X = xLeft + Width - 1;
237   coPos.Y = yTop;
238   FillConsoleOutputCharacter(0xBF, // '+',
239                              1,
240                              coPos,
241                              &Written);
242
243   /* Draw right edge, inner space and left edge */
244   for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
245     {
246       coPos.X = xLeft;
247       FillConsoleOutputCharacter(0xB3, // '|',
248                                  1,
249                                  coPos,
250                                  &Written);
251
252       coPos.X = xLeft + 1;
253       FillConsoleOutputCharacter(' ',
254                                  Width - 2,
255                                  coPos,
256                                  &Written);
257
258       coPos.X = xLeft + Width - 1;
259       FillConsoleOutputCharacter(0xB3, // '|',
260                                  1,
261                                  coPos,
262                                  &Written);
263     }
264
265   /* draw lower left corner */
266   coPos.X = xLeft;
267   coPos.Y = yTop + Height - 1;
268   FillConsoleOutputCharacter(0xC0, // '+',
269                              1,
270                              coPos,
271                              &Written);
272
273   /* draw lower edge */
274   coPos.X = xLeft + 1;
275   coPos.Y = yTop + Height - 1;
276   FillConsoleOutputCharacter(0xC4, // '-',
277                              Width - 2,
278                              coPos,
279                              &Written);
280
281   /* draw lower right corner */
282   coPos.X = xLeft + Width - 1;
283   coPos.Y = yTop + Height - 1;
284   FillConsoleOutputCharacter(0xD9, // '+',
285                              1,
286                              coPos,
287                              &Written);
288
289   /* Print message text */
290   coPos.Y = yTop + 1;
291   pnext = Text;
292   while (TRUE)
293     {
294       p = strchr(pnext, '\n');
295       if (p == NULL)
296         {
297           Length = strlen(pnext);
298           LastLine = TRUE;
299         }
300       else
301         {
302           Length = (ULONG)(p - pnext);
303           LastLine = FALSE;
304         }
305
306       if (Length != 0)
307         {
308           coPos.X = xLeft + 2;
309           WriteConsoleOutputCharacters(pnext,
310                                        Length,
311                                        coPos);
312         }
313
314       if (LastLine == TRUE)
315         break;
316
317       coPos.Y++;
318       pnext = p + 1;
319     }
320
321   /* Print separator line and status text */
322   if (Status != NULL)
323     {
324       coPos.Y = yTop + Height - 3;
325       coPos.X = xLeft;
326       FillConsoleOutputCharacter(0xC3, // '+',
327                                  1,
328                                  coPos,
329                                  &Written);
330
331       coPos.X = xLeft + 1;
332       FillConsoleOutputCharacter(0xC4, // '-',
333                                  Width - 2,
334                                  coPos,
335                                  &Written);
336
337       coPos.X = xLeft + Width - 1;
338       FillConsoleOutputCharacter(0xB4, // '+',
339                                  1,
340                                  coPos,
341                                  &Written);
342
343       coPos.Y++;
344       coPos.X = xLeft + 2;
345       WriteConsoleOutputCharacters(Status,
346                                    min(strlen(Status), Width - 4),
347                                    coPos);
348     }
349 }
350
351
352 /*
353  * Confirm quit setup
354  * RETURNS
355  *      TRUE: Quit setup.
356  *      FALSE: Don't quit setup.
357  */
358 static BOOL
359 ConfirmQuit(PINPUT_RECORD Ir)
360 {
361   BOOL Result = FALSE;
362
363   PopupError("ReactOS is not completely installed on your\n"
364              "computer. If you quit Setup now, you will need to\n"
365              "run Setup again to install ReactOS.\n"
366              "\n"
367              "  \x07  Press ENTER to continue Setup.\n"
368              "  \x07  Press F3 to quit Setup.",
369              "F3= Quit  ENTER = Continue");
370
371   while(TRUE)
372     {
373       ConInKey(Ir);
374
375       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
376           (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3))        /* F3 */
377         {
378           Result = TRUE;
379           break;
380         }
381       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)      /* ENTER */
382         {
383           Result = FALSE;
384           break;
385         }
386     }
387
388   return(Result);
389 }
390
391
392
393 /*
394  * Start page
395  * RETURNS
396  *      Number of the next page.
397  */
398 static PAGE_NUMBER
399 StartPage(PINPUT_RECORD Ir)
400 {
401   NTSTATUS Status;
402   WCHAR FileNameBuffer[MAX_PATH];
403   UNICODE_STRING FileName;
404   INFCONTEXT Context;
405   PWCHAR Value;
406   ULONG ErrorLine;
407
408   SetStatusText("   Please wait...");
409
410   Status = GetSourcePaths(&SourcePath,
411                           &SourceRootPath);
412   if (!NT_SUCCESS(Status))
413     {
414       PrintTextXY(6, 15, "GetSourcePath() failed (Status 0x%08lx)", Status);
415       PopupError("Setup could not find its source drive.\n",
416                  "ENTER = Reboot computer");
417       while(TRUE)
418         {
419           ConInKey(Ir);
420
421           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
422             {
423               return(QUIT_PAGE);
424             }
425         }
426     }
427 #if 0
428   else
429     {
430       PrintTextXY(6, 15, "SourcePath: '%wZ'", &SourcePath);
431       PrintTextXY(6, 16, "SourceRootPath: '%wZ'", &SourceRootPath);
432     }
433 #endif
434
435   /* Load txtsetup.sif from install media. */
436   wcscpy(FileNameBuffer, SourceRootPath.Buffer);
437   wcscat(FileNameBuffer, L"\\reactos\\txtsetup.sif");
438   RtlInitUnicodeString(&FileName,
439                        FileNameBuffer);
440
441   Status = InfOpenFile(&SetupInf,
442                        &FileName,
443                        &ErrorLine);
444   if (!NT_SUCCESS(Status))
445     {
446       PopupError("Setup failed to load the file TXTSETUP.SIF.\n",
447                  "ENTER = Reboot computer");
448
449       while(TRUE)
450         {
451           ConInKey(Ir);
452
453           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
454             {
455               return(QUIT_PAGE);
456             }
457         }
458     }
459
460   /* Open 'Version' section */
461   if (!InfFindFirstLine (SetupInf, L"Version", L"Signature", &Context))
462     {
463       PopupError("Setup found a corrupt TXTSETUP.SIF.\n",
464                  "ENTER = Reboot computer");
465
466       while(TRUE)
467         {
468           ConInKey(Ir);
469
470           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
471             {
472               return(QUIT_PAGE);
473             }
474         }
475     }
476
477
478   /* Get pointer 'Signature' key */
479   if (!InfGetData (&Context, NULL, &Value))
480     {
481       PopupError("Setup found a corrupt TXTSETUP.SIF.\n",
482                  "ENTER = Reboot computer");
483
484       while(TRUE)
485         {
486           ConInKey(Ir);
487
488           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
489             {
490               return(QUIT_PAGE);
491             }
492         }
493     }
494
495   /* Check 'Signature' string */
496   if (_wcsicmp(Value, L"$ReactOS$") != 0)
497     {
498       PopupError("Setup found an invalid signature in TXTSETUP.SIF.\n",
499                  "ENTER = Reboot computer");
500
501       while(TRUE)
502         {
503           ConInKey(Ir);
504
505           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
506             {
507               return(QUIT_PAGE);
508             }
509         }
510     }
511
512   return(INTRO_PAGE);
513 }
514
515
516 /*
517  * First setup page
518  * RETURNS
519  *      Next page number.
520  */
521 static PAGE_NUMBER
522 IntroPage(PINPUT_RECORD Ir)
523 {
524   SetHighlightedTextXY(6, 8, "Welcome to ReactOS Setup");
525
526   SetTextXY(6, 11, "This part of the setup copies the ReactOS Operating System to your");
527   SetTextXY(6, 12, "computer and prepares the second part of the setup.");
528
529   SetTextXY(8, 15, "\x07  Press ENTER to install ReactOS.");
530
531   SetTextXY(8, 17, "\x07  Press E to start the emergency console.");
532
533   SetTextXY(8, 19, "\x07  Press R to repair ReactOS.");
534
535   SetTextXY(8, 21, "\x07  Press F3 to quit without installing ReactOS.");
536
537
538   SetStatusText("   ENTER = Continue   F3 = Quit");
539
540   while(TRUE)
541     {
542       ConInKey(Ir);
543
544       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
545           (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
546         {
547           if (ConfirmQuit(Ir) == TRUE)
548             return(QUIT_PAGE);
549           break;
550         }
551       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
552         {
553           return(INSTALL_INTRO_PAGE);
554         }
555       else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'E') /* E */
556         {
557           return(EMERGENCY_INTRO_PAGE);
558         }
559       else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
560         {
561           return(REPAIR_INTRO_PAGE);
562         }
563     }
564
565   return(INTRO_PAGE);
566 }
567
568
569 static PAGE_NUMBER
570 EmergencyIntroPage(PINPUT_RECORD Ir)
571 {
572   SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet");
573   SetTextXY(6, 9, "support all the functions of a fully usable setup application.");
574
575   SetTextXY(6, 12, "The emergency console is not implemented yet.");
576
577   SetTextXY(8, 15, "\x07  Press ESC to return to the main page.");
578
579   SetTextXY(8, 17, "\x07  Press ENTER to reboot your computer.");
580
581   SetStatusText("   ESC = Main page  ENTER = Reboot");
582
583   while(TRUE)
584     {
585       ConInKey(Ir);
586
587       if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
588         {
589           return(REBOOT_PAGE);
590         }
591       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
592                (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
593         {
594           return(INTRO_PAGE);
595         }
596     }
597
598   return(REPAIR_INTRO_PAGE);
599 }
600
601
602 static PAGE_NUMBER
603 RepairIntroPage(PINPUT_RECORD Ir)
604 {
605   SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet");
606   SetTextXY(6, 9, "support all the functions of a fully usable setup application.");
607
608   SetTextXY(6, 12, "The repair functions are not implemented yet.");
609
610   SetTextXY(8, 15, "\x07  Press ESC to return to the main page.");
611
612   SetTextXY(8, 17, "\x07  Press ENTER to reboot your computer.");
613
614   SetStatusText("   ESC = Main page  ENTER = Reboot");
615
616   while(TRUE)
617     {
618       ConInKey(Ir);
619
620       if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
621         {
622           return(REBOOT_PAGE);
623         }
624       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
625                (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
626         {
627           return(INTRO_PAGE);
628         }
629     }
630
631   return(REPAIR_INTRO_PAGE);
632 }
633
634
635 static PAGE_NUMBER
636 InstallIntroPage(PINPUT_RECORD Ir)
637 {
638   SetTextXY(6, 8, "ReactOS Setup is in an early development phase. It does not yet");
639   SetTextXY(6, 9, "support all the functions of a fully usable setup application.");
640
641   SetTextXY(6, 12, "The following functions are missing:");
642   SetTextXY(8, 13, "- Creating and deleting harddisk partitions.");
643   SetTextXY(8, 14, "- Formatting partitions.");
644   SetTextXY(8, 15, "- Support for non-FAT file systems.");
645   SetTextXY(8, 16, "- Checking file systems.");
646
647
648
649   SetTextXY(8, 21, "\x07  Press ENTER to install ReactOS.");
650
651   SetTextXY(8, 23, "\x07  Press F3 to quit without installing ReactOS.");
652
653
654   SetStatusText("   ENTER = Continue   F3 = Quit");
655
656   while(TRUE)
657     {
658       ConInKey(Ir);
659
660       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
661           (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
662         {
663           if (ConfirmQuit(Ir) == TRUE)
664             return(QUIT_PAGE);
665           break;
666         }
667       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
668         {
669           return(SELECT_PARTITION_PAGE);
670         }
671     }
672
673   return(INSTALL_INTRO_PAGE);
674 }
675
676
677 static PAGE_NUMBER
678 SelectPartitionPage(PINPUT_RECORD Ir)
679 {
680   SHORT xScreen;
681   SHORT yScreen;
682
683   SetTextXY(6, 8, "The list below shows existing partitions and unused disk");
684   SetTextXY(6, 9, "space for new partitions.");
685
686   SetTextXY(8, 11, "\x07  Press UP or DOWN to select a list entry.");
687   SetTextXY(8, 13, "\x07  Press ENTER to install ReactOS onto the selected partition.");
688   SetTextXY(8, 15, "\x07  Press C to create a new partition.");
689   SetTextXY(8, 17, "\x07  Press D to delete an existing partition.");
690
691   SetStatusText("   Please wait...");
692
693   GetScreenSize(&xScreen, &yScreen);
694
695   if (PartitionList == NULL)
696     {
697       PartitionList = CreatePartitionList (2,
698                                            19,
699                                            xScreen - 3,
700                                            yScreen - 3);
701       if (PartitionList == NULL)
702         {
703           /* FIXME: show an error dialog */
704           return(QUIT_PAGE);
705         }
706     }
707
708   CheckActiveBootPartition (PartitionList);
709
710   DrawPartitionList (PartitionList);
711
712   /* Warn about partitions created by Linux Fdisk */
713   if (WarnLinuxPartitions == TRUE &&
714       CheckForLinuxFdiskPartitions (PartitionList) == TRUE)
715     {
716       PopupError ("Setup found that at least one harddisk contains an incompatible\n"
717                   "partition table that can not be handled properly!\n"
718                   "\n"
719                   "Creating or deleting partitions can destroy the partiton table.\n"
720                   "\n"
721                   "  \x07  Press F3 to quit Setup."
722                   "  \x07  Press ENTER to continue.",
723                   "F3= Quit  ENTER = Continue");
724       while (TRUE)
725         {
726           ConInKey (Ir);
727
728           if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
729               (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
730             {
731               return QUIT_PAGE;
732             }
733           else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
734             {
735               WarnLinuxPartitions = FALSE;
736               return SELECT_PARTITION_PAGE;
737             }
738         }
739     }
740
741   while(TRUE)
742     {
743       /* Update status text */
744       if (PartitionList->CurrentPartition == NULL ||
745           PartitionList->CurrentPartition->Unpartitioned == TRUE)
746         {
747           SetStatusText ("   ENTER = Install   C = Create Partition   F3 = Quit");
748         }
749       else
750         {
751           SetStatusText ("   ENTER = Install   D = Delete Partition   F3 = Quit");
752         }
753
754       ConInKey(Ir);
755
756       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
757           (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
758         {
759           if (ConfirmQuit(Ir) == TRUE)
760             {
761               DestroyPartitionList (PartitionList);
762               PartitionList = NULL;
763               return QUIT_PAGE;
764             }
765           break;
766         }
767       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
768                (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
769         {
770           ScrollDownPartitionList (PartitionList);
771         }
772       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
773                (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
774         {
775           ScrollUpPartitionList (PartitionList);
776         }
777       else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
778         {
779           if (PartitionList->CurrentPartition == NULL ||
780               PartitionList->CurrentPartition->Unpartitioned == TRUE)
781             {
782               CreateNewPartition (PartitionList,
783                                   0ULL,
784                                   TRUE);
785             }
786
787           return SELECT_FILE_SYSTEM_PAGE;
788         }
789       else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_C) /* C */
790         {
791           if (PartitionList->CurrentPartition->Unpartitioned == FALSE)
792             {
793               PopupError ("You can not create a new Partition inside\n"
794                           "of an already existing Partition!\n"
795                           "\n"
796                           "  * Press any key to continue.",
797                           NULL);
798               ConInKey (Ir);
799
800               return SELECT_PARTITION_PAGE;
801             }
802
803           return CREATE_PARTITION_PAGE;
804         }
805       else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_D) /* D */
806         {
807           if (PartitionList->CurrentPartition->Unpartitioned == TRUE)
808             {
809               PopupError ("You can not delete unpartitioned disk space!\n"
810                           "\n"
811                           "  * Press any key to continue.",
812                           NULL);
813               ConInKey (Ir);
814
815               return SELECT_PARTITION_PAGE;
816             }
817
818           return DELETE_PARTITION_PAGE;
819         }
820     }
821
822   return SELECT_PARTITION_PAGE;
823 }
824
825
826 static VOID
827 DrawInputField(ULONG FieldLength,
828   SHORT Left,
829   SHORT Top,
830   PCHAR FieldContent)
831 {
832   CHAR buf[100];
833   COORD coPos;
834
835   coPos.X = Left;
836   coPos.Y = Top;
837   memset(buf, '_', sizeof(buf));
838   buf[FieldLength - strlen(FieldContent)] = 0;
839   strcat(buf, FieldContent);
840
841   WriteConsoleOutputCharacters (buf,
842                                 strlen (buf),
843                                 coPos);
844 }
845
846
847 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 6
848
849 static VOID
850 ShowPartitionSizeInputBox(SHORT Left,
851                           SHORT Top,
852                           SHORT Right,
853                           SHORT Bottom,
854                           ULONG MaxSize,
855                           PCHAR InputBuffer,
856                           PBOOLEAN Quit,
857                           PBOOLEAN Cancel)
858 {
859   INPUT_RECORD Ir;
860   COORD coPos;
861   ULONG Written;
862   SHORT i;
863   CHAR Buffer[100];
864   ULONG Index;
865   CHAR ch;
866   SHORT iLeft;
867   SHORT iTop;
868
869   if (Quit != NULL)
870     *Quit = FALSE;
871
872   if (Cancel != NULL)
873     *Cancel = FALSE;
874
875   /* draw upper left corner */
876   coPos.X = Left;
877   coPos.Y = Top;
878   FillConsoleOutputCharacter(0xDA, // '+',
879                              1,
880                              coPos,
881                              &Written);
882
883   /* draw upper edge */
884   coPos.X = Left + 1;
885   coPos.Y = Top;
886   FillConsoleOutputCharacter(0xC4, // '-',
887                              Right - Left - 1,
888                              coPos,
889                              &Written);
890
891   /* draw upper right corner */
892   coPos.X = Right;
893   coPos.Y = Top;
894   FillConsoleOutputCharacter(0xBF, // '+',
895                              1,
896                              coPos,
897                              &Written);
898
899   /* draw left and right edge */
900   for (i = Top + 1; i < Bottom; i++)
901     {
902       coPos.X = Left;
903       coPos.Y = i;
904       FillConsoleOutputCharacter(0xB3, // '|',
905                                  1,
906                                  coPos,
907                                  &Written);
908
909       coPos.X = Right;
910       FillConsoleOutputCharacter(0xB3, //'|',
911                                  1,
912                                  coPos,
913                                  &Written);
914     }
915
916   /* draw lower left corner */
917   coPos.X = Left;
918   coPos.Y = Bottom;
919   FillConsoleOutputCharacter(0xC0, // '+',
920                              1,
921                              coPos,
922                              &Written);
923
924   /* draw lower edge */
925   coPos.X = Left + 1;
926   coPos.Y = Bottom;
927   FillConsoleOutputCharacter(0xC4, // '-',
928                              Right - Left - 1,
929                              coPos,
930                              &Written);
931
932   /* draw lower right corner */
933   coPos.X = Right;
934   coPos.Y = Bottom;
935   FillConsoleOutputCharacter(0xD9, // '+',
936                              1,
937                              coPos,
938                              &Written);
939
940   /* Print message */
941   coPos.X = Left + 2;
942   coPos.Y = Top + 2;
943   strcpy (Buffer, "Size of new partition:");
944   iLeft = coPos.X + strlen (Buffer) + 1;
945   iTop = coPos.Y;
946   WriteConsoleOutputCharacters (Buffer,
947                                  strlen (Buffer),
948                                  coPos);
949
950   sprintf (Buffer, "MB (max. %d MB)", MaxSize);
951   coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
952   coPos.Y = iTop;
953   WriteConsoleOutputCharacters (Buffer,
954                                 strlen (Buffer),
955                                 coPos);
956
957   Buffer[0] = 0;
958   Index = 0;
959   DrawInputField (PARTITION_SIZE_INPUT_FIELD_LENGTH,
960                   iLeft,
961                   iTop,
962                   Buffer);
963
964   while (TRUE)
965     {
966       ConInKey (&Ir);
967
968       if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
969           (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
970         {
971           if (Quit != NULL)
972             *Quit = TRUE;
973           Buffer[0] = 0;
974           break;
975         }
976       else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN)  /* ENTER */
977         {
978           break;
979         }
980       else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)  /* ESCAPE */
981         {
982           if (Cancel != NULL)
983             *Cancel = TRUE;
984           Buffer[0] = 0;
985           break;
986         }
987       else if ((Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) &&  /* BACKSPACE */
988                (Index > 0))
989         {
990           Index--;
991           Buffer[Index] = 0;
992           DrawInputField (PARTITION_SIZE_INPUT_FIELD_LENGTH,
993                           iLeft,
994                           iTop,
995                           Buffer);
996         }
997       else if ((Ir.Event.KeyEvent.uChar.AsciiChar != 0x00) &&
998                (Index < PARTITION_SIZE_INPUT_FIELD_LENGTH))
999         {
1000           ch = Ir.Event.KeyEvent.uChar.AsciiChar;
1001           if ((ch >= '0') && (ch <= '9'))
1002             {
1003               Buffer[Index] = ch;
1004               Index++;
1005               Buffer[Index] = 0;
1006               DrawInputField (PARTITION_SIZE_INPUT_FIELD_LENGTH,
1007                               iLeft,
1008                               iTop,
1009                               Buffer);
1010             }
1011         }
1012     }
1013
1014   strcpy (InputBuffer,
1015           Buffer);
1016 }
1017
1018
1019 static PAGE_NUMBER
1020 CreatePartitionPage (PINPUT_RECORD Ir)
1021 {
1022   PDISKENTRY DiskEntry;
1023   PPARTENTRY PartEntry;
1024   SHORT xScreen;
1025   SHORT yScreen;
1026   BOOLEAN Quit;
1027   BOOLEAN Cancel;
1028   CHAR InputBuffer[50];
1029   ULONG MaxSize;
1030   ULONGLONG PartSize;
1031   ULONGLONG DiskSize;
1032   PCHAR Unit;
1033
1034   if (PartitionList == NULL ||
1035       PartitionList->CurrentDisk == NULL ||
1036       PartitionList->CurrentPartition == NULL)
1037     {
1038       /* FIXME: show an error dialog */
1039       return QUIT_PAGE;
1040     }
1041
1042   DiskEntry = PartitionList->CurrentDisk;
1043   PartEntry = PartitionList->CurrentPartition;
1044
1045   SetStatusText ("   Please wait...");
1046
1047   GetScreenSize (&xScreen, &yScreen);
1048
1049   SetTextXY (6, 8, "You have chosen to create a new partition on");
1050
1051 #if 0
1052   if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
1053     {
1054       DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
1055       Unit = "GB";
1056     }
1057   else
1058 #endif
1059     {
1060       DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
1061       if (DiskSize == 0)
1062         DiskSize = 1;
1063       Unit = "MB";
1064     }
1065
1066   if (DiskEntry->DriverName.Length > 0)
1067     {
1068       PrintTextXY (6, 10,
1069                    "%I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu) on %wZ.",
1070                    DiskSize,
1071                    Unit,
1072                    DiskEntry->DiskNumber,
1073                    DiskEntry->Port,
1074                    DiskEntry->Bus,
1075                    DiskEntry->Id,
1076                    &DiskEntry->DriverName);
1077     }
1078   else
1079     {
1080       PrintTextXY (6, 10,
1081                    "%I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu).",
1082                    DiskSize,
1083                    Unit,
1084                    DiskEntry->DiskNumber,
1085                    DiskEntry->Port,
1086                    DiskEntry->Bus,
1087                    DiskEntry->Id);
1088     }
1089
1090
1091   SetTextXY (6, 12, "Please enter the size of the new partition in megabytes.");
1092
1093 #if 0
1094   PrintTextXY (8, 10, "Maximum size of the new partition is %I64u MB",
1095                PartitionList->CurrentPartition->UnpartitionedLength / (1024*1024));
1096 #endif
1097
1098   SetStatusText ("   ENTER = Create Partition   ESC = Cancel   F3 = Quit");
1099
1100   PartEntry = PartitionList->CurrentPartition;
1101   while (TRUE)
1102     {
1103       MaxSize = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;  /* in MBytes (rounded) */
1104       ShowPartitionSizeInputBox (12, 14, xScreen - 12, 17, /* left, top, right, bottom */
1105                                  MaxSize, InputBuffer, &Quit, &Cancel);
1106       if (Quit == TRUE)
1107         {
1108           if (ConfirmQuit (Ir) == TRUE)
1109             {
1110               return QUIT_PAGE;
1111             }
1112         }
1113       else if (Cancel == TRUE)
1114         {
1115           return SELECT_PARTITION_PAGE;
1116         }
1117       else
1118         {
1119           PartSize = atoi (InputBuffer);
1120           if (PartSize < 1)
1121             {
1122               /* Too small */
1123               continue;
1124             }
1125
1126           if (PartSize > MaxSize)
1127             {
1128               /* Too large */
1129               continue;
1130             }
1131
1132           /* Convert to bytes */
1133           if (PartSize == MaxSize)
1134             {
1135               /* Use all of the unpartitioned disk space */
1136               PartSize = PartEntry->UnpartitionedLength;
1137             }
1138           else
1139             {
1140               /* Round-up by cylinder size */
1141               PartSize = ROUND_UP (PartSize * 1024 * 1024,
1142                                    DiskEntry->CylinderSize);
1143
1144               /* But never get larger than the unpartitioned disk space */
1145               if (PartSize > PartEntry->UnpartitionedLength)
1146                 PartSize = PartEntry->UnpartitionedLength;
1147             }
1148
1149           DPRINT ("Partition size: %I64u bytes\n", PartSize);
1150
1151           CreateNewPartition (PartitionList,
1152                               PartSize,
1153                               FALSE);
1154
1155           return SELECT_PARTITION_PAGE;
1156         }
1157     }
1158
1159   return CREATE_PARTITION_PAGE;
1160 }
1161
1162
1163 static PAGE_NUMBER
1164 DeletePartitionPage (PINPUT_RECORD Ir)
1165 {
1166   PDISKENTRY DiskEntry;
1167   PPARTENTRY PartEntry;
1168   ULONGLONG DiskSize;
1169   ULONGLONG PartSize;
1170   PCHAR Unit;
1171   PCHAR PartType;
1172
1173   if (PartitionList == NULL ||
1174       PartitionList->CurrentDisk == NULL ||
1175       PartitionList->CurrentPartition == NULL)
1176     {
1177       /* FIXME: show an error dialog */
1178       return QUIT_PAGE;
1179     }
1180
1181   DiskEntry = PartitionList->CurrentDisk;
1182   PartEntry = PartitionList->CurrentPartition;
1183
1184   SetTextXY (6, 8, "You have chosen to delete the partition");
1185
1186   /* Determine partition type */
1187   PartType = NULL;
1188   if (PartEntry->New == TRUE)
1189     {
1190       PartType = "New (Unformatted)";
1191     }
1192   else if (PartEntry->Unpartitioned == FALSE)
1193     {
1194       if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
1195           (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
1196           (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
1197           (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
1198         {
1199           PartType = "FAT";
1200         }
1201       else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
1202                (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
1203         {
1204           PartType = "FAT32";
1205         }
1206       else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
1207         {
1208           PartType = "NTFS"; /* FIXME: Not quite correct! */
1209         }
1210     }
1211
1212 #if 0
1213   if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000ULL) /* 10 GB */
1214     {
1215       PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
1216       Unit = "GB";
1217     }
1218   else
1219 #endif
1220   if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0xA00000ULL) /* 10 MB */
1221     {
1222       PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
1223       Unit = "MB";
1224     }
1225   else
1226     {
1227       PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 9)) >> 10;
1228       Unit = "KB";
1229     }
1230
1231   if (PartType == NULL)
1232     {
1233       PrintTextXY (6, 10,
1234                    "   %c%c  Type %lu    %I64u %s",
1235                    (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1236                    (PartEntry->DriveLetter == 0) ? '-' : ':',
1237                    PartEntry->PartInfo[0].PartitionType,
1238                    PartSize,
1239                    Unit);
1240     }
1241   else
1242     {
1243       PrintTextXY (6, 10,
1244                    "   %c%c  %s    %I64u %s",
1245                    (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1246                    (PartEntry->DriveLetter == 0) ? '-' : ':',
1247                    PartType,
1248                    PartSize,
1249                    Unit);
1250     }
1251
1252 #if 0
1253   if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
1254     {
1255       DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
1256       Unit = "GB";
1257     }
1258   else
1259 #endif
1260     {
1261       DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
1262       if (DiskSize == 0)
1263         DiskSize = 1;
1264       Unit = "MB";
1265     }
1266
1267   if (DiskEntry->DriverName.Length > 0)
1268     {
1269       PrintTextXY (6, 12,
1270                    "on %I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu) on %wZ.",
1271                    DiskSize,
1272                    Unit,
1273                    DiskEntry->DiskNumber,
1274                    DiskEntry->Port,
1275                    DiskEntry->Bus,
1276                    DiskEntry->Id,
1277                    &DiskEntry->DriverName);
1278     }
1279   else
1280     {
1281       PrintTextXY (6, 12,
1282                    "on %I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu).",
1283                    DiskSize,
1284                    Unit,
1285                    DiskEntry->DiskNumber,
1286                    DiskEntry->Port,
1287                    DiskEntry->Bus,
1288                    DiskEntry->Id);
1289     }
1290
1291   SetTextXY (8, 18, "\x07  Press D to delete the partition.");
1292   SetTextXY (11, 19, "WARNING: All data on this partition will be lost!");
1293
1294   SetTextXY (8, 21, "\x07  Press ESC to cancel.");
1295
1296   SetStatusText ("   D = Delete Partition   ESC = Cancel   F3 = Quit");
1297
1298   while (TRUE)
1299     {
1300       ConInKey (Ir);
1301
1302       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1303           (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1304         {
1305           if (ConfirmQuit (Ir) == TRUE)
1306             {
1307               return QUIT_PAGE;
1308             }
1309           break;
1310         }
1311       else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)  /* ESC */
1312         {
1313           return SELECT_PARTITION_PAGE;
1314         }
1315       else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_D) /* D */
1316         {
1317           DeleteCurrentPartition (PartitionList);
1318
1319           return SELECT_PARTITION_PAGE;
1320         }
1321     }
1322
1323   return DELETE_PARTITION_PAGE;
1324 }
1325
1326
1327 static PAGE_NUMBER
1328 SelectFileSystemPage (PINPUT_RECORD Ir)
1329 {
1330   PDISKENTRY DiskEntry;
1331   PPARTENTRY PartEntry;
1332   ULONGLONG DiskSize;
1333   ULONGLONG PartSize;
1334   PCHAR DiskUnit;
1335   PCHAR PartUnit;
1336   PCHAR PartType;
1337
1338   if (PartitionList == NULL ||
1339       PartitionList->CurrentDisk == NULL ||
1340       PartitionList->CurrentPartition == NULL)
1341     {
1342       /* FIXME: show an error dialog */
1343       return QUIT_PAGE;
1344     }
1345
1346   DiskEntry = PartitionList->CurrentDisk;
1347   PartEntry = PartitionList->CurrentPartition;
1348
1349   /* adjust disk size */
1350   if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
1351     {
1352       DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
1353       DiskUnit = "GB";
1354     }
1355   else
1356     {
1357       DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
1358       DiskUnit = "MB";
1359     }
1360
1361   /* adjust partition size */
1362   if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000ULL) /* 10 GB */
1363     {
1364       PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
1365       PartUnit = "GB";
1366     }
1367   else
1368     {
1369       PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
1370       PartUnit = "MB";
1371     }
1372
1373   /* adjust partition type */
1374   if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
1375       (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
1376       (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
1377       (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
1378     {
1379       PartType = "FAT";
1380     }
1381   else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
1382            (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
1383     {
1384       PartType = "FAT32";
1385     }
1386   else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
1387     {
1388       PartType = "NTFS"; /* FIXME: Not quite correct! */
1389     }
1390   else if (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED)
1391     {
1392       PartType = "Unused";
1393     }
1394   else
1395     {
1396       PartType = "Unknown";
1397     }
1398
1399   if (PartEntry->AutoCreate == TRUE)
1400     {
1401       SetTextXY(6, 8, "Setup created a new partition on");
1402
1403 #if 0
1404   PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
1405               PartEntry->PartInfo[0].PartitionNumber,
1406               PartSize,
1407               PartUnit,
1408               PartType);
1409 #endif
1410
1411   PrintTextXY(8, 10, "Harddisk %lu (%I64u %s), Port=%hu, Bus=%hu, Id=%hu (%wZ).",
1412               DiskEntry->DiskNumber,
1413               DiskSize,
1414               DiskUnit,
1415               DiskEntry->Port,
1416               DiskEntry->Bus,
1417               DiskEntry->Id,
1418               &DiskEntry->DriverName);
1419
1420       SetTextXY(6, 12, "This Partition will be formatted next.");
1421
1422
1423       PartEntry->AutoCreate = FALSE;
1424     }
1425   else if (PartEntry->New == TRUE)
1426     {
1427       SetTextXY(6, 8, "You chose to install ReactOS on a new or unformatted Partition.");
1428       SetTextXY(6, 10, "This Partition will be formatted next.");
1429     }
1430   else
1431     {
1432       SetTextXY(6, 8, "Setup install ReactOS onto Partition");
1433
1434       if (PartType == NULL)
1435         {
1436           PrintTextXY (8, 10,
1437                        "%c%c  Type %lu    %I64u %s",
1438                        (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1439                        (PartEntry->DriveLetter == 0) ? '-' : ':',
1440                        PartEntry->PartInfo[0].PartitionType,
1441                        PartSize,
1442                        PartUnit);
1443         }
1444       else
1445         {
1446           PrintTextXY (8, 10,
1447                        "%c%c  %s    %I64u %s",
1448                        (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
1449                        (PartEntry->DriveLetter == 0) ? '-' : ':',
1450                        PartType,
1451                        PartSize,
1452                        PartUnit);
1453         }
1454
1455       PrintTextXY(6, 12, "on Harddisk %lu (%I64u %s), Port=%hu, Bus=%hu, Id=%hu (%wZ).",
1456                   DiskEntry->DiskNumber,
1457                   DiskSize,
1458                   DiskUnit,
1459                   DiskEntry->Port,
1460                   DiskEntry->Bus,
1461                   DiskEntry->Id,
1462                   &DiskEntry->DriverName);
1463     }
1464
1465
1466   SetTextXY(6, 17, "Select a file system from the list below.");
1467
1468   SetTextXY(8, 19, "\x07  Press UP or DOWN to select a file system.");
1469   SetTextXY(8, 21, "\x07  Press ENTER to format the partition.");
1470   SetTextXY(8, 23, "\x07  Press ESC to select another partition.");
1471
1472   if (FileSystemList == NULL)
1473     {
1474       FileSystemList = CreateFileSystemList (6, 26, PartEntry->New, FsFat);
1475       if (FileSystemList == NULL)
1476         {
1477           /* FIXME: show an error dialog */
1478           return QUIT_PAGE;
1479         }
1480
1481       /* FIXME: Add file systems to list */
1482     }
1483   DrawFileSystemList (FileSystemList);
1484
1485   SetStatusText ("   ENTER = Continue   ESC = Cancel   F3 = Quit");
1486
1487   while (TRUE)
1488     {
1489       ConInKey (Ir);
1490
1491       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1492           (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1493         {
1494           if (ConfirmQuit (Ir) == TRUE)
1495             {
1496               return QUIT_PAGE;
1497             }
1498           break;
1499         }
1500       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1501                (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1502         {
1503           return SELECT_PARTITION_PAGE;
1504         }
1505       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1506                (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1507         {
1508           ScrollDownFileSystemList (FileSystemList);
1509         }
1510       else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1511                (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1512         {
1513           ScrollUpFileSystemList (FileSystemList);
1514         }
1515       else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1516         {
1517           if (FileSystemList->CurrentFileSystem == FsKeep)
1518             {
1519               return CHECK_FILE_SYSTEM_PAGE;
1520             }
1521           else
1522             {
1523               return FORMAT_PARTITION_PAGE;
1524             }
1525         }
1526     }
1527
1528   return SELECT_FILE_SYSTEM_PAGE;
1529 }
1530
1531
1532 static ULONG
1533 FormatPartitionPage (PINPUT_RECORD Ir)
1534 {
1535   WCHAR PathBuffer[MAX_PATH];
1536   PDISKENTRY DiskEntry;
1537   PPARTENTRY PartEntry;
1538   PLIST_ENTRY Entry;
1539   NTSTATUS Status;
1540
1541 //#ifndef NDEBUG
1542   ULONG Line;
1543   ULONG i;
1544 //#endif
1545
1546
1547   SetTextXY(6, 8, "Format partition");
1548
1549   SetTextXY(6, 10, "Setup will now format the partition. Press ENTER to continue.");
1550
1551   SetStatusText("   ENTER = Continue   F3 = Quit");
1552
1553
1554   if (PartitionList == NULL ||
1555       PartitionList->CurrentDisk == NULL ||
1556       PartitionList->CurrentPartition == NULL)
1557     {
1558       /* FIXME: show an error dialog */
1559       return QUIT_PAGE;
1560     }
1561
1562   DiskEntry = PartitionList->CurrentDisk;
1563   PartEntry = PartitionList->CurrentPartition;
1564
1565   while(TRUE)
1566     {
1567       ConInKey(Ir);
1568
1569       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1570           (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1571         {
1572           if (ConfirmQuit (Ir) == TRUE)
1573             {
1574               return QUIT_PAGE;
1575             }
1576           break;
1577         }
1578       else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1579         {
1580           SetStatusText ("   Please wait ...");
1581
1582           if (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED)
1583             {
1584               switch (FileSystemList->CurrentFileSystem)
1585                 {
1586                   case FsFat:
1587                     if (PartEntry->PartInfo[0].PartitionLength.QuadPart < (4200ULL * 1024ULL))
1588                       {
1589                         /* FAT12 CHS partition (disk is smaller than 4.1MB) */
1590                         PartEntry->PartInfo[0].PartitionType = PARTITION_FAT_12;
1591                       }
1592                     else if (PartEntry->PartInfo[0].StartingOffset.QuadPart < (1024ULL * 255ULL * 63ULL * 512ULL))
1593                       {
1594                         /* Partition starts below the 8.4GB boundary ==> CHS partition */
1595
1596                         if (PartEntry->PartInfo[0].PartitionLength.QuadPart < (32ULL * 1024ULL * 1024ULL))
1597                           {
1598                             /* FAT16 CHS partition (partiton size < 32MB) */
1599                             PartEntry->PartInfo[0].PartitionType = PARTITION_FAT_16;
1600                           }
1601                         else if (PartEntry->PartInfo[0].PartitionLength.QuadPart < (512ULL * 1024ULL * 1024ULL))
1602                           {
1603                             /* FAT16 CHS partition (partition size < 512MB) */
1604                             PartEntry->PartInfo[0].PartitionType = PARTITION_HUGE;
1605                           }
1606                         else
1607                           {
1608                             /* FAT32 CHS partition (partition size >= 512MB) */
1609                             PartEntry->PartInfo[0].PartitionType = PARTITION_FAT32;
1610                           }
1611                       }
1612                     else
1613                       {
1614                         /* Partition starts above the 8.4GB boundary ==> LBA partition */
1615
1616                         if (PartEntry->PartInfo[0].PartitionLength.QuadPart < (512ULL * 1024ULL * 1024ULL))
1617                           {
1618                             /* FAT16 LBA partition (partition size < 512MB) */
1619                             PartEntry->PartInfo[0].PartitionType = PARTITION_XINT13;
1620                           }
1621                         else
1622                           {
1623                             /* FAT32 LBA partition (partition size >= 512MB) */
1624                             PartEntry->PartInfo[0].PartitionType = PARTITION_FAT32_XINT13;
1625                           }
1626                       }
1627                     break;
1628
1629                   case FsKeep:
1630                     break;
1631
1632                   default:
1633                     return QUIT_PAGE;
1634                 }
1635             }
1636
1637           CheckActiveBootPartition (PartitionList);
1638
1639 //#ifndef NDEBUG
1640           PrintTextXY (6, 12,
1641                        "Disk: %I64u  Cylinder: %I64u  Track: %I64u",
1642                        DiskEntry->DiskSize,
1643                        DiskEntry->CylinderSize,
1644                        DiskEntry->TrackSize);
1645
1646           Line = 13;
1647           DiskEntry = PartitionList->CurrentDisk;
1648           Entry = DiskEntry->PartListHead.Flink;
1649           while (Entry != &DiskEntry->PartListHead)
1650             {
1651               PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1652
1653               if (PartEntry->Unpartitioned == FALSE)
1654                 {
1655
1656                   for (i = 0; i < 4; i++)
1657                     {
1658                       PrintTextXY (6, Line,
1659                                    "%2u:  %2u  %c  %12I64u  %12I64u  %2u  %c",
1660                                    i,
1661                                    PartEntry->PartInfo[i].PartitionNumber,
1662                                    PartEntry->PartInfo[i].BootIndicator ? 'A' : '-',
1663                                    PartEntry->PartInfo[i].StartingOffset.QuadPart,
1664                                    PartEntry->PartInfo[i].PartitionLength.QuadPart,
1665                                    PartEntry->PartInfo[i].PartitionType,
1666                                    PartEntry->PartInfo[i].RewritePartition ? '*' : ' ');
1667
1668                       Line++;
1669                     }
1670
1671                   Line++;
1672                 }
1673
1674               Entry = Entry->Flink;
1675             }
1676
1677           /* Restore the old entry */
1678           PartEntry = PartitionList->CurrentPartition;
1679 //#endif
1680
1681           if (WritePartitionsToDisk (PartitionList) == FALSE)
1682             {
1683               DPRINT ("WritePartitionsToDisk() failed\n");
1684
1685               PopupError ("Setup failed to write partition tables.\n",
1686                           "ENTER = Reboot computer");
1687
1688               while (TRUE)
1689                 {
1690                   ConInKey (Ir);
1691
1692                   if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1693                     {
1694                       return QUIT_PAGE;
1695                     }
1696                 }
1697             }
1698
1699
1700           /* Set DestinationRootPath */
1701           RtlFreeUnicodeString (&DestinationRootPath);
1702           swprintf (PathBuffer,
1703                     L"\\Device\\Harddisk%lu\\Partition%lu",
1704                     PartitionList->CurrentDisk->DiskNumber,
1705                     PartitionList->CurrentPartition->PartInfo[0].PartitionNumber);
1706           RtlCreateUnicodeString (&DestinationRootPath,
1707                                   PathBuffer);
1708           DPRINT ("DestinationRootPath: %wZ\n", &DestinationRootPath);
1709
1710
1711           /* Set SystemRootPath */
1712           RtlFreeUnicodeString (&SystemRootPath);
1713           swprintf (PathBuffer,
1714                     L"\\Device\\Harddisk%lu\\Partition%lu",
1715                     PartitionList->ActiveBootDisk->DiskNumber,
1716                     PartitionList->ActiveBootPartition->PartInfo[0].PartitionNumber);
1717           RtlCreateUnicodeString (&SystemRootPath,
1718                                   PathBuffer);
1719           DPRINT ("SystemRootPath: %wZ\n", &SystemRootPath);
1720
1721
1722           switch (FileSystemList->CurrentFileSystem)
1723             {
1724               case FsFat:
1725                 Status = FormatPartition (&DestinationRootPath);
1726                 if (!NT_SUCCESS (Status))
1727                   {
1728                     DPRINT1 ("FormatPartition() failed with status 0x%.08x\n", Status);
1729                     /* FIXME: show an error dialog */
1730                     return QUIT_PAGE;
1731                   }
1732
1733                 PartEntry->New = FALSE;
1734                 if (FileSystemList != NULL)
1735                   {
1736                     DestroyFileSystemList (FileSystemList);
1737                     FileSystemList = NULL;
1738                   }
1739
1740                 CheckActiveBootPartition (PartitionList);
1741
1742                 /* FIXME: Install boot code. This is a hack! */
1743                 if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13) ||
1744                     (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32))
1745                   {
1746                     wcscpy (PathBuffer, SourceRootPath.Buffer);
1747                     wcscat (PathBuffer, L"\\loader\\fat32.bin");
1748
1749                     DPRINT1 ("Install FAT32 bootcode: %S ==> %S\n", PathBuffer,
1750                              DestinationRootPath.Buffer);
1751                     Status = InstallFat32BootCodeToDisk (PathBuffer,
1752                                                          DestinationRootPath.Buffer);
1753                     if (!NT_SUCCESS (Status))
1754                       {
1755                         DPRINT1 ("InstallFat32BootCodeToDisk() failed with status 0x%.08x\n", Status);
1756                         /* FIXME: show an error dialog */
1757                         return QUIT_PAGE;
1758                       }
1759                   }
1760                 else
1761                   {
1762                     wcscpy (PathBuffer, SourceRootPath.Buffer);
1763                     wcscat (PathBuffer, L"\\loader\\fat.bin");
1764
1765                     DPRINT1 ("Install FAT bootcode: %S ==> %S\n", PathBuffer,
1766                              DestinationRootPath.Buffer);
1767                     Status = InstallFat16BootCodeToDisk (PathBuffer,
1768                                                          DestinationRootPath.Buffer);
1769                     if (!NT_SUCCESS (Status))
1770                       {
1771                         DPRINT1 ("InstallFat16BootCodeToDisk() failed with status 0x%.08x\n", Status);
1772                         /* FIXME: show an error dialog */
1773                         return QUIT_PAGE;
1774                       }
1775                   }
1776                 break;
1777
1778               case FsKeep:
1779                 break;
1780
1781               default:
1782                 return QUIT_PAGE;
1783             }
1784
1785           SetStatusText ("   Done.  Press any key ...");
1786           ConInKey(Ir);
1787
1788           return INSTALL_DIRECTORY_PAGE;
1789         }
1790     }
1791
1792   return FORMAT_PARTITION_PAGE;
1793 }
1794
1795
1796 static ULONG
1797 CheckFileSystemPage(PINPUT_RECORD Ir)
1798 {
1799   WCHAR PathBuffer[MAX_PATH];
1800
1801   SetTextXY(6, 8, "Check file system");
1802
1803   SetTextXY(6, 10, "At present, ReactOS can not check file systems.");
1804
1805   SetStatusText("   Please wait ...");
1806
1807
1808   SetStatusText("   ENTER = Continue   F3 = Quit");
1809
1810
1811   /* Set DestinationRootPath */
1812   RtlFreeUnicodeString (&DestinationRootPath);
1813   swprintf (PathBuffer,
1814             L"\\Device\\Harddisk%lu\\Partition%lu",
1815             PartitionList->CurrentDisk->DiskNumber,
1816             PartitionList->CurrentPartition->PartInfo[0].PartitionNumber);
1817   RtlCreateUnicodeString (&DestinationRootPath,
1818                           PathBuffer);
1819   DPRINT ("DestinationRootPath: %wZ\n", &DestinationRootPath);
1820
1821   /* Set SystemRootPath */
1822   RtlFreeUnicodeString (&SystemRootPath);
1823   swprintf (PathBuffer,
1824             L"\\Device\\Harddisk%lu\\Partition%lu",
1825             PartitionList->ActiveBootDisk->DiskNumber,
1826             PartitionList->ActiveBootPartition->PartInfo[0].PartitionNumber);
1827   RtlCreateUnicodeString (&SystemRootPath,
1828                           PathBuffer);
1829   DPRINT ("SystemRootPath: %wZ\n", &SystemRootPath);
1830
1831
1832   while(TRUE)
1833     {
1834       ConInKey(Ir);
1835
1836       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1837           (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1838         {
1839           if (ConfirmQuit(Ir) == TRUE)
1840             return(QUIT_PAGE);
1841           break;
1842         }
1843       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1844         {
1845           return(INSTALL_DIRECTORY_PAGE);
1846         }
1847     }
1848
1849   return(CHECK_FILE_SYSTEM_PAGE);
1850 }
1851
1852
1853 static PAGE_NUMBER
1854 InstallDirectoryPage(PINPUT_RECORD Ir)
1855 {
1856   PDISKENTRY DiskEntry;
1857   PPARTENTRY PartEntry;
1858   WCHAR PathBuffer[MAX_PATH];
1859   WCHAR InstallDir[51];
1860   PWCHAR DefaultPath;
1861   INFCONTEXT Context;
1862   ULONG Length;
1863   NTSTATUS Status;
1864
1865   if (PartitionList == NULL ||
1866       PartitionList->CurrentDisk == NULL ||
1867       PartitionList->CurrentPartition == NULL)
1868     {
1869       /* FIXME: show an error dialog */
1870       return QUIT_PAGE;
1871     }
1872
1873   DiskEntry = PartitionList->CurrentDisk;
1874   PartEntry = PartitionList->CurrentPartition;
1875
1876   /* Search for 'DefaultPath' in the 'SetupData' section */
1877   if (!InfFindFirstLine (SetupInf, L"SetupData", L"DefaultPath", &Context))
1878     {
1879       PopupError("Setup failed to find the 'SetupData' section\n"
1880                  "in TXTSETUP.SIF.\n",
1881                  "ENTER = Reboot computer");
1882
1883       while (TRUE)
1884         {
1885           ConInKey (Ir);
1886
1887           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
1888             {
1889               return QUIT_PAGE;
1890             }
1891         }
1892     }
1893
1894   /* Read the 'DefaultPath' data */
1895   if (InfGetData (&Context, NULL, &DefaultPath))
1896     {
1897       wcscpy(InstallDir, DefaultPath);
1898     }
1899   else
1900     {
1901       wcscpy(InstallDir, L"\\ReactOS");
1902     }
1903   Length = wcslen(InstallDir);
1904
1905   SetTextXY(6, 8, "Setup installs ReactOS files onto the selected partition. Choose a");
1906   SetTextXY(6, 9, "directory where you want ReactOS to be installed:");
1907
1908   SetInputTextXY(8, 11, 51, InstallDir);
1909
1910   SetTextXY(6, 14, "To change the suggested directory, press BACKSPACE to delete");
1911   SetTextXY(6, 15, "characters and then type the directory where you want ReactOS to");
1912   SetTextXY(6, 16, "be installed.");
1913
1914   SetStatusText("   ENTER = Continue   F3 = Quit");
1915
1916   while(TRUE)
1917     {
1918       ConInKey(Ir);
1919
1920       if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1921           (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1922         {
1923           if (ConfirmQuit(Ir) == TRUE)
1924             return(QUIT_PAGE);
1925           break;
1926         }
1927       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1928         {
1929           /* Create 'InstallPath' string */
1930           RtlFreeUnicodeString(&InstallPath);
1931           RtlCreateUnicodeString(&InstallPath,
1932                                  InstallDir);
1933
1934           /* Create 'DestinationPath' string */
1935           RtlFreeUnicodeString(&DestinationPath);
1936           wcscpy(PathBuffer,
1937                  DestinationRootPath.Buffer);
1938           if (InstallDir[0] != L'\\')
1939             wcscat(PathBuffer,
1940                    L"\\");
1941           wcscat(PathBuffer, InstallDir);
1942           RtlCreateUnicodeString(&DestinationPath,
1943                                  PathBuffer);
1944
1945           /* Create 'DestinationArcPath' */
1946           RtlFreeUnicodeString(&DestinationArcPath);
1947           swprintf(PathBuffer,
1948                    L"multi(0)disk(0)rdisk(%lu)partition(%lu)",
1949                    DiskEntry->DiskNumber,
1950                    PartEntry->PartInfo[0].PartitionNumber);
1951           if (InstallDir[0] != L'\\')
1952             wcscat(PathBuffer,
1953                    L"\\");
1954           wcscat(PathBuffer, InstallDir);
1955           RtlCreateUnicodeString(&DestinationArcPath,
1956                                  PathBuffer);
1957
1958           return(PREPARE_COPY_PAGE);
1959         }
1960       else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
1961         {
1962           if (Length > 0)
1963             {
1964               Length--;
1965               InstallDir[Length] = 0;
1966               SetInputTextXY(8, 11, 51, InstallDir);
1967             }
1968         }
1969       else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
1970         {
1971           if (Length < 50)
1972             {
1973               InstallDir[Length] = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
1974               Length++;
1975               InstallDir[Length] = 0;
1976               SetInputTextXY(8, 11, 51, InstallDir);
1977             }
1978         }
1979     }
1980
1981   return(INSTALL_DIRECTORY_PAGE);
1982 }
1983
1984
1985 static BOOLEAN
1986 PrepareCopyPageInfFile(HINF InfFile, PWCHAR SourceCabinet, PINPUT_RECORD Ir)
1987 {
1988   WCHAR PathBuffer[MAX_PATH];
1989   INFCONTEXT FilesContext;
1990   INFCONTEXT DirContext;
1991   PWCHAR KeyName;
1992   PWCHAR KeyValue;
1993   ULONG Length;
1994   NTSTATUS Status;
1995   PWCHAR FileKeyName;
1996   PWCHAR FileKeyValue;
1997   PWCHAR DirKeyName;
1998   PWCHAR DirKeyValue;
1999
2000   /* Search for the 'SourceFiles' section */
2001   if (!InfFindFirstLine (InfFile, L"SourceFiles", NULL, &FilesContext))
2002     {
2003       PopupError("Setup failed to find the 'SourceFiles' section\n"
2004                  "in TXTSETUP.SIF.\n",  // FIXME
2005                  "ENTER = Reboot computer");
2006
2007       while(TRUE)
2008         {
2009           ConInKey(Ir);
2010
2011           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2012             {
2013               return(FALSE);
2014             }
2015         }
2016     }
2017
2018   /*
2019    * Enumerate the files in the 'SourceFiles' section
2020    * and add them to the file queue.
2021    */
2022   do
2023     {
2024       if (!InfGetData (&FilesContext, &FileKeyName, &FileKeyValue))
2025         {
2026           DPRINT("break\n");
2027                 break;
2028         }
2029
2030       DPRINT ("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
2031
2032       /* Lookup target directory */
2033       if (!InfFindFirstLine (InfFile, L"Directories", FileKeyValue, &DirContext))
2034         {
2035           /* FIXME: Handle error! */
2036           DPRINT1("InfFindFirstLine() failed\n");
2037           break;
2038         }
2039
2040       if (!InfGetData (&DirContext, NULL, &DirKeyValue))
2041         {
2042           /* FIXME: Handle error! */
2043           DPRINT1("InfGetData() failed\n");
2044           break;
2045         }
2046
2047       if (!SetupQueueCopy(SetupFileQueue,
2048         SourceCabinet,
2049                           SourceRootPath.Buffer,
2050                           L"\\reactos",
2051                           FileKeyName,
2052                           DirKeyValue,
2053                           NULL))
2054         {
2055           /* FIXME: Handle error! */
2056           DPRINT1("SetupQueueCopy() failed\n");
2057         }
2058     }
2059   while (InfFindNextLine(&FilesContext, &FilesContext));
2060
2061
2062   /* Create directories */
2063
2064   /*
2065    * FIXME:
2066    * Install directories like '\reactos\test' are not handled yet.
2067    */
2068
2069   /* Get destination path */
2070   wcscpy(PathBuffer, DestinationPath.Buffer);
2071
2072   /* Remove trailing backslash */
2073   Length = wcslen(PathBuffer);
2074   if ((Length > 0) && (PathBuffer[Length - 1] == '\\'))
2075     {
2076       PathBuffer[Length - 1] = 0;
2077     }
2078
2079   /* Create the install directory */
2080   Status = CreateDirectory(PathBuffer);
2081   if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
2082     {
2083       DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
2084       PopupError("Setup could not create the install directory.",
2085                  "ENTER = Reboot computer");
2086
2087       while(TRUE)
2088         {
2089           ConInKey(Ir);
2090
2091           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2092             {
2093               return(FALSE);
2094             }
2095         }
2096     }
2097
2098
2099   /* Search for the 'Directories' section */
2100   if (!InfFindFirstLine(InfFile, L"Directories", NULL, &DirContext))
2101     {
2102       if (SourceCabinet)
2103         {
2104           PopupError("Setup failed to find the 'Directories' section\n"
2105                     "in the cabinet.\n", "ENTER = Reboot computer");
2106         }
2107       else
2108         {
2109           PopupError("Setup failed to find the 'Directories' section\n"
2110                     "in TXTSETUP.SIF.\n", "ENTER = Reboot computer");
2111         }
2112
2113       while(TRUE)
2114         {
2115           ConInKey(Ir);
2116
2117           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2118             {
2119               return(FALSE);
2120             }
2121         }
2122     }
2123
2124   /* Enumerate the directory values and create the subdirectories */
2125   do
2126     {
2127       if (!InfGetData (&DirContext, NULL, &KeyValue))
2128         {
2129           DPRINT1("break\n");
2130                 break;
2131         }
2132
2133       if (KeyValue[0] == L'\\' && KeyValue[1] != 0)
2134         {
2135               DPRINT("Absolute Path: '%S'\n", KeyValue);
2136
2137               wcscpy(PathBuffer, DestinationRootPath.Buffer);
2138               wcscat(PathBuffer, KeyValue);
2139
2140               DPRINT("FullPath: '%S'\n", PathBuffer);
2141         }
2142       else if (KeyValue[0] != L'\\')
2143         {
2144           DPRINT("RelativePath: '%S'\n", KeyValue);
2145           wcscpy(PathBuffer, DestinationPath.Buffer);
2146           wcscat(PathBuffer, L"\\");
2147           wcscat(PathBuffer, KeyValue);
2148
2149           DPRINT("FullPath: '%S'\n", PathBuffer);
2150
2151           Status = CreateDirectory(PathBuffer);
2152           if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
2153             {
2154               DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
2155               PopupError("Setup could not create install directories.",
2156                          "ENTER = Reboot computer");
2157
2158               while (TRUE)
2159                 {
2160                   ConInKey(Ir);
2161
2162                   if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2163                     {
2164                       return(FALSE);
2165                     }
2166                 }
2167             }
2168         }
2169     }
2170   while (InfFindNextLine (&DirContext, &DirContext));
2171
2172   return(TRUE);
2173 }
2174
2175
2176 static PAGE_NUMBER
2177 PrepareCopyPage(PINPUT_RECORD Ir)
2178 {
2179   INT CabStatus;
2180   HINF InfHandle;
2181   WCHAR PathBuffer[MAX_PATH];
2182   INFCONTEXT CabinetsContext;
2183   ULONG InfFileSize;
2184   PWCHAR KeyValue;
2185   NTSTATUS Status;
2186   ULONG ErrorLine;
2187   PVOID InfFileData;
2188
2189   SetTextXY(6, 8, "Setup prepares your computer for copying the ReactOS files. ");
2190
2191
2192   /*
2193    * Build the file copy list
2194    */
2195   SetStatusText("   Building the file copy list...");
2196
2197   /* Create the file queue */
2198   SetupFileQueue = SetupOpenFileQueue();
2199   if (SetupFileQueue == NULL)
2200     {
2201       PopupError("Setup failed to open the copy file queue.\n",
2202                  "ENTER = Reboot computer");
2203
2204       while(TRUE)
2205         {
2206           ConInKey(Ir);
2207
2208           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2209             {
2210               return(QUIT_PAGE);
2211             }
2212         }
2213     }
2214
2215
2216   if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
2217     {
2218       return(QUIT_PAGE);
2219     }
2220
2221
2222   /* Search for the 'Cabinets' section */
2223   if (!InfFindFirstLine (SetupInf, L"Cabinets", NULL, &CabinetsContext))
2224     {
2225       PopupError("Setup failed to find the 'Cabinets' section\n"
2226                  "in TXTSETUP.SIF.\n",
2227                  "ENTER = Reboot computer");
2228
2229       while(TRUE)
2230         {
2231           ConInKey(Ir);
2232
2233           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2234             {
2235               return(QUIT_PAGE);
2236             }
2237         }
2238     }
2239
2240
2241   /*
2242    * Enumerate the directory values in the 'Cabinets'
2243    * section and parse their inf files.
2244    */
2245   do
2246     {
2247       if (!InfGetData (&CabinetsContext, NULL, &KeyValue))
2248     break;
2249
2250           wcscpy(PathBuffer, SourcePath.Buffer);
2251           wcscat(PathBuffer, L"\\");
2252           wcscat(PathBuffer, KeyValue);
2253
2254     CabinetInitialize();
2255     CabinetSetEventHandlers(NULL, NULL, NULL);
2256     CabinetSetCabinetName(PathBuffer);
2257
2258     if (CabinetOpen() == CAB_STATUS_SUCCESS)
2259       {
2260         DPRINT("Cabinet %S\n", CabinetGetCabinetName());
2261
2262         InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
2263         if (InfFileData == NULL)
2264           {
2265             PopupError("Cabinet has no setup script.\n",
2266                     "ENTER = Reboot computer");
2267
2268             while(TRUE)
2269                 {
2270                   ConInKey(Ir);
2271             
2272                   if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2273                     {
2274                       return(QUIT_PAGE);
2275                     }
2276                 }
2277           }
2278       }
2279     else
2280       {
2281         DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
2282
2283         PopupError("Cabinet not found.\n", "ENTER = Reboot computer");
2284   
2285         while(TRUE)
2286                 {
2287                   ConInKey(Ir);
2288         
2289                   if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2290                     {
2291                       return(QUIT_PAGE);
2292                     }
2293                 }
2294       }
2295
2296     Status = InfOpenBufferedFile(&InfHandle,
2297             InfFileData,
2298       InfFileSize,
2299             &ErrorLine);
2300     if (!NT_SUCCESS(Status))
2301       {
2302         PopupError("Cabinet has no valid inf file.\n",
2303                  "ENTER = Reboot computer");
2304   
2305         while(TRUE)
2306         {
2307           ConInKey(Ir);
2308   
2309           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2310             {
2311               return(QUIT_PAGE);
2312             }
2313         }
2314       }
2315
2316       CabinetCleanup();
2317
2318       if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
2319         {
2320           return(QUIT_PAGE);
2321         }
2322     }
2323   while (InfFindNextLine (&CabinetsContext, &CabinetsContext));
2324
2325   return(FILE_COPY_PAGE);
2326 }
2327
2328
2329 static ULONG
2330 FileCopyCallback(PVOID Context,
2331                  ULONG Notification,
2332                  PVOID Param1,
2333                  PVOID Param2)
2334 {
2335   PCOPYCONTEXT CopyContext;
2336
2337   CopyContext = (PCOPYCONTEXT)Context;
2338
2339   switch (Notification)
2340     {
2341       case SPFILENOTIFY_STARTSUBQUEUE:
2342         CopyContext->TotalOperations = (ULONG)Param2;
2343         ProgressSetStepCount(CopyContext->ProgressBar,
2344                              CopyContext->TotalOperations);
2345         break;
2346
2347       case SPFILENOTIFY_STARTCOPY:
2348         /* Display copy message */
2349         PrintTextXYN(6, 16, 60, "Copying file: %S", (PWSTR)Param1);
2350
2351         PrintTextXYN(6, 18, 60, "File %lu of %lu",
2352                      CopyContext->CompletedOperations + 1,
2353                      CopyContext->TotalOperations);
2354         break;
2355
2356       case SPFILENOTIFY_ENDCOPY:
2357         CopyContext->CompletedOperations++;
2358         ProgressNextStep(CopyContext->ProgressBar);
2359         break;
2360     }
2361
2362   return(0);
2363 }
2364
2365
2366 static PAGE_NUMBER
2367 FileCopyPage(PINPUT_RECORD Ir)
2368 {
2369   COPYCONTEXT CopyContext;
2370   SHORT xScreen;
2371   SHORT yScreen;
2372
2373   SetStatusText("   Please wait...");
2374
2375   SetTextXY(6, 8, "Copying files");
2376
2377   GetScreenSize(&xScreen, &yScreen);
2378
2379   CopyContext.TotalOperations = 0;
2380   CopyContext.CompletedOperations = 0;
2381   CopyContext.ProgressBar = CreateProgressBar(6,
2382                                               yScreen - 14,
2383                                               xScreen - 7,
2384                                               yScreen - 10);
2385
2386   SetupCommitFileQueue(SetupFileQueue,
2387                        DestinationRootPath.Buffer,
2388                        InstallPath.Buffer,
2389                        (PSP_FILE_CALLBACK)FileCopyCallback,
2390                        &CopyContext);
2391
2392   SetupCloseFileQueue(SetupFileQueue);
2393
2394   DestroyProgressBar(CopyContext.ProgressBar);
2395
2396   return(REGISTRY_PAGE);
2397 }
2398
2399
2400 static PAGE_NUMBER
2401 RegistryPage(PINPUT_RECORD Ir)
2402 {
2403   INFCONTEXT InfContext;
2404   NTSTATUS Status;
2405
2406   PWSTR Action;
2407   PWSTR File;
2408   PWSTR Section;
2409   BOOLEAN Delete;
2410
2411
2412   SetTextXY(6, 8, "Setup is updating the system configuration");
2413
2414   SetStatusText("   Creating registry hives...");
2415
2416   if (!SetInstallPathValue(&DestinationPath))
2417     {
2418       DPRINT("SetInstallPathValue() failed\n");
2419       PopupError("Setup failed to set the initialize the registry.",
2420                  "ENTER = Reboot computer");
2421
2422       while(TRUE)
2423         {
2424           ConInKey(Ir);
2425
2426           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2427             {
2428               return(QUIT_PAGE);
2429             }
2430         }
2431     }
2432
2433   /* Create the default hives */
2434   Status = NtInitializeRegistry(TRUE);
2435   if (!NT_SUCCESS(Status))
2436     {
2437       DPRINT("NtInitializeRegistry() failed (Status %lx)\n", Status);
2438       PopupError("Setup failed to create the registry hives.",
2439                  "ENTER = Reboot computer");
2440
2441       while(TRUE)
2442         {
2443           ConInKey(Ir);
2444
2445           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2446             {
2447               return(QUIT_PAGE);
2448             }
2449         }
2450     }
2451
2452   /* Update registry */
2453   SetStatusText("   Updating registry hives...");
2454
2455   if (!InfFindFirstLine(SetupInf, L"HiveInfs.Install", NULL, &InfContext))
2456     {
2457       DPRINT1("InfFindFirstLine() failed\n");
2458       PopupError("Setup failed to find the registry data files.",
2459                  "ENTER = Reboot computer");
2460
2461       while(TRUE)
2462         {
2463           ConInKey(Ir);
2464
2465           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2466             {
2467               return(QUIT_PAGE);
2468             }
2469         }
2470     }
2471
2472   do
2473     {
2474       InfGetDataField (&InfContext, 0, &Action);
2475       InfGetDataField (&InfContext, 1, &File);
2476       InfGetDataField (&InfContext, 2, &Section);
2477
2478       DPRINT1("Action: %S  File: %S  Section %S\n", Action, File, Section);
2479
2480       if (!_wcsicmp (Action, L"AddReg"))
2481         {
2482           Delete = FALSE;
2483         }
2484       else if (!_wcsicmp (Action, L"DelReg"))
2485         {
2486           Delete = TRUE;
2487         }
2488       else
2489         {
2490           continue;
2491         }
2492
2493       SetStatusText("   Importing %S...", File);
2494
2495       if (!ImportRegistryFile(File, Section, Delete))
2496         {
2497           DPRINT1("Importing %S failed\n", File);
2498
2499           PopupError("Setup failed to import a hive file.",
2500                      "ENTER = Reboot computer");
2501
2502           while(TRUE)
2503             {
2504               ConInKey(Ir);
2505
2506               if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
2507                 {
2508                   return(QUIT_PAGE);
2509                 }
2510             }
2511         }
2512     }
2513   while (InfFindNextLine (&InfContext, &InfContext));
2514
2515   SetStatusText("   Done...");
2516
2517   return(BOOT_LOADER_PAGE);
2518 }
2519
2520
2521 static PAGE_NUMBER
2522 BootLoaderPage(PINPUT_RECORD Ir)
2523 {
2524   WCHAR SrcPath[MAX_PATH];
2525   WCHAR DstPath[MAX_PATH];
2526   PINICACHE IniCache;
2527   PINICACHESECTION IniSection;
2528   NTSTATUS Status;
2529
2530   SetTextXY(6, 8, "Installing the boot loader");
2531
2532   SetStatusText("   Please wait...");
2533
2534   if (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED)
2535     {
2536       DPRINT1("Error: active partition invalid (unused)\n");
2537       PopupError("The active partition is unused (invalid).\n",
2538                  "ENTER = Reboot computer");
2539
2540       while(TRUE)
2541         {
2542           ConInKey(Ir);
2543
2544           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2545             {
2546               return(QUIT_PAGE);
2547             }
2548         }
2549     }
2550   if (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == 0x0A)
2551     {
2552       /* OS/2 boot manager partition */
2553       DPRINT1("Found OS/2 boot manager partition\n");
2554       PopupError("Setup found an OS/2 boot manager partiton.\n"
2555                  "The OS/2 boot manager is not supported yet!",
2556                  "ENTER = Reboot computer");
2557
2558       while(TRUE)
2559         {
2560           ConInKey(Ir);
2561
2562           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2563             {
2564               return(QUIT_PAGE);
2565             }
2566         }
2567     }
2568   else if (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == 0x83)
2569     {
2570       /* Linux ext2 partition */
2571       DPRINT1("Found Linux ext2 partition\n");
2572       PopupError("Setup found a Linux ext2 partiton.\n"
2573                  "Linux ext2 partitions are not supported yet!",
2574                  "ENTER = Reboot computer");
2575
2576       while(TRUE)
2577         {
2578           ConInKey(Ir);
2579
2580           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2581             {
2582               return(QUIT_PAGE);
2583             }
2584         }
2585     }
2586   else if (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_IFS)
2587     {
2588       /* NTFS partition */
2589       DPRINT1("Found NTFS partition\n");
2590       PopupError("Setup found an NTFS partiton.\n"
2591                  "NTFS partitions are not supported yet!",
2592                  "ENTER = Reboot computer");
2593
2594       while(TRUE)
2595         {
2596           ConInKey(Ir);
2597
2598           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2599             {
2600               return(QUIT_PAGE);
2601             }
2602         }
2603     }
2604   else if ((PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
2605            (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
2606            (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_HUGE) ||
2607            (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_XINT13) ||
2608            (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT32) ||
2609            (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
2610   {
2611     /* FAT or FAT32 partition */
2612     DPRINT1("System path: '%wZ'\n", &SystemRootPath);
2613
2614     if (DoesFileExist(SystemRootPath.Buffer, L"ntldr") == TRUE ||
2615         DoesFileExist(SystemRootPath.Buffer, L"boot.ini") == TRUE)
2616     {
2617       /* Search root directory for 'ntldr' and 'boot.ini'. */
2618       DPRINT1("Found Microsoft Windows NT/2000/XP boot loader\n");
2619
2620       /* Copy FreeLoader to the boot partition */
2621       wcscpy(SrcPath, SourceRootPath.Buffer);
2622       wcscat(SrcPath, L"\\loader\\freeldr.sys");
2623       wcscpy(DstPath, SystemRootPath.Buffer);
2624       wcscat(DstPath, L"\\freeldr.sys");
2625
2626       DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath);
2627       Status = SetupCopyFile(SrcPath, DstPath);
2628       if (!NT_SUCCESS(Status))
2629       {
2630         DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2631         PopupError("Setup failed to copy 'freeldr.sys'.",
2632                    "ENTER = Reboot computer");
2633
2634         while(TRUE)
2635         {
2636           ConInKey(Ir);
2637
2638           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2639           {
2640             return(QUIT_PAGE);
2641           }
2642         }
2643       }
2644
2645       /* Create or update freeldr.ini */
2646       if (DoesFileExist(SystemRootPath.Buffer, L"freeldr.ini") == FALSE)
2647       {
2648         /* Create new 'freeldr.ini' */
2649         DPRINT1("Create new 'freeldr.ini'\n");
2650         wcscpy(DstPath, SystemRootPath.Buffer);
2651         wcscat(DstPath, L"\\freeldr.ini");
2652
2653         Status = CreateFreeLoaderIniForReactos(DstPath,
2654                                                DestinationArcPath.Buffer);
2655         if (!NT_SUCCESS(Status))
2656         {
2657           DPRINT1("CreateFreeLoaderIniForReactos() failed (Status %lx)\n", Status);
2658           PopupError("Setup failed to create 'freeldr.ini'.",
2659                      "ENTER = Reboot computer");
2660
2661           while(TRUE)
2662           {
2663             ConInKey(Ir);
2664
2665             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
2666             {
2667               return(QUIT_PAGE);
2668             }
2669           }
2670         }
2671
2672         /* Install new bootcode */
2673         if ((PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT32) ||
2674             (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
2675         {
2676           /* Install FAT32 bootcode */
2677           wcscpy(SrcPath, SourceRootPath.Buffer);
2678           wcscat(SrcPath, L"\\loader\\fat32.bin");
2679           wcscpy(DstPath, SystemRootPath.Buffer);
2680           wcscat(DstPath, L"\\bootsect.ros");
2681
2682           DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, DstPath);
2683           Status = InstallFat32BootCodeToFile(SrcPath,
2684                                               DstPath,
2685                                               SystemRootPath.Buffer);
2686           if (!NT_SUCCESS(Status))
2687           {
2688             DPRINT1("InstallFat32BootCodeToFile() failed (Status %lx)\n", Status);
2689             PopupError("Setup failed to install the FAT32 bootcode.",
2690                        "ENTER = Reboot computer");
2691
2692             while(TRUE)
2693             {
2694               ConInKey(Ir);
2695
2696               if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
2697               {
2698                 return(QUIT_PAGE);
2699               }
2700             }
2701           }
2702         }
2703         else
2704         {
2705           /* Install FAT16 bootcode */
2706           wcscpy(SrcPath, SourceRootPath.Buffer);
2707           wcscat(SrcPath, L"\\loader\\fat.bin");
2708           wcscpy(DstPath, SystemRootPath.Buffer);
2709           wcscat(DstPath, L"\\bootsect.ros");
2710
2711           DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, DstPath);
2712           Status = InstallFat16BootCodeToFile(SrcPath,
2713                                               DstPath,
2714                                               SystemRootPath.Buffer);
2715           if (!NT_SUCCESS(Status))
2716           {
2717             DPRINT1("InstallFat16BootCodeToFile() failed (Status %lx)\n", Status);
2718             PopupError("Setup failed to install the FAT bootcode.",
2719                        "ENTER = Reboot computer");
2720
2721             while(TRUE)
2722             {
2723               ConInKey(Ir);
2724
2725               if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
2726               {
2727                 return(QUIT_PAGE);
2728               }
2729             }
2730           }
2731         }
2732
2733         /* Update 'boot.ini' */
2734         wcscpy(DstPath, SystemRootPath.Buffer);
2735         wcscat(DstPath, L"\\boot.ini");
2736
2737         DPRINT1("Update 'boot.ini': %S\n", DstPath);
2738         Status = UpdateBootIni(DstPath,
2739                                L"C:\\bootsect.ros",
2740                                L"\"ReactOS\"");
2741         if (!NT_SUCCESS(Status))
2742         {
2743           DPRINT1("UpdateBootIni() failed (Status %lx)\n", Status);
2744           PopupError("Setup failed to update \'boot.ini\'.",
2745                      "ENTER = Reboot computer");
2746
2747           while(TRUE)
2748           {
2749             ConInKey(Ir);
2750
2751             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
2752             {
2753               return(QUIT_PAGE);
2754             }
2755           }
2756         }
2757       }
2758       else
2759       {
2760         /* Update existing 'freeldr.ini' */
2761         DPRINT1("Update existing 'freeldr.ini'\n");
2762         wcscpy(DstPath, SystemRootPath.Buffer);
2763         wcscat(DstPath, L"\\freeldr.ini");
2764
2765         Status = UpdateFreeLoaderIni(DstPath,
2766                                      DestinationArcPath.Buffer);
2767         if (!NT_SUCCESS(Status))
2768         {
2769           DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
2770           PopupError("Setup failed to update 'freeldr.ini'.",
2771                      "ENTER = Reboot computer");
2772
2773           while(TRUE)
2774           {
2775             ConInKey(Ir);
2776
2777             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
2778             {
2779               return(QUIT_PAGE);
2780             }
2781           }
2782         }
2783       }
2784     }
2785     else if (DoesFileExist(SystemRootPath.Buffer, L"io.sys") == TRUE ||
2786              DoesFileExist(SystemRootPath.Buffer, L"msdos.sys") == TRUE)
2787     {
2788       /* Search for root directory for 'io.sys' and 'msdos.sys'. */
2789       DPRINT1("Found Microsoft DOS or Windows 9x boot loader\n");
2790
2791       /* Copy FreeLoader to the boot partition */
2792       wcscpy(SrcPath, SourceRootPath.Buffer);
2793       wcscat(SrcPath, L"\\loader\\freeldr.sys");
2794       wcscpy(DstPath, SystemRootPath.Buffer);
2795       wcscat(DstPath, L"\\freeldr.sys");
2796
2797       DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
2798       Status = SetupCopyFile(SrcPath, DstPath);
2799       if (!NT_SUCCESS(Status))
2800       {
2801         DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2802         PopupError("Setup failed to copy 'freeldr.sys'.",
2803                    "ENTER = Reboot computer");
2804
2805         while(TRUE)
2806         {
2807           ConInKey(Ir);
2808
2809           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2810           {
2811             return(QUIT_PAGE);
2812           }
2813         }
2814       }
2815
2816       /* Create or update 'freeldr.ini' */
2817       if (DoesFileExist(SystemRootPath.Buffer, L"freeldr.ini") == FALSE)
2818       {
2819         /* Create new 'freeldr.ini' */
2820         DPRINT1("Create new 'freeldr.ini'\n");
2821         wcscpy(DstPath, SystemRootPath.Buffer);
2822         wcscat(DstPath, L"\\freeldr.ini");
2823
2824         Status = CreateFreeLoaderIniForDos(DstPath,
2825                                            DestinationArcPath.Buffer);
2826         if (!NT_SUCCESS(Status))
2827         {
2828           DPRINT1("CreateFreeLoaderIniForDos() failed (Status %lx)\n", Status);
2829           PopupError("Setup failed to create 'freeldr.ini'.",
2830                      "ENTER = Reboot computer");
2831
2832           while(TRUE)
2833           {
2834             ConInKey(Ir);
2835
2836             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
2837             {
2838               return(QUIT_PAGE);
2839             }
2840           }
2841         }
2842
2843         /* Save current bootsector as 'BOOTSECT.DOS' */
2844         wcscpy(SrcPath, SystemRootPath.Buffer);
2845         wcscpy(DstPath, SystemRootPath.Buffer);
2846         wcscat(DstPath, L"\\bootsect.dos");
2847
2848         DPRINT1("Save bootsector: %S ==> %S\n", SrcPath, DstPath);
2849         Status = SaveCurrentBootSector(SrcPath,
2850                                        DstPath);
2851         if (!NT_SUCCESS(Status))
2852         {
2853           DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status);
2854           PopupError("Setup failed to save the current bootsector.",
2855                      "ENTER = Reboot computer");
2856
2857           while(TRUE)
2858           {
2859             ConInKey(Ir);
2860
2861             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
2862             {
2863               return(QUIT_PAGE);
2864             }
2865           }
2866         }
2867
2868         /* Install new bootsector */
2869         if ((PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT32) ||
2870             (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
2871         {
2872           wcscpy(SrcPath, SourceRootPath.Buffer);
2873           wcscat(SrcPath, L"\\loader\\fat32.bin");
2874
2875           DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
2876           Status = InstallFat32BootCodeToDisk(SrcPath,
2877                                               SystemRootPath.Buffer);
2878           if (!NT_SUCCESS(Status))
2879           {
2880             DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
2881             PopupError("Setup failed to install the FAT32 bootcode.",
2882                        "ENTER = Reboot computer");
2883
2884             while(TRUE)
2885             {
2886               ConInKey(Ir);
2887
2888               if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
2889               {
2890                 return(QUIT_PAGE);
2891               }
2892             }
2893           }
2894         }
2895         else
2896         {
2897           wcscpy(SrcPath, SourceRootPath.Buffer);
2898           wcscat(SrcPath, L"\\loader\\fat.bin");
2899
2900           DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
2901           Status = InstallFat16BootCodeToDisk(SrcPath,
2902                                               SystemRootPath.Buffer);
2903           if (!NT_SUCCESS(Status))
2904           {
2905             DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
2906             PopupError("Setup failed to install the FAT bootcode.",
2907                        "ENTER = Reboot computer");
2908
2909             while(TRUE)
2910             {
2911               ConInKey(Ir);
2912
2913               if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
2914               {
2915                 return(QUIT_PAGE);
2916               }
2917             }
2918           }
2919         }
2920       }
2921       else
2922       {
2923         /* Update existing 'freeldr.ini' */
2924         wcscpy(DstPath, SystemRootPath.Buffer);
2925         wcscat(DstPath, L"\\freeldr.ini");
2926
2927         Status = UpdateFreeLoaderIni(DstPath,
2928                                      DestinationArcPath.Buffer);
2929         if (!NT_SUCCESS(Status))
2930         {
2931           DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
2932           PopupError("Setup failed to update 'freeldr.ini'.",
2933                      "ENTER = Reboot computer");
2934
2935           while(TRUE)
2936           {
2937             ConInKey(Ir);
2938
2939             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
2940             {
2941               return(QUIT_PAGE);
2942             }
2943           }
2944         }
2945       }
2946     }
2947     else
2948     {
2949       /* No or unknown boot loader */
2950       DPRINT1("No or unknown boot loader found\n");
2951
2952       /* Copy FreeLoader to the boot partition */
2953       wcscpy(SrcPath, SourceRootPath.Buffer);
2954       wcscat(SrcPath, L"\\loader\\freeldr.sys");
2955       wcscpy(DstPath, SystemRootPath.Buffer);
2956       wcscat(DstPath, L"\\freeldr.sys");
2957
2958       DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath);
2959       Status = SetupCopyFile(SrcPath, DstPath);
2960       if (!NT_SUCCESS(Status))
2961       {
2962         DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
2963         PopupError("Setup failed to copy 'freeldr.sys'.",
2964                    "ENTER = Reboot computer");
2965
2966         while(TRUE)
2967         {
2968           ConInKey(Ir);
2969
2970           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
2971           {
2972             return(QUIT_PAGE);
2973           }
2974         }
2975       }
2976
2977       /* Create or update 'freeldr.ini' */
2978       if (DoesFileExist(SystemRootPath.Buffer, L"freeldr.ini") == FALSE)
2979       {
2980         /* Create new freeldr.ini */
2981         wcscpy(DstPath, SystemRootPath.Buffer);
2982         wcscat(DstPath, L"\\freeldr.ini");
2983
2984         DPRINT1("Copy: %S ==> %S\n", SrcPath, DstPath);
2985         Status = CreateFreeLoaderIniForReactos(DstPath,
2986                                                DestinationArcPath.Buffer);
2987         if (!NT_SUCCESS(Status))
2988         {
2989           DPRINT1("CreateFreeLoaderIniForReactos() failed (Status %lx)\n", Status);
2990           PopupError("Setup failed to create \'freeldr.ini\'.",
2991                      "ENTER = Reboot computer");
2992
2993           while(TRUE)
2994           {
2995             ConInKey(Ir);
2996
2997             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
2998             {
2999               return(QUIT_PAGE);
3000             }
3001           }
3002         }
3003
3004         /* Save current bootsector as 'BOOTSECT.OLD' */
3005         wcscpy(SrcPath, SystemRootPath.Buffer);
3006         wcscpy(DstPath, SystemRootPath.Buffer);
3007         wcscat(DstPath, L"\\bootsect.old");
3008
3009         DPRINT1("Save bootsector: %S ==> %S\n", SrcPath, DstPath);
3010         Status = SaveCurrentBootSector(SrcPath,
3011                                        DstPath);
3012         if (!NT_SUCCESS(Status))
3013         {
3014           DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status);
3015           PopupError("Setup failed save the current bootsector.",
3016                      "ENTER = Reboot computer");
3017
3018           while(TRUE)
3019           {
3020             ConInKey(Ir);
3021
3022             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
3023             {
3024               return(QUIT_PAGE);
3025             }
3026           }
3027         }
3028
3029         /* Install new bootsector */
3030         if ((PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT32) ||
3031             (PartitionList->ActiveBootPartition->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
3032         {
3033           wcscpy(SrcPath, SourceRootPath.Buffer);
3034           wcscat(SrcPath, L"\\loader\\fat32.bin");
3035
3036           DPRINT1("Install FAT32 bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
3037           Status = InstallFat32BootCodeToDisk(SrcPath,
3038                                               SystemRootPath.Buffer);
3039           if (!NT_SUCCESS(Status))
3040           {
3041             DPRINT1("InstallFat32BootCodeToDisk() failed (Status %lx)\n", Status);
3042             PopupError("Setup failed to install the FAT32 bootcode.",
3043                        "ENTER = Reboot computer");
3044
3045             while(TRUE)
3046             {
3047               ConInKey(Ir);
3048
3049               if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
3050               {
3051                 return(QUIT_PAGE);
3052               }
3053             }
3054           }
3055         }
3056         else
3057         {
3058           wcscpy(SrcPath, SourceRootPath.Buffer);
3059           wcscat(SrcPath, L"\\loader\\fat.bin");
3060
3061           DPRINT1("Install FAT bootcode: %S ==> %S\n", SrcPath, SystemRootPath.Buffer);
3062           Status = InstallFat16BootCodeToDisk(SrcPath,
3063                                               SystemRootPath.Buffer);
3064           if (!NT_SUCCESS(Status))
3065           {
3066             DPRINT1("InstallFat16BootCodeToDisk() failed (Status %lx)\n", Status);
3067             PopupError("Setup failed to install the FAT bootcode.",
3068                        "ENTER = Reboot computer");
3069
3070             while(TRUE)
3071             {
3072               ConInKey(Ir);
3073
3074               if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)   /* ENTER */
3075               {
3076                 return(QUIT_PAGE);
3077               }
3078             }
3079           }
3080         }
3081       }
3082       else
3083       {
3084         /* Update existing 'freeldr.ini' */
3085         wcscpy(DstPath, SystemRootPath.Buffer);
3086         wcscat(DstPath, L"\\freeldr.ini");
3087
3088         Status = UpdateFreeLoaderIni(DstPath,
3089                                      DestinationArcPath.Buffer);
3090         if (!NT_SUCCESS(Status))
3091         {
3092           DPRINT1("UpdateFreeLoaderIni() failed (Status %lx)\n", Status);
3093           PopupError("Setup failed to update 'freeldr.ini'.",
3094                      "ENTER = Reboot computer");
3095
3096           while(TRUE)
3097           {
3098             ConInKey(Ir);
3099
3100             if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)     /* ENTER */
3101             {
3102               return(QUIT_PAGE);
3103             }
3104           }
3105         }
3106       }
3107     }
3108   }
3109   else
3110     {
3111       /* Unknown partition */
3112       DPRINT1("Unknown partition found\n");
3113       PopupError("Setup found an unknown partiton type.\n"
3114                  "This partition type is not supported!",
3115                  "ENTER = Reboot computer");
3116
3117       while(TRUE)
3118         {
3119           ConInKey(Ir);
3120
3121           if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)       /* ENTER */
3122             {
3123               return(QUIT_PAGE);
3124             }
3125         }
3126     }
3127
3128   return(SUCCESS_PAGE);
3129 }
3130
3131
3132
3133 static PAGE_NUMBER
3134 QuitPage(PINPUT_RECORD Ir)
3135 {
3136   SetTextXY(10, 6, "ReactOS is not completely installed");
3137
3138   SetTextXY(10, 8, "Remove floppy disk from Drive A: and");
3139   SetTextXY(10, 9, "all CD-ROMs from CD-Drives.");
3140
3141   SetTextXY(10, 11, "Press ENTER to reboot your computer.");
3142
3143   SetStatusText("   Please wait ...");
3144
3145   /* Destroy partition list */
3146   if (PartitionList != NULL)
3147     {
3148       DestroyPartitionList (PartitionList);
3149       PartitionList = NULL;
3150     }
3151
3152   /* Destroy filesystem list */
3153   if (FileSystemList != NULL)
3154     {
3155       DestroyFileSystemList (FileSystemList);
3156       FileSystemList = NULL;
3157     }
3158
3159   SetStatusText("   ENTER = Reboot computer");
3160
3161   while(TRUE)
3162     {
3163       ConInKey(Ir);
3164
3165       if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3166         {
3167           return(REBOOT_PAGE);
3168         }
3169     }
3170 }
3171
3172
3173 static PAGE_NUMBER
3174 SuccessPage(PINPUT_RECORD Ir)
3175 {
3176   SetTextXY(10, 6, "The basic components of ReactOS have been installed successfully.");
3177
3178   SetTextXY(10, 8, "Remove floppy disk from Drive A: and");
3179   SetTextXY(10, 9, "all CD-ROMs from CD-Drive.");
3180
3181   SetTextXY(10, 11, "Press ENTER to reboot your computer.");
3182
3183   SetStatusText("   ENTER = Reboot computer");
3184
3185   while(TRUE)
3186     {
3187       ConInKey(Ir);
3188
3189       if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3190         {
3191           return(REBOOT_PAGE);
3192         }
3193     }
3194 }
3195
3196
3197 VOID STDCALL
3198 NtProcessStartup(PPEB Peb)
3199 {
3200   NTSTATUS Status;
3201   INPUT_RECORD Ir;
3202   PAGE_NUMBER Page;
3203
3204   RtlNormalizeProcessParams(Peb->ProcessParameters);
3205
3206   ProcessHeap = Peb->ProcessHeap;
3207
3208   Status = AllocConsole();
3209   if (!NT_SUCCESS(Status))
3210     {
3211       PrintString("AllocConsole() failed (Status = 0x%08lx)\n", Status);
3212
3213       /* Raise a hard error (crash the system/BSOD) */
3214       NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
3215                        0,0,0,0,0);
3216     }
3217
3218
3219   /* Initialize global unicode strings */
3220   RtlInitUnicodeString(&SourcePath, NULL);
3221   RtlInitUnicodeString(&SourceRootPath, NULL);
3222   RtlInitUnicodeString(&InstallPath, NULL);
3223   RtlInitUnicodeString(&DestinationPath, NULL);
3224   RtlInitUnicodeString(&DestinationArcPath, NULL);
3225   RtlInitUnicodeString(&DestinationRootPath, NULL);
3226   RtlInitUnicodeString(&SystemRootPath, NULL);
3227
3228
3229   Page = START_PAGE;
3230   while (Page != REBOOT_PAGE)
3231     {
3232       ClearScreen();
3233
3234       SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
3235
3236       switch (Page)
3237         {
3238           /* Start page */
3239           case START_PAGE:
3240             Page = StartPage(&Ir);
3241             break;
3242
3243           /* Intro page */
3244           case INTRO_PAGE:
3245             Page = IntroPage(&Ir);
3246             break;
3247
3248           /* Install pages */
3249           case INSTALL_INTRO_PAGE:
3250             Page = InstallIntroPage(&Ir);
3251             break;
3252
3253 #if 0
3254           case OEM_DRIVER_PAGE:
3255             Page = OemDriverPage(&Ir);
3256             break;
3257 #endif
3258
3259 #if 0
3260           case DEVICE_SETTINGS_PAGE:
3261 #endif
3262
3263           case SELECT_PARTITION_PAGE:
3264             Page = SelectPartitionPage(&Ir);
3265             break;
3266
3267           case CREATE_PARTITION_PAGE:
3268             Page = CreatePartitionPage(&Ir);
3269             break;
3270
3271           case DELETE_PARTITION_PAGE:
3272             Page = DeletePartitionPage(&Ir);
3273             break;
3274
3275           case SELECT_FILE_SYSTEM_PAGE:
3276             Page = SelectFileSystemPage(&Ir);
3277             break;
3278
3279           case FORMAT_PARTITION_PAGE:
3280             Page = FormatPartitionPage(&Ir);
3281             break;
3282
3283           case CHECK_FILE_SYSTEM_PAGE:
3284             Page = CheckFileSystemPage(&Ir);
3285             break;
3286
3287           case INSTALL_DIRECTORY_PAGE:
3288             Page = InstallDirectoryPage(&Ir);
3289             break;
3290
3291           case PREPARE_COPY_PAGE:
3292             Page = PrepareCopyPage(&Ir);
3293             break;
3294
3295           case FILE_COPY_PAGE:
3296             Page = FileCopyPage(&Ir);
3297             break;
3298
3299           case REGISTRY_PAGE:
3300             Page = RegistryPage(&Ir);
3301             break;
3302
3303           case BOOT_LOADER_PAGE:
3304             Page = BootLoaderPage(&Ir);
3305             break;
3306
3307
3308           /* Repair pages */
3309           case REPAIR_INTRO_PAGE:
3310             Page = RepairIntroPage(&Ir);
3311             break;
3312
3313
3314           /* Emergency pages */
3315           case EMERGENCY_INTRO_PAGE:
3316             Page = EmergencyIntroPage(&Ir);
3317             break;
3318
3319
3320           case SUCCESS_PAGE:
3321             Page = SuccessPage(&Ir);
3322             break;
3323
3324           case QUIT_PAGE:
3325             Page = QuitPage(&Ir);
3326             break;
3327         }
3328     }
3329
3330   /* Reboot */
3331   FreeConsole();
3332   NtShutdownSystem(ShutdownReboot);
3333 }
3334
3335 /* EOF */