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