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