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