239fd3465ced293a5beab2d51a8adb636c502e89
[reactos.git] / base / setup / usetup / usetup.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004 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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/usetup.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
26 */
27
28 #include <usetup.h>
29 #include <math.h>
30 #include <ntstrsafe.h>
31
32 #include "bootsup.h"
33 #include "chkdsk.h"
34 #include "cmdcons.h"
35 #include "devinst.h"
36 #include "format.h"
37
38 #define NDEBUG
39 #include <debug.h>
40
41
42 /* GLOBALS & LOCALS *********************************************************/
43
44 HANDLE ProcessHeap;
45 BOOLEAN IsUnattendedSetup = FALSE;
46
47 static USETUP_DATA USetupData;
48
49 /* Partition where to perform the installation */
50 static PPARTENTRY InstallPartition = NULL;
51 // static PPARTENTRY SystemPartition = NULL; // The system partition we will actually use (can be different from PartitionList->SystemPartition in case we install on removable disk)
52
53 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
54 static WCHAR DestinationDriveLetter;
55
56
57 /* OTHER Stuff *****/
58
59 PCWSTR SelectedLanguageId;
60 static WCHAR DefaultLanguage[20]; // Copy of string inside LanguageList
61 static WCHAR DefaultKBLayout[20]; // Copy of string inside KeyboardList
62
63 static BOOLEAN RepairUpdateFlag = FALSE;
64
65 /* Global partition list on the system */
66 static PPARTLIST PartitionList = NULL;
67
68 /* Currently selected partition entry in the list */
69 static PPARTENTRY CurrentPartition = NULL;
70
71 /* List of supported file systems for the partition to be formatted */
72 static PFILE_SYSTEM_LIST FileSystemList = NULL;
73
74 /* Machine state for the formatter */
75 static PPARTENTRY TempPartition = NULL;
76 static FORMATMACHINESTATE FormatState = Start;
77
78 /*****************************************************/
79
80 static PNTOS_INSTALLATION CurrentInstallation = NULL;
81 static PGENERIC_LIST NtOsInstallsList = NULL;
82
83
84 /* FUNCTIONS ****************************************************************/
85
86 static VOID
87 PrintString(char* fmt,...)
88 {
89 char buffer[512];
90 va_list ap;
91 UNICODE_STRING UnicodeString;
92 ANSI_STRING AnsiString;
93
94 va_start(ap, fmt);
95 vsprintf(buffer, fmt, ap);
96 va_end(ap);
97
98 RtlInitAnsiString(&AnsiString, buffer);
99 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
100 NtDisplayString(&UnicodeString);
101 RtlFreeUnicodeString(&UnicodeString);
102 }
103
104
105 static VOID
106 DrawBox(IN SHORT xLeft,
107 IN SHORT yTop,
108 IN SHORT Width,
109 IN SHORT Height)
110 {
111 COORD coPos;
112 DWORD Written;
113
114 /* Draw upper left corner */
115 coPos.X = xLeft;
116 coPos.Y = yTop;
117 FillConsoleOutputCharacterA(StdOutput,
118 0xDA, // '+',
119 1,
120 coPos,
121 &Written);
122
123 /* Draw upper edge */
124 coPos.X = xLeft + 1;
125 coPos.Y = yTop;
126 FillConsoleOutputCharacterA(StdOutput,
127 0xC4, // '-',
128 Width - 2,
129 coPos,
130 &Written);
131
132 /* Draw upper right corner */
133 coPos.X = xLeft + Width - 1;
134 coPos.Y = yTop;
135 FillConsoleOutputCharacterA(StdOutput,
136 0xBF, // '+',
137 1,
138 coPos,
139 &Written);
140
141 /* Draw right edge, inner space and left edge */
142 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
143 {
144 coPos.X = xLeft;
145 FillConsoleOutputCharacterA(StdOutput,
146 0xB3, // '|',
147 1,
148 coPos,
149 &Written);
150
151 coPos.X = xLeft + 1;
152 FillConsoleOutputCharacterA(StdOutput,
153 ' ',
154 Width - 2,
155 coPos,
156 &Written);
157
158 coPos.X = xLeft + Width - 1;
159 FillConsoleOutputCharacterA(StdOutput,
160 0xB3, // '|',
161 1,
162 coPos,
163 &Written);
164 }
165
166 /* Draw lower left corner */
167 coPos.X = xLeft;
168 coPos.Y = yTop + Height - 1;
169 FillConsoleOutputCharacterA(StdOutput,
170 0xC0, // '+',
171 1,
172 coPos,
173 &Written);
174
175 /* Draw lower edge */
176 coPos.X = xLeft + 1;
177 coPos.Y = yTop + Height - 1;
178 FillConsoleOutputCharacterA(StdOutput,
179 0xC4, // '-',
180 Width - 2,
181 coPos,
182 &Written);
183
184 /* Draw lower right corner */
185 coPos.X = xLeft + Width - 1;
186 coPos.Y = yTop + Height - 1;
187 FillConsoleOutputCharacterA(StdOutput,
188 0xD9, // '+',
189 1,
190 coPos,
191 &Written);
192 }
193
194
195 VOID
196 PopupError(PCCH Text,
197 PCCH Status,
198 PINPUT_RECORD Ir,
199 ULONG WaitEvent)
200 {
201 SHORT yTop;
202 SHORT xLeft;
203 COORD coPos;
204 DWORD Written;
205 ULONG Length;
206 ULONG MaxLength;
207 ULONG Lines;
208 PCHAR p;
209 PCCH pnext;
210 BOOLEAN LastLine;
211 SHORT Width;
212 SHORT Height;
213
214 /* Count text lines and longest line */
215 MaxLength = 0;
216 Lines = 0;
217 pnext = Text;
218
219 while (TRUE)
220 {
221 p = strchr(pnext, '\n');
222
223 if (p == NULL)
224 {
225 Length = strlen(pnext);
226 LastLine = TRUE;
227 }
228 else
229 {
230 Length = (ULONG)(p - pnext);
231 LastLine = FALSE;
232 }
233
234 Lines++;
235
236 if (Length > MaxLength)
237 MaxLength = Length;
238
239 if (LastLine)
240 break;
241
242 pnext = p + 1;
243 }
244
245 /* Check length of status line */
246 if (Status != NULL)
247 {
248 Length = strlen(Status);
249
250 if (Length > MaxLength)
251 MaxLength = Length;
252 }
253
254 Width = MaxLength + 4;
255 Height = Lines + 2;
256
257 if (Status != NULL)
258 Height += 2;
259
260 yTop = (yScreen - Height) / 2;
261 xLeft = (xScreen - Width) / 2;
262
263
264 /* Set screen attributes */
265 coPos.X = xLeft;
266 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
267 {
268 FillConsoleOutputAttribute(StdOutput,
269 FOREGROUND_RED | BACKGROUND_WHITE,
270 Width,
271 coPos,
272 &Written);
273 }
274
275 DrawBox(xLeft, yTop, Width, Height);
276
277 /* Print message text */
278 coPos.Y = yTop + 1;
279 pnext = Text;
280 while (TRUE)
281 {
282 p = strchr(pnext, '\n');
283
284 if (p == NULL)
285 {
286 Length = strlen(pnext);
287 LastLine = TRUE;
288 }
289 else
290 {
291 Length = (ULONG)(p - pnext);
292 LastLine = FALSE;
293 }
294
295 if (Length != 0)
296 {
297 coPos.X = xLeft + 2;
298 WriteConsoleOutputCharacterA(StdOutput,
299 pnext,
300 Length,
301 coPos,
302 &Written);
303 }
304
305 if (LastLine)
306 break;
307
308 coPos.Y++;
309 pnext = p + 1;
310 }
311
312 /* Print separator line and status text */
313 if (Status != NULL)
314 {
315 coPos.Y = yTop + Height - 3;
316 coPos.X = xLeft;
317 FillConsoleOutputCharacterA(StdOutput,
318 0xC3, // '+',
319 1,
320 coPos,
321 &Written);
322
323 coPos.X = xLeft + 1;
324 FillConsoleOutputCharacterA(StdOutput,
325 0xC4, // '-',
326 Width - 2,
327 coPos,
328 &Written);
329
330 coPos.X = xLeft + Width - 1;
331 FillConsoleOutputCharacterA(StdOutput,
332 0xB4, // '+',
333 1,
334 coPos,
335 &Written);
336
337 coPos.Y++;
338 coPos.X = xLeft + 2;
339 WriteConsoleOutputCharacterA(StdOutput,
340 Status,
341 min(strlen(Status), (SIZE_T)Width - 4),
342 coPos,
343 &Written);
344 }
345
346 if (WaitEvent == POPUP_WAIT_NONE)
347 return;
348
349 while (TRUE)
350 {
351 CONSOLE_ConInKey(Ir);
352
353 if (WaitEvent == POPUP_WAIT_ANY_KEY ||
354 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
355 {
356 return;
357 }
358 }
359 }
360
361
362 /*
363 * Confirm quit setup
364 * RETURNS
365 * TRUE: Quit setup.
366 * FALSE: Don't quit setup.
367 */
368 static BOOL
369 ConfirmQuit(PINPUT_RECORD Ir)
370 {
371 BOOL Result = FALSE;
372 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE);
373
374 while (TRUE)
375 {
376 CONSOLE_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 static VOID
396 UpdateKBLayout(VOID)
397 {
398 PGENERIC_LIST_ENTRY ListEntry;
399 PCWSTR pszNewLayout;
400
401 pszNewLayout = MUIDefaultKeyboardLayout(SelectedLanguageId);
402
403 if (USetupData.LayoutList == NULL)
404 {
405 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
406 if (USetupData.LayoutList == NULL)
407 {
408 /* FIXME: Handle error! */
409 return;
410 }
411 }
412
413 /* Search for default layout (if provided) */
414 if (pszNewLayout != NULL)
415 {
416 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
417 ListEntry = GetNextListEntry(ListEntry))
418 {
419 if (!wcscmp(pszNewLayout, ((PGENENTRY)GetListEntryData(ListEntry))->Id))
420 {
421 SetCurrentListEntry(USetupData.LayoutList, ListEntry);
422 break;
423 }
424 }
425 }
426 }
427
428
429 static NTSTATUS
430 NTAPI
431 GetSettingDescription(
432 IN PGENERIC_LIST_ENTRY Entry,
433 OUT PSTR Buffer,
434 IN SIZE_T cchBufferSize)
435 {
436 return RtlStringCchPrintfA(Buffer, cchBufferSize, "%S",
437 ((PGENENTRY)GetListEntryData(Entry))->Value);
438 }
439
440 static NTSTATUS
441 NTAPI
442 GetNTOSInstallationName(
443 IN PGENERIC_LIST_ENTRY Entry,
444 OUT PSTR Buffer,
445 IN SIZE_T cchBufferSize)
446 {
447 PNTOS_INSTALLATION NtOsInstall = (PNTOS_INSTALLATION)GetListEntryData(Entry);
448 PPARTENTRY PartEntry = NtOsInstall->PartEntry;
449
450 if (PartEntry && PartEntry->DriveLetter)
451 {
452 /* We have retrieved a partition that is mounted */
453 return RtlStringCchPrintfA(Buffer, cchBufferSize,
454 "%C:%S \"%S\"",
455 PartEntry->DriveLetter,
456 NtOsInstall->PathComponent,
457 NtOsInstall->InstallationName);
458 }
459 else
460 {
461 /* We failed somewhere, just show the NT path */
462 return RtlStringCchPrintfA(Buffer, cchBufferSize,
463 "%wZ \"%S\"",
464 &NtOsInstall->SystemNtPath,
465 NtOsInstall->InstallationName);
466 }
467 }
468
469
470 /*
471 * Displays the LanguagePage.
472 *
473 * Next pages: WelcomePage, QuitPage
474 *
475 * SIDEEFFECTS
476 * Init SelectedLanguageId
477 * Init USetupData.LanguageId
478 *
479 * RETURNS
480 * Number of the next page.
481 */
482 static PAGE_NUMBER
483 LanguagePage(PINPUT_RECORD Ir)
484 {
485 GENERIC_LIST_UI ListUi;
486 PCWSTR NewLanguageId;
487 BOOL RefreshPage = FALSE;
488
489 /* Initialize the computer settings list */
490 if (USetupData.LanguageList == NULL)
491 {
492 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
493 if (USetupData.LanguageList == NULL)
494 {
495 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
496 return WELCOME_PAGE;
497 }
498 }
499
500 SelectedLanguageId = DefaultLanguage;
501 USetupData.LanguageId = 0;
502
503 /* Load the font */
504 SetConsoleCodePage();
505 UpdateKBLayout();
506
507 /*
508 * If there is no language or just a single one in the list,
509 * skip the language selection process altogether.
510 */
511 if (GetNumberOfListEntries(USetupData.LanguageList) <= 1)
512 {
513 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
514 return WELCOME_PAGE;
515 }
516
517 InitGenericListUi(&ListUi, USetupData.LanguageList, GetSettingDescription);
518 DrawGenericList(&ListUi,
519 2, 18,
520 xScreen - 3,
521 yScreen - 3);
522
523 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex());
524
525 MUIDisplayPage(LANGUAGE_PAGE);
526
527 while (TRUE)
528 {
529 CONSOLE_ConInKey(Ir);
530
531 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
532 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
533 {
534 ScrollDownGenericList(&ListUi);
535 RefreshPage = TRUE;
536 }
537 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
538 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
539 {
540 ScrollUpGenericList(&ListUi);
541 RefreshPage = TRUE;
542 }
543 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
544 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
545 {
546 ScrollPageDownGenericList(&ListUi);
547 RefreshPage = TRUE;
548 }
549 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
550 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
551 {
552 ScrollPageUpGenericList(&ListUi);
553 RefreshPage = TRUE;
554 }
555 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
556 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
557 {
558 if (ConfirmQuit(Ir))
559 return QUIT_PAGE;
560 else
561 RedrawGenericList(&ListUi);
562 }
563 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
564 {
565 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
566
567 SelectedLanguageId =
568 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
569
570 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
571
572 if (wcscmp(SelectedLanguageId, DefaultLanguage))
573 {
574 UpdateKBLayout();
575 }
576
577 /* Load the font */
578 SetConsoleCodePage();
579
580 return WELCOME_PAGE;
581 }
582 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
583 {
584 /* a-z */
585 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
586 RefreshPage = TRUE;
587 }
588
589 if (RefreshPage)
590 {
591 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
592
593 NewLanguageId =
594 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
595
596 if (wcscmp(SelectedLanguageId, NewLanguageId))
597 {
598 /* Clear the language page */
599 MUIClearPage(LANGUAGE_PAGE);
600
601 SelectedLanguageId = NewLanguageId;
602
603 /* Load the font */
604 SetConsoleCodePage();
605
606 /* Redraw language selection page in native language */
607 MUIDisplayPage(LANGUAGE_PAGE);
608 }
609
610 RefreshPage = FALSE;
611 }
612 }
613
614 return WELCOME_PAGE;
615 }
616
617
618 /*
619 * Start page
620 *
621 * Next pages:
622 * LanguagePage (at once, default)
623 * InstallIntroPage (at once, if unattended)
624 * QuitPage
625 *
626 * SIDEEFFECTS
627 * Init Sdi
628 * Init USetupData.SourcePath
629 * Init USetupData.SourceRootPath
630 * Init USetupData.SourceRootDir
631 * Init USetupData.SetupInf
632 * Init USetupData.RequiredPartitionDiskSpace
633 * Init IsUnattendedSetup
634 * If unattended, init *List and sets the Codepage
635 * If unattended, init SelectedLanguageId
636 * If unattended, init USetupData.LanguageId
637 *
638 * RETURNS
639 * Number of the next page.
640 */
641 static PAGE_NUMBER
642 SetupStartPage(PINPUT_RECORD Ir)
643 {
644 ULONG Error;
645 PGENERIC_LIST_ENTRY ListEntry;
646 PCWSTR LocaleId;
647
648 MUIDisplayPage(SETUP_INIT_PAGE);
649
650 /* Initialize Setup, phase 1 */
651 Error = InitializeSetup(&USetupData, 1);
652 if (Error != ERROR_SUCCESS)
653 {
654 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
655 return QUIT_PAGE;
656 }
657
658 /* Initialize the user-mode PnP manager */
659 if (!EnableUserModePnpManager())
660 DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n");
661
662 /* Wait for any immediate pending installations to finish */
663 if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0)
664 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n");
665
666 CheckUnattendedSetup(&USetupData);
667
668 if (IsUnattendedSetup)
669 {
670 // TODO: Read options from inf
671 /* Load the hardware, language and keyboard layout lists */
672
673 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
674 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
675 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
676
677 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
678
679 /* new part */
680 SelectedLanguageId = DefaultLanguage;
681 wcscpy(DefaultLanguage, USetupData.LocaleID);
682 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
683
684 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
685
686 /* first we hack LanguageList */
687 for (ListEntry = GetFirstListEntry(USetupData.LanguageList); ListEntry;
688 ListEntry = GetNextListEntry(ListEntry))
689 {
690 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
691 if (!wcsicmp(USetupData.LocaleID, LocaleId))
692 {
693 DPRINT("found %S in LanguageList\n", LocaleId);
694 SetCurrentListEntry(USetupData.LanguageList, ListEntry);
695 break;
696 }
697 }
698
699 /* now LayoutList */
700 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
701 ListEntry = GetNextListEntry(ListEntry))
702 {
703 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
704 if (!wcsicmp(USetupData.LocaleID, LocaleId))
705 {
706 DPRINT("found %S in LayoutList\n", LocaleId);
707 SetCurrentListEntry(USetupData.LayoutList, ListEntry);
708 break;
709 }
710 }
711
712 SetConsoleCodePage();
713
714 return INSTALL_INTRO_PAGE;
715 }
716
717 return LANGUAGE_PAGE;
718 }
719
720
721 /*
722 * Displays the WelcomePage.
723 *
724 * Next pages:
725 * InstallIntroPage (default)
726 * RepairIntroPage
727 * RecoveryPage
728 * LicensePage
729 * QuitPage
730 *
731 * RETURNS
732 * Number of the next page.
733 */
734 static PAGE_NUMBER
735 WelcomePage(PINPUT_RECORD Ir)
736 {
737 MUIDisplayPage(WELCOME_PAGE);
738
739 while (TRUE)
740 {
741 CONSOLE_ConInKey(Ir);
742
743 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
744 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
745 {
746 if (ConfirmQuit(Ir))
747 return QUIT_PAGE;
748
749 break;
750 }
751 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
752 {
753 return INSTALL_INTRO_PAGE;
754 }
755 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
756 {
757 return RECOVERY_PAGE; // REPAIR_INTRO_PAGE;
758 }
759 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */
760 {
761 return LICENSE_PAGE;
762 }
763 }
764
765 return WELCOME_PAGE;
766 }
767
768
769 /*
770 * Displays the License page.
771 *
772 * Next page:
773 * WelcomePage (default)
774 *
775 * RETURNS
776 * Number of the next page.
777 */
778 static PAGE_NUMBER
779 LicensePage(PINPUT_RECORD Ir)
780 {
781 MUIDisplayPage(LICENSE_PAGE);
782
783 while (TRUE)
784 {
785 CONSOLE_ConInKey(Ir);
786
787 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
788 {
789 return WELCOME_PAGE;
790 }
791 }
792
793 return LICENSE_PAGE;
794 }
795
796
797 /*
798 * Displays the RepairIntroPage.
799 *
800 * Next pages:
801 * RebootPage (default)
802 * InstallIntroPage
803 * RecoveryPage
804 * IntroPage
805 *
806 * RETURNS
807 * Number of the next page.
808 */
809 static PAGE_NUMBER
810 RepairIntroPage(PINPUT_RECORD Ir)
811 {
812 MUIDisplayPage(REPAIR_INTRO_PAGE);
813
814 while (TRUE)
815 {
816 CONSOLE_ConInKey(Ir);
817
818 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
819 {
820 return REBOOT_PAGE;
821 }
822 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
823 {
824 RepairUpdateFlag = TRUE;
825 return INSTALL_INTRO_PAGE;
826 }
827 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
828 {
829 return RECOVERY_PAGE;
830 }
831 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
832 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
833 {
834 return WELCOME_PAGE;
835 }
836 }
837
838 return REPAIR_INTRO_PAGE;
839 }
840
841 /*
842 * Displays the UpgradeRepairPage.
843 *
844 * Next pages:
845 * RebootPage (default)
846 * InstallIntroPage
847 * RecoveryPage
848 * WelcomePage
849 *
850 * RETURNS
851 * Number of the next page.
852 */
853 static PAGE_NUMBER
854 UpgradeRepairPage(PINPUT_RECORD Ir)
855 {
856 GENERIC_LIST_UI ListUi;
857
858 /*** HACK!! ***/
859 if (PartitionList == NULL)
860 {
861 PartitionList = CreatePartitionList();
862 if (PartitionList == NULL)
863 {
864 /* FIXME: show an error dialog */
865 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
866 return QUIT_PAGE;
867 }
868 else if (IsListEmpty(&PartitionList->DiskListHead))
869 {
870 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
871 return QUIT_PAGE;
872 }
873
874 /* Reset the formatter machine state */
875 TempPartition = NULL;
876 FormatState = Start;
877 }
878 /**************/
879
880 NtOsInstallsList = CreateNTOSInstallationsList(PartitionList);
881 if (!NtOsInstallsList)
882 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
883
884 /*
885 * If there is no available installation (or just a single one??) that can
886 * be updated in the list, just continue with the regular installation.
887 */
888 if (!NtOsInstallsList || GetNumberOfListEntries(NtOsInstallsList) == 0)
889 {
890 RepairUpdateFlag = FALSE;
891
892 // return INSTALL_INTRO_PAGE;
893 return DEVICE_SETTINGS_PAGE;
894 // return SCSI_CONTROLLER_PAGE;
895 }
896
897 MUIDisplayPage(UPGRADE_REPAIR_PAGE);
898
899 InitGenericListUi(&ListUi, NtOsInstallsList, GetNTOSInstallationName);
900 DrawGenericList(&ListUi,
901 2, 23,
902 xScreen - 3,
903 yScreen - 3);
904
905 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
906 while (TRUE)
907 {
908 CONSOLE_ConInKey(Ir);
909
910 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00)
911 {
912 switch (Ir->Event.KeyEvent.wVirtualKeyCode)
913 {
914 case VK_DOWN: /* DOWN */
915 ScrollDownGenericList(&ListUi);
916 break;
917 case VK_UP: /* UP */
918 ScrollUpGenericList(&ListUi);
919 break;
920 case VK_NEXT: /* PAGE DOWN */
921 ScrollPageDownGenericList(&ListUi);
922 break;
923 case VK_PRIOR: /* PAGE UP */
924 ScrollPageUpGenericList(&ListUi);
925 break;
926 case VK_F3: /* F3 */
927 {
928 if (ConfirmQuit(Ir))
929 return QUIT_PAGE;
930 else
931 RedrawGenericList(&ListUi);
932 break;
933 }
934 case VK_ESCAPE: /* ESC */
935 {
936 RestoreGenericListUiState(&ListUi);
937 // return nextPage; // prevPage;
938
939 // return INSTALL_INTRO_PAGE;
940 return DEVICE_SETTINGS_PAGE;
941 // return SCSI_CONTROLLER_PAGE;
942 }
943 }
944 }
945 else
946 {
947 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
948 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
949 if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
950 {
951 /* Retrieve the current installation */
952 ASSERT(GetNumberOfListEntries(NtOsInstallsList) >= 1);
953
954 CurrentInstallation =
955 (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(NtOsInstallsList));
956
957 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
958 CurrentInstallation->InstallationName, CurrentInstallation->DiskNumber, CurrentInstallation->PartitionNumber);
959
960 RepairUpdateFlag = TRUE;
961
962 // return nextPage;
963 /***/return INSTALL_INTRO_PAGE;/***/
964 }
965 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) &&
966 (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) /* a-z */
967 {
968 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
969 }
970 }
971 }
972
973 return UPGRADE_REPAIR_PAGE;
974 }
975
976
977 /*
978 * Displays the InstallIntroPage.
979 *
980 * Next pages:
981 * DeviceSettingsPage (At once if repair or update is selected)
982 * SelectPartitionPage (At once if unattended setup)
983 * DeviceSettingsPage (default)
984 * QuitPage
985 *
986 * RETURNS
987 * Number of the next page.
988 */
989 static PAGE_NUMBER
990 InstallIntroPage(PINPUT_RECORD Ir)
991 {
992 if (RepairUpdateFlag)
993 {
994 #if 1 /* Old code that looks good */
995
996 // return SELECT_PARTITION_PAGE;
997 return DEVICE_SETTINGS_PAGE;
998
999 #else /* Possible new code? */
1000
1001 return DEVICE_SETTINGS_PAGE;
1002 // return SCSI_CONTROLLER_PAGE;
1003
1004 #endif
1005 }
1006
1007 if (IsUnattendedSetup)
1008 return SELECT_PARTITION_PAGE;
1009
1010 MUIDisplayPage(INSTALL_INTRO_PAGE);
1011
1012 while (TRUE)
1013 {
1014 CONSOLE_ConInKey(Ir);
1015
1016 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1017 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1018 {
1019 if (ConfirmQuit(Ir))
1020 return QUIT_PAGE;
1021
1022 break;
1023 }
1024 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1025 {
1026 return UPGRADE_REPAIR_PAGE;
1027 }
1028 }
1029
1030 return INSTALL_INTRO_PAGE;
1031 }
1032
1033
1034 #if 0
1035 static PAGE_NUMBER
1036 ScsiControllerPage(PINPUT_RECORD Ir)
1037 {
1038 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1039
1040 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1041
1042 /* FIXME: print loaded mass storage driver descriptions */
1043 #if 0
1044 CONSOLE_SetTextXY(8, 10, "TEST device");
1045 #endif
1046
1047 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1048
1049 while (TRUE)
1050 {
1051 CONSOLE_ConInKey(Ir);
1052
1053 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1054 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1055 {
1056 if (ConfirmQuit(Ir))
1057 return QUIT_PAGE;
1058
1059 break;
1060 }
1061 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1062 {
1063 return DEVICE_SETTINGS_PAGE;
1064 }
1065 }
1066
1067 return SCSI_CONTROLLER_PAGE;
1068 }
1069
1070 static PAGE_NUMBER
1071 OemDriverPage(PINPUT_RECORD Ir)
1072 {
1073 // MUIDisplayPage(OEM_DRIVER_PAGE);
1074
1075 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1076
1077 /* FIXME: Implement!! */
1078
1079 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1080
1081 while (TRUE)
1082 {
1083 CONSOLE_ConInKey(Ir);
1084
1085 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1086 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1087 {
1088 if (ConfirmQuit(Ir))
1089 return QUIT_PAGE;
1090
1091 break;
1092 }
1093 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1094 {
1095 return DEVICE_SETTINGS_PAGE;
1096 }
1097 }
1098
1099 return OEM_DRIVER_PAGE;
1100 }
1101 #endif
1102
1103
1104 /*
1105 * Displays the DeviceSettingsPage.
1106 *
1107 * Next pages:
1108 * SelectPartitionPage (At once if repair or update is selected)
1109 * ComputerSettingsPage
1110 * DisplaySettingsPage
1111 * KeyboardSettingsPage
1112 * LayoutsettingsPage
1113 * SelectPartitionPage
1114 * QuitPage
1115 *
1116 * SIDEEFFECTS
1117 * Init USetupData.ComputerList
1118 * Init USetupData.DisplayList
1119 * Init USetupData.KeyboardList
1120 * Init USetupData.LayoutList
1121 *
1122 * RETURNS
1123 * Number of the next page.
1124 */
1125 static PAGE_NUMBER
1126 DeviceSettingsPage(PINPUT_RECORD Ir)
1127 {
1128 static ULONG Line = 16;
1129
1130 /* Initialize the computer settings list */
1131 if (USetupData.ComputerList == NULL)
1132 {
1133 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
1134 if (USetupData.ComputerList == NULL)
1135 {
1136 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1137 return QUIT_PAGE;
1138 }
1139 }
1140
1141 /* Initialize the display settings list */
1142 if (USetupData.DisplayList == NULL)
1143 {
1144 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
1145 if (USetupData.DisplayList == NULL)
1146 {
1147 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1148 return QUIT_PAGE;
1149 }
1150 }
1151
1152 /* Initialize the keyboard settings list */
1153 if (USetupData.KeyboardList == NULL)
1154 {
1155 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
1156 if (USetupData.KeyboardList == NULL)
1157 {
1158 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1159 return QUIT_PAGE;
1160 }
1161 }
1162
1163 /* Initialize the keyboard layout list */
1164 if (USetupData.LayoutList == NULL)
1165 {
1166 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
1167 if (USetupData.LayoutList == NULL)
1168 {
1169 /* FIXME: report error */
1170 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1171 return QUIT_PAGE;
1172 }
1173 }
1174
1175 if (RepairUpdateFlag)
1176 return SELECT_PARTITION_PAGE;
1177
1178 // if (IsUnattendedSetup)
1179 // return SELECT_PARTITION_PAGE;
1180
1181 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1182
1183 DrawGenericListCurrentItem(USetupData.ComputerList, GetSettingDescription, 25, 11);
1184 DrawGenericListCurrentItem(USetupData.DisplayList , GetSettingDescription, 25, 12);
1185 DrawGenericListCurrentItem(USetupData.KeyboardList, GetSettingDescription, 25, 13);
1186 DrawGenericListCurrentItem(USetupData.LayoutList , GetSettingDescription, 25, 14);
1187
1188 CONSOLE_InvertTextXY(24, Line, 48, 1);
1189
1190 while (TRUE)
1191 {
1192 CONSOLE_ConInKey(Ir);
1193
1194 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1195 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1196 {
1197 CONSOLE_NormalTextXY(24, Line, 48, 1);
1198
1199 if (Line == 14)
1200 Line = 16;
1201 else if (Line == 16)
1202 Line = 11;
1203 else
1204 Line++;
1205
1206 CONSOLE_InvertTextXY(24, Line, 48, 1);
1207 }
1208 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1209 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1210 {
1211 CONSOLE_NormalTextXY(24, Line, 48, 1);
1212
1213 if (Line == 11)
1214 Line = 16;
1215 else if (Line == 16)
1216 Line = 14;
1217 else
1218 Line--;
1219
1220 CONSOLE_InvertTextXY(24, Line, 48, 1);
1221 }
1222 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1223 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1224 {
1225 if (ConfirmQuit(Ir))
1226 return QUIT_PAGE;
1227
1228 break;
1229 }
1230 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1231 {
1232 if (Line == 11)
1233 return COMPUTER_SETTINGS_PAGE;
1234 else if (Line == 12)
1235 return DISPLAY_SETTINGS_PAGE;
1236 else if (Line == 13)
1237 return KEYBOARD_SETTINGS_PAGE;
1238 else if (Line == 14)
1239 return LAYOUT_SETTINGS_PAGE;
1240 else if (Line == 16)
1241 return SELECT_PARTITION_PAGE;
1242 }
1243 }
1244
1245 return DEVICE_SETTINGS_PAGE;
1246 }
1247
1248
1249 /*
1250 * Handles generic selection lists.
1251 *
1252 * PARAMS
1253 * GenericList: The list to handle.
1254 * nextPage: The page it needs to jump to after this page.
1255 * Ir: The PINPUT_RECORD
1256 */
1257 static PAGE_NUMBER
1258 HandleGenericList(PGENERIC_LIST_UI ListUi,
1259 PAGE_NUMBER nextPage,
1260 PINPUT_RECORD Ir)
1261 {
1262 while (TRUE)
1263 {
1264 CONSOLE_ConInKey(Ir);
1265
1266 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1267 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1268 {
1269 ScrollDownGenericList(ListUi);
1270 }
1271 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1272 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1273 {
1274 ScrollUpGenericList(ListUi);
1275 }
1276 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1277 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1278 {
1279 ScrollPageDownGenericList(ListUi);
1280 }
1281 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1282 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1283 {
1284 ScrollPageUpGenericList(ListUi);
1285 }
1286 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1287 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1288 {
1289 if (ConfirmQuit(Ir))
1290 return QUIT_PAGE;
1291 else
1292 RedrawGenericList(ListUi);
1293 }
1294 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1295 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1296 {
1297 RestoreGenericListUiState(ListUi);
1298 return nextPage; // Use some "prevPage;" instead?
1299 }
1300 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1301 {
1302 return nextPage;
1303 }
1304 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1305 {
1306 /* a-z */
1307 GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
1308 }
1309 }
1310 }
1311
1312
1313 /*
1314 * Displays the ComputerSettingsPage.
1315 *
1316 * Next pages:
1317 * DeviceSettingsPage
1318 * QuitPage
1319 *
1320 * RETURNS
1321 * Number of the next page.
1322 */
1323 static PAGE_NUMBER
1324 ComputerSettingsPage(PINPUT_RECORD Ir)
1325 {
1326 GENERIC_LIST_UI ListUi;
1327 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1328
1329 InitGenericListUi(&ListUi, USetupData.ComputerList, GetSettingDescription);
1330 DrawGenericList(&ListUi,
1331 2, 18,
1332 xScreen - 3,
1333 yScreen - 3);
1334
1335 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1336 }
1337
1338
1339 /*
1340 * Displays the DisplaySettingsPage.
1341 *
1342 * Next pages:
1343 * DeviceSettingsPage
1344 * QuitPage
1345 *
1346 * RETURNS
1347 * Number of the next page.
1348 */
1349 static PAGE_NUMBER
1350 DisplaySettingsPage(PINPUT_RECORD Ir)
1351 {
1352 GENERIC_LIST_UI ListUi;
1353 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1354
1355 InitGenericListUi(&ListUi, USetupData.DisplayList, GetSettingDescription);
1356 DrawGenericList(&ListUi,
1357 2, 18,
1358 xScreen - 3,
1359 yScreen - 3);
1360
1361 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1362 }
1363
1364
1365 /*
1366 * Displays the KeyboardSettingsPage.
1367 *
1368 * Next pages:
1369 * DeviceSettingsPage
1370 * QuitPage
1371 *
1372 * RETURNS
1373 * Number of the next page.
1374 */
1375 static PAGE_NUMBER
1376 KeyboardSettingsPage(PINPUT_RECORD Ir)
1377 {
1378 GENERIC_LIST_UI ListUi;
1379 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1380
1381 InitGenericListUi(&ListUi, USetupData.KeyboardList, GetSettingDescription);
1382 DrawGenericList(&ListUi,
1383 2, 18,
1384 xScreen - 3,
1385 yScreen - 3);
1386
1387 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1388 }
1389
1390
1391 /*
1392 * Displays the LayoutSettingsPage.
1393 *
1394 * Next pages:
1395 * DeviceSettingsPage
1396 * QuitPage
1397 *
1398 * RETURNS
1399 * Number of the next page.
1400 */
1401 static PAGE_NUMBER
1402 LayoutSettingsPage(PINPUT_RECORD Ir)
1403 {
1404 GENERIC_LIST_UI ListUi;
1405 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1406
1407 InitGenericListUi(&ListUi, USetupData.LayoutList, GetSettingDescription);
1408 DrawGenericList(&ListUi,
1409 2, 18,
1410 xScreen - 3,
1411 yScreen - 3);
1412
1413 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1414 }
1415
1416
1417 static BOOL
1418 IsDiskSizeValid(PPARTENTRY PartEntry)
1419 {
1420 ULONGLONG size;
1421
1422 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1423 size = (size + (512 * KB)) / MB; /* in MBytes */
1424
1425 if (size < USetupData.RequiredPartitionDiskSpace)
1426 {
1427 /* Partition is too small so ask for another one */
1428 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, USetupData.RequiredPartitionDiskSpace);
1429 return FALSE;
1430 }
1431 else
1432 {
1433 return TRUE;
1434 }
1435 }
1436
1437
1438 /*
1439 * Displays the SelectPartitionPage.
1440 *
1441 * Next pages:
1442 * SelectFileSystemPage (At once if unattended)
1443 * SelectFileSystemPage (Default if free space is selected)
1444 * CreatePrimaryPartitionPage
1445 * CreateExtendedPartitionPage
1446 * CreateLogicalPartitionPage
1447 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1448 * DeletePartitionPage
1449 * QuitPage
1450 *
1451 * SIDEEFFECTS
1452 * Set InstallShortcut (only if not unattended + free space is selected)
1453 *
1454 * RETURNS
1455 * Number of the next page.
1456 */
1457 static PAGE_NUMBER
1458 SelectPartitionPage(PINPUT_RECORD Ir)
1459 {
1460 PARTLIST_UI ListUi;
1461 ULONG Error;
1462
1463 if (PartitionList == NULL)
1464 {
1465 PartitionList = CreatePartitionList();
1466 if (PartitionList == NULL)
1467 {
1468 /* FIXME: show an error dialog */
1469 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
1470 return QUIT_PAGE;
1471 }
1472 else if (IsListEmpty(&PartitionList->DiskListHead))
1473 {
1474 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
1475 return QUIT_PAGE;
1476 }
1477
1478 /* Reset the formatter machine state */
1479 TempPartition = NULL;
1480 FormatState = Start;
1481 }
1482
1483 if (RepairUpdateFlag)
1484 {
1485 ASSERT(CurrentInstallation);
1486
1487 /* Determine the selected installation disk & partition */
1488 InstallPartition = SelectPartition(PartitionList,
1489 CurrentInstallation->DiskNumber,
1490 CurrentInstallation->PartitionNumber);
1491 if (!InstallPartition)
1492 {
1493 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1494 ASSERT(FALSE);
1495 }
1496 ASSERT(!IsContainerPartition(InstallPartition->PartitionType));
1497
1498 return SELECT_FILE_SYSTEM_PAGE;
1499 }
1500
1501 MUIDisplayPage(SELECT_PARTITION_PAGE);
1502
1503 InitPartitionListUi(&ListUi, PartitionList,
1504 CurrentPartition,
1505 2, 23,
1506 xScreen - 3,
1507 yScreen - 3);
1508 DrawPartitionList(&ListUi);
1509
1510 if (IsUnattendedSetup)
1511 {
1512 /* Determine the selected installation disk & partition */
1513 InstallPartition = SelectPartition(PartitionList,
1514 USetupData.DestinationDiskNumber,
1515 USetupData.DestinationPartitionNumber);
1516 if (!InstallPartition)
1517 {
1518 CurrentPartition = ListUi.CurrentPartition;
1519
1520 if (USetupData.AutoPartition)
1521 {
1522 ASSERT(CurrentPartition != NULL);
1523 ASSERT(!IsContainerPartition(CurrentPartition->PartitionType));
1524
1525 if (CurrentPartition->LogicalPartition)
1526 {
1527 CreateLogicalPartition(PartitionList,
1528 CurrentPartition,
1529 CurrentPartition->SectorCount.QuadPart,
1530 TRUE);
1531 }
1532 else
1533 {
1534 CreatePrimaryPartition(PartitionList,
1535 CurrentPartition,
1536 CurrentPartition->SectorCount.QuadPart,
1537 TRUE);
1538 }
1539
1540 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1541 if (!IsDiskSizeValid(CurrentPartition))
1542 {
1543 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1544 USetupData.RequiredPartitionDiskSpace);
1545 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1546 }
1547
1548 InstallPartition = CurrentPartition;
1549 return SELECT_FILE_SYSTEM_PAGE;
1550 }
1551 }
1552 else
1553 {
1554 ASSERT(!IsContainerPartition(InstallPartition->PartitionType));
1555
1556 DrawPartitionList(&ListUi); // FIXME: Doesn't make much sense...
1557
1558 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1559 if (!IsDiskSizeValid(InstallPartition))
1560 {
1561 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1562 USetupData.RequiredPartitionDiskSpace);
1563 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1564 }
1565
1566 return SELECT_FILE_SYSTEM_PAGE;
1567 }
1568 }
1569
1570 while (TRUE)
1571 {
1572 CurrentPartition = ListUi.CurrentPartition;
1573
1574 /* Update status text */
1575 if (CurrentPartition == NULL)
1576 {
1577 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1578 }
1579 else if (CurrentPartition->LogicalPartition)
1580 {
1581 if (CurrentPartition->IsPartitioned)
1582 {
1583 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1584 }
1585 else
1586 {
1587 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL));
1588 }
1589 }
1590 else
1591 {
1592 if (CurrentPartition->IsPartitioned)
1593 {
1594 if (IsContainerPartition(CurrentPartition->PartitionType))
1595 {
1596 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1597 }
1598 else
1599 {
1600 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1601 }
1602 }
1603 else
1604 {
1605 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1606 }
1607 }
1608
1609 CONSOLE_ConInKey(Ir);
1610
1611 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1612 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1613 {
1614 if (ConfirmQuit(Ir))
1615 {
1616 DestroyPartitionList(PartitionList);
1617 PartitionList = NULL;
1618 return QUIT_PAGE;
1619 }
1620
1621 break;
1622 }
1623 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1624 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1625 {
1626 ScrollDownPartitionList(&ListUi);
1627 }
1628 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1629 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1630 {
1631 ScrollUpPartitionList(&ListUi);
1632 }
1633 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1634 {
1635 ASSERT(CurrentPartition != NULL);
1636
1637 if (IsContainerPartition(CurrentPartition->PartitionType))
1638 continue; // return SELECT_PARTITION_PAGE;
1639
1640 /*
1641 * Check whether the user wants to install ReactOS on a disk that
1642 * is not recognized by the computer's firmware and if so, display
1643 * a warning since such disks may not be bootable.
1644 */
1645 if (CurrentPartition->DiskEntry->MediaType == FixedMedia &&
1646 !CurrentPartition->DiskEntry->BiosFound)
1647 {
1648 PopupError("The disk you have selected for installing ReactOS\n"
1649 "is not visible by the firmware of your computer,\n"
1650 "and so may not be bootable.\n"
1651 "Press ENTER to continue nonetheless.",
1652 MUIGetString(STRING_CONTINUE),
1653 Ir, POPUP_WAIT_ENTER);
1654 // return SELECT_PARTITION_PAGE;
1655 }
1656
1657 if (CurrentPartition->IsPartitioned == FALSE)
1658 {
1659 if (CurrentPartition->LogicalPartition)
1660 {
1661 Error = LogicalPartitionCreationChecks(CurrentPartition);
1662 if (Error != NOT_AN_ERROR)
1663 {
1664 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1665 return SELECT_PARTITION_PAGE;
1666 }
1667
1668 CreateLogicalPartition(PartitionList,
1669 CurrentPartition,
1670 0ULL,
1671 TRUE);
1672 }
1673 else
1674 {
1675 Error = PrimaryPartitionCreationChecks(CurrentPartition);
1676 if (Error != NOT_AN_ERROR)
1677 {
1678 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1679 return SELECT_PARTITION_PAGE;
1680 }
1681
1682 CreatePrimaryPartition(PartitionList,
1683 CurrentPartition,
1684 0ULL,
1685 TRUE);
1686 }
1687 }
1688
1689 if (!IsDiskSizeValid(CurrentPartition))
1690 {
1691 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1692 USetupData.RequiredPartitionDiskSpace);
1693 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1694 }
1695
1696 InstallPartition = CurrentPartition;
1697 return SELECT_FILE_SYSTEM_PAGE;
1698 }
1699 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1700 {
1701 ASSERT(CurrentPartition != NULL);
1702
1703 if (CurrentPartition->LogicalPartition == FALSE)
1704 {
1705 Error = PrimaryPartitionCreationChecks(CurrentPartition);
1706 if (Error != NOT_AN_ERROR)
1707 {
1708 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1709 return SELECT_PARTITION_PAGE;
1710 }
1711
1712 return CREATE_PRIMARY_PARTITION_PAGE;
1713 }
1714 }
1715 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1716 {
1717 ASSERT(CurrentPartition != NULL);
1718
1719 if (CurrentPartition->LogicalPartition == FALSE)
1720 {
1721 Error = ExtendedPartitionCreationChecks(CurrentPartition);
1722 if (Error != NOT_AN_ERROR)
1723 {
1724 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1725 return SELECT_PARTITION_PAGE;
1726 }
1727
1728 return CREATE_EXTENDED_PARTITION_PAGE;
1729 }
1730 }
1731 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1732 {
1733 ASSERT(CurrentPartition != NULL);
1734
1735 if (CurrentPartition->LogicalPartition)
1736 {
1737 Error = LogicalPartitionCreationChecks(CurrentPartition);
1738 if (Error != NOT_AN_ERROR)
1739 {
1740 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1741 return SELECT_PARTITION_PAGE;
1742 }
1743
1744 return CREATE_LOGICAL_PARTITION_PAGE;
1745 }
1746 }
1747 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1748 {
1749 UNICODE_STRING CurrentPartitionU;
1750 WCHAR PathBuffer[MAX_PATH];
1751
1752 ASSERT(CurrentPartition != NULL);
1753
1754 if (CurrentPartition->IsPartitioned == FALSE)
1755 {
1756 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1757 return SELECT_PARTITION_PAGE;
1758 }
1759
1760 // TODO: Do something similar before trying to format the partition?
1761 if (!CurrentPartition->New &&
1762 !IsContainerPartition(CurrentPartition->PartitionType) &&
1763 CurrentPartition->FormatState != Unformatted)
1764 {
1765 ASSERT(CurrentPartition->PartitionNumber != 0);
1766
1767 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
1768 L"\\Device\\Harddisk%lu\\Partition%lu\\",
1769 CurrentPartition->DiskEntry->DiskNumber,
1770 CurrentPartition->PartitionNumber);
1771 RtlInitUnicodeString(&CurrentPartitionU, PathBuffer);
1772
1773 /*
1774 * Check whether the user attempts to delete the partition on which
1775 * the installation source is present. If so, fail with an error.
1776 */
1777 // &USetupData.SourceRootPath
1778 if (RtlPrefixUnicodeString(&CurrentPartitionU, &USetupData.SourcePath, TRUE))
1779 {
1780 PopupError("You cannot delete the partition containing the installation source!",
1781 MUIGetString(STRING_CONTINUE),
1782 Ir, POPUP_WAIT_ENTER);
1783 return SELECT_PARTITION_PAGE;
1784 }
1785 }
1786
1787 // FIXME TODO: PartitionList->SystemPartition is not yet initialized!!!!
1788 if (CurrentPartition == PartitionList->SystemPartition ||
1789 CurrentPartition->BootIndicator)
1790 {
1791 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1792 }
1793
1794 return DELETE_PARTITION_PAGE;
1795 }
1796 }
1797
1798 return SELECT_PARTITION_PAGE;
1799 }
1800
1801
1802 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1803 /* Restriction for MaxSize */
1804 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1805
1806 static VOID
1807 ShowPartitionSizeInputBox(SHORT Left,
1808 SHORT Top,
1809 SHORT Right,
1810 SHORT Bottom,
1811 ULONG MaxSize,
1812 PWSTR InputBuffer,
1813 PBOOLEAN Quit,
1814 PBOOLEAN Cancel)
1815 {
1816 INPUT_RECORD Ir;
1817 COORD coPos;
1818 DWORD Written;
1819 CHAR Buffer[128];
1820 INT Length, Pos;
1821 WCHAR ch;
1822 SHORT iLeft;
1823 SHORT iTop;
1824
1825 if (Quit != NULL)
1826 *Quit = FALSE;
1827
1828 if (Cancel != NULL)
1829 *Cancel = FALSE;
1830
1831 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1832
1833 /* Print message */
1834 coPos.X = Left + 2;
1835 coPos.Y = Top + 2;
1836 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1837 iLeft = coPos.X + strlen(Buffer) + 1;
1838 iTop = coPos.Y;
1839
1840 WriteConsoleOutputCharacterA(StdOutput,
1841 Buffer,
1842 strlen(Buffer),
1843 coPos,
1844 &Written);
1845
1846 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1847 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1848 coPos.Y = iTop;
1849 WriteConsoleOutputCharacterA(StdOutput,
1850 Buffer,
1851 strlen(Buffer),
1852 coPos,
1853 &Written);
1854
1855 swprintf(InputBuffer, L"%lu", MaxSize);
1856 Length = wcslen(InputBuffer);
1857 Pos = Length;
1858 CONSOLE_SetInputTextXY(iLeft,
1859 iTop,
1860 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1861 InputBuffer);
1862 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1863 CONSOLE_SetCursorType(TRUE, TRUE);
1864
1865 while (TRUE)
1866 {
1867 CONSOLE_ConInKey(&Ir);
1868
1869 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1870 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1871 {
1872 if (Quit != NULL)
1873 *Quit = TRUE;
1874
1875 InputBuffer[0] = UNICODE_NULL;
1876 CONSOLE_SetCursorType(TRUE, FALSE);
1877 break;
1878 }
1879 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1880 {
1881 CONSOLE_SetCursorType(TRUE, FALSE);
1882 break;
1883 }
1884 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1885 {
1886 if (Cancel != NULL)
1887 *Cancel = TRUE;
1888
1889 InputBuffer[0] = UNICODE_NULL;
1890 CONSOLE_SetCursorType(TRUE, FALSE);
1891 break;
1892 }
1893 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1894 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1895 {
1896 Pos = 0;
1897 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1898 }
1899 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1900 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1901 {
1902 Pos = Length;
1903 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1904 }
1905 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1906 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1907 {
1908 if (Pos > 0)
1909 {
1910 Pos--;
1911 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1912 }
1913 }
1914 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1915 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1916 {
1917 if (Pos < Length)
1918 {
1919 Pos++;
1920 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1921 }
1922 }
1923 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1924 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1925 {
1926 if (Pos < Length)
1927 {
1928 memmove(&InputBuffer[Pos],
1929 &InputBuffer[Pos + 1],
1930 (Length - Pos - 1) * sizeof(WCHAR));
1931 InputBuffer[Length - 1] = UNICODE_NULL;
1932
1933 Length--;
1934 CONSOLE_SetInputTextXY(iLeft,
1935 iTop,
1936 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1937 InputBuffer);
1938 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1939 }
1940 }
1941 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
1942 {
1943 if (Pos > 0)
1944 {
1945 if (Pos < Length)
1946 memmove(&InputBuffer[Pos - 1],
1947 &InputBuffer[Pos],
1948 (Length - Pos) * sizeof(WCHAR));
1949 InputBuffer[Length - 1] = UNICODE_NULL;
1950
1951 Pos--;
1952 Length--;
1953 CONSOLE_SetInputTextXY(iLeft,
1954 iTop,
1955 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1956 InputBuffer);
1957 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1958 }
1959 }
1960 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
1961 {
1962 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
1963 {
1964 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1965
1966 if ((ch >= L'0') && (ch <= L'9'))
1967 {
1968 if (Pos < Length)
1969 memmove(&InputBuffer[Pos + 1],
1970 &InputBuffer[Pos],
1971 (Length - Pos) * sizeof(WCHAR));
1972 InputBuffer[Length + 1] = UNICODE_NULL;
1973 InputBuffer[Pos] = ch;
1974
1975 Pos++;
1976 Length++;
1977 CONSOLE_SetInputTextXY(iLeft,
1978 iTop,
1979 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1980 InputBuffer);
1981 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1982 }
1983 }
1984 }
1985 }
1986 }
1987
1988
1989 /*
1990 * Displays the CreatePrimaryPartitionPage.
1991 *
1992 * Next pages:
1993 * SelectPartitionPage
1994 * SelectFileSystemPage (default)
1995 * QuitPage
1996 *
1997 * RETURNS
1998 * Number of the next page.
1999 */
2000 static PAGE_NUMBER
2001 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
2002 {
2003 PPARTENTRY PartEntry;
2004 PDISKENTRY DiskEntry;
2005 BOOLEAN Quit;
2006 BOOLEAN Cancel;
2007 WCHAR InputBuffer[50];
2008 ULONG MaxSize;
2009 ULONGLONG PartSize;
2010 ULONGLONG DiskSize;
2011 ULONGLONG SectorCount;
2012 PCHAR Unit;
2013
2014 if (PartitionList == NULL || CurrentPartition == NULL)
2015 {
2016 /* FIXME: show an error dialog */
2017 return QUIT_PAGE;
2018 }
2019
2020 PartEntry = CurrentPartition;
2021 DiskEntry = CurrentPartition->DiskEntry;
2022
2023 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2024
2025 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
2026
2027 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2028 #if 0
2029 if (DiskSize >= 10 * GB) /* 10 GB */
2030 {
2031 DiskSize = DiskSize / GB;
2032 Unit = MUIGetString(STRING_GB);
2033 }
2034 else
2035 #endif
2036 {
2037 DiskSize = DiskSize / MB;
2038 if (DiskSize == 0)
2039 DiskSize = 1;
2040
2041 Unit = MUIGetString(STRING_MB);
2042 }
2043
2044 if (DiskEntry->DriverName.Length > 0)
2045 {
2046 CONSOLE_PrintTextXY(6, 10,
2047 MUIGetString(STRING_HDINFOPARTCREATE_1),
2048 DiskSize,
2049 Unit,
2050 DiskEntry->DiskNumber,
2051 DiskEntry->Port,
2052 DiskEntry->Bus,
2053 DiskEntry->Id,
2054 &DiskEntry->DriverName,
2055 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2056 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2057 "RAW");
2058 }
2059 else
2060 {
2061 CONSOLE_PrintTextXY(6, 10,
2062 MUIGetString(STRING_HDINFOPARTCREATE_2),
2063 DiskSize,
2064 Unit,
2065 DiskEntry->DiskNumber,
2066 DiskEntry->Port,
2067 DiskEntry->Bus,
2068 DiskEntry->Id,
2069 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2070 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2071 "RAW");
2072 }
2073
2074 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2075
2076 #if 0
2077 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2078 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2079 #endif
2080
2081 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2082
2083 PartEntry = CurrentPartition;
2084 while (TRUE)
2085 {
2086 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2087
2088 if (MaxSize > PARTITION_MAXSIZE)
2089 MaxSize = PARTITION_MAXSIZE;
2090
2091 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2092 MaxSize, InputBuffer, &Quit, &Cancel);
2093
2094 if (Quit)
2095 {
2096 if (ConfirmQuit(Ir))
2097 return QUIT_PAGE;
2098
2099 break;
2100 }
2101 else if (Cancel)
2102 {
2103 return SELECT_PARTITION_PAGE;
2104 }
2105 else
2106 {
2107 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2108
2109 if (PartSize < 1)
2110 {
2111 /* Too small */
2112 continue;
2113 }
2114
2115 if (PartSize > MaxSize)
2116 {
2117 /* Too large */
2118 continue;
2119 }
2120
2121 /* Convert to bytes */
2122 if (PartSize == MaxSize)
2123 {
2124 /* Use all of the unpartitioned disk space */
2125 SectorCount = PartEntry->SectorCount.QuadPart;
2126 }
2127 else
2128 {
2129 /* Calculate the sector count from the size in MB */
2130 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2131
2132 /* But never get larger than the unpartitioned disk space */
2133 if (SectorCount > PartEntry->SectorCount.QuadPart)
2134 SectorCount = PartEntry->SectorCount.QuadPart;
2135 }
2136
2137 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2138
2139 CreatePrimaryPartition(PartitionList,
2140 CurrentPartition,
2141 SectorCount,
2142 FALSE);
2143
2144 return SELECT_PARTITION_PAGE;
2145 }
2146 }
2147
2148 return CREATE_PRIMARY_PARTITION_PAGE;
2149 }
2150
2151
2152 /*
2153 * Displays the CreateExtendedPartitionPage.
2154 *
2155 * Next pages:
2156 * SelectPartitionPage (default)
2157 * QuitPage
2158 *
2159 * RETURNS
2160 * Number of the next page.
2161 */
2162 static PAGE_NUMBER
2163 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2164 {
2165 PPARTENTRY PartEntry;
2166 PDISKENTRY DiskEntry;
2167 BOOLEAN Quit;
2168 BOOLEAN Cancel;
2169 WCHAR InputBuffer[50];
2170 ULONG MaxSize;
2171 ULONGLONG PartSize;
2172 ULONGLONG DiskSize;
2173 ULONGLONG SectorCount;
2174 PCHAR Unit;
2175
2176 if (PartitionList == NULL || CurrentPartition == NULL)
2177 {
2178 /* FIXME: show an error dialog */
2179 return QUIT_PAGE;
2180 }
2181
2182 PartEntry = CurrentPartition;
2183 DiskEntry = CurrentPartition->DiskEntry;
2184
2185 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2186
2187 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2188
2189 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2190 #if 0
2191 if (DiskSize >= 10 * GB) /* 10 GB */
2192 {
2193 DiskSize = DiskSize / GB;
2194 Unit = MUIGetString(STRING_GB);
2195 }
2196 else
2197 #endif
2198 {
2199 DiskSize = DiskSize / MB;
2200 if (DiskSize == 0)
2201 DiskSize = 1;
2202
2203 Unit = MUIGetString(STRING_MB);
2204 }
2205
2206 if (DiskEntry->DriverName.Length > 0)
2207 {
2208 CONSOLE_PrintTextXY(6, 10,
2209 MUIGetString(STRING_HDINFOPARTCREATE_1),
2210 DiskSize,
2211 Unit,
2212 DiskEntry->DiskNumber,
2213 DiskEntry->Port,
2214 DiskEntry->Bus,
2215 DiskEntry->Id,
2216 &DiskEntry->DriverName,
2217 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2218 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2219 "RAW");
2220 }
2221 else
2222 {
2223 CONSOLE_PrintTextXY(6, 10,
2224 MUIGetString(STRING_HDINFOPARTCREATE_2),
2225 DiskSize,
2226 Unit,
2227 DiskEntry->DiskNumber,
2228 DiskEntry->Port,
2229 DiskEntry->Bus,
2230 DiskEntry->Id,
2231 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2232 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2233 "RAW");
2234 }
2235
2236 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2237
2238 #if 0
2239 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2240 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2241 #endif
2242
2243 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2244
2245 PartEntry = CurrentPartition;
2246 while (TRUE)
2247 {
2248 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2249
2250 if (MaxSize > PARTITION_MAXSIZE)
2251 MaxSize = PARTITION_MAXSIZE;
2252
2253 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2254 MaxSize, InputBuffer, &Quit, &Cancel);
2255
2256 if (Quit)
2257 {
2258 if (ConfirmQuit(Ir))
2259 return QUIT_PAGE;
2260
2261 break;
2262 }
2263 else if (Cancel)
2264 {
2265 return SELECT_PARTITION_PAGE;
2266 }
2267 else
2268 {
2269 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2270
2271 if (PartSize < 1)
2272 {
2273 /* Too small */
2274 continue;
2275 }
2276
2277 if (PartSize > MaxSize)
2278 {
2279 /* Too large */
2280 continue;
2281 }
2282
2283 /* Convert to bytes */
2284 if (PartSize == MaxSize)
2285 {
2286 /* Use all of the unpartitioned disk space */
2287 SectorCount = PartEntry->SectorCount.QuadPart;
2288 }
2289 else
2290 {
2291 /* Calculate the sector count from the size in MB */
2292 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2293
2294 /* But never get larger than the unpartitioned disk space */
2295 if (SectorCount > PartEntry->SectorCount.QuadPart)
2296 SectorCount = PartEntry->SectorCount.QuadPart;
2297 }
2298
2299 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2300
2301 CreateExtendedPartition(PartitionList,
2302 CurrentPartition,
2303 SectorCount);
2304
2305 return SELECT_PARTITION_PAGE;
2306 }
2307 }
2308
2309 return CREATE_EXTENDED_PARTITION_PAGE;
2310 }
2311
2312
2313 /*
2314 * Displays the CreateLogicalPartitionPage.
2315 *
2316 * Next pages:
2317 * SelectFileSystemPage (default)
2318 * QuitPage
2319 *
2320 * RETURNS
2321 * Number of the next page.
2322 */
2323 static PAGE_NUMBER
2324 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2325 {
2326 PPARTENTRY PartEntry;
2327 PDISKENTRY DiskEntry;
2328 BOOLEAN Quit;
2329 BOOLEAN Cancel;
2330 WCHAR InputBuffer[50];
2331 ULONG MaxSize;
2332 ULONGLONG PartSize;
2333 ULONGLONG DiskSize;
2334 ULONGLONG SectorCount;
2335 PCHAR Unit;
2336
2337 if (PartitionList == NULL || CurrentPartition == NULL)
2338 {
2339 /* FIXME: show an error dialog */
2340 return QUIT_PAGE;
2341 }
2342
2343 PartEntry = CurrentPartition;
2344 DiskEntry = CurrentPartition->DiskEntry;
2345
2346 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2347
2348 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2349
2350 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2351 #if 0
2352 if (DiskSize >= 10 * GB) /* 10 GB */
2353 {
2354 DiskSize = DiskSize / GB;
2355 Unit = MUIGetString(STRING_GB);
2356 }
2357 else
2358 #endif
2359 {
2360 DiskSize = DiskSize / MB;
2361 if (DiskSize == 0)
2362 DiskSize = 1;
2363
2364 Unit = MUIGetString(STRING_MB);
2365 }
2366
2367 if (DiskEntry->DriverName.Length > 0)
2368 {
2369 CONSOLE_PrintTextXY(6, 10,
2370 MUIGetString(STRING_HDINFOPARTCREATE_1),
2371 DiskSize,
2372 Unit,
2373 DiskEntry->DiskNumber,
2374 DiskEntry->Port,
2375 DiskEntry->Bus,
2376 DiskEntry->Id,
2377 &DiskEntry->DriverName,
2378 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2379 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2380 "RAW");
2381 }
2382 else
2383 {
2384 CONSOLE_PrintTextXY(6, 10,
2385 MUIGetString(STRING_HDINFOPARTCREATE_2),
2386 DiskSize,
2387 Unit,
2388 DiskEntry->DiskNumber,
2389 DiskEntry->Port,
2390 DiskEntry->Bus,
2391 DiskEntry->Id,
2392 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2393 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2394 "RAW");
2395 }
2396
2397 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2398
2399 #if 0
2400 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2401 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2402 #endif
2403
2404 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2405
2406 PartEntry = CurrentPartition;
2407 while (TRUE)
2408 {
2409 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2410
2411 if (MaxSize > PARTITION_MAXSIZE)
2412 MaxSize = PARTITION_MAXSIZE;
2413
2414 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2415 MaxSize, InputBuffer, &Quit, &Cancel);
2416
2417 if (Quit)
2418 {
2419 if (ConfirmQuit(Ir))
2420 return QUIT_PAGE;
2421
2422 break;
2423 }
2424 else if (Cancel)
2425 {
2426 return SELECT_PARTITION_PAGE;
2427 }
2428 else
2429 {
2430 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2431
2432 if (PartSize < 1)
2433 {
2434 /* Too small */
2435 continue;
2436 }
2437
2438 if (PartSize > MaxSize)
2439 {
2440 /* Too large */
2441 continue;
2442 }
2443
2444 /* Convert to bytes */
2445 if (PartSize == MaxSize)
2446 {
2447 /* Use all of the unpartitioned disk space */
2448 SectorCount = PartEntry->SectorCount.QuadPart;
2449 }
2450 else
2451 {
2452 /* Calculate the sector count from the size in MB */
2453 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2454
2455 /* But never get larger than the unpartitioned disk space */
2456 if (SectorCount > PartEntry->SectorCount.QuadPart)
2457 SectorCount = PartEntry->SectorCount.QuadPart;
2458 }
2459
2460 DPRINT("Partition size: %I64u bytes\n", PartSize);
2461
2462 CreateLogicalPartition(PartitionList,
2463 CurrentPartition,
2464 SectorCount,
2465 FALSE);
2466
2467 return SELECT_PARTITION_PAGE;
2468 }
2469 }
2470
2471 return CREATE_LOGICAL_PARTITION_PAGE;
2472 }
2473
2474
2475 /*
2476 * Displays the ConfirmDeleteSystemPartitionPage.
2477 *
2478 * Next pages:
2479 * DeletePartitionPage (default)
2480 * SelectPartitionPage
2481 *
2482 * RETURNS
2483 * Number of the next page.
2484 */
2485 static PAGE_NUMBER
2486 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2487 {
2488 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2489
2490 while (TRUE)
2491 {
2492 CONSOLE_ConInKey(Ir);
2493
2494 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2495 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2496 {
2497 if (ConfirmQuit(Ir))
2498 return QUIT_PAGE;
2499
2500 break;
2501 }
2502 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2503 {
2504 return DELETE_PARTITION_PAGE;
2505 }
2506 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2507 {
2508 return SELECT_PARTITION_PAGE;
2509 }
2510 }
2511
2512 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2513 }
2514
2515
2516 /*
2517 * Displays the DeletePartitionPage.
2518 *
2519 * Next pages:
2520 * SelectPartitionPage (default)
2521 * QuitPage
2522 *
2523 * RETURNS
2524 * Number of the next page.
2525 */
2526 static PAGE_NUMBER
2527 DeletePartitionPage(PINPUT_RECORD Ir)
2528 {
2529 PPARTENTRY PartEntry;
2530 PDISKENTRY DiskEntry;
2531 ULONGLONG DiskSize;
2532 ULONGLONG PartSize;
2533 PCHAR Unit;
2534 CHAR PartTypeString[32];
2535
2536 if (PartitionList == NULL || CurrentPartition == NULL)
2537 {
2538 /* FIXME: show an error dialog */
2539 return QUIT_PAGE;
2540 }
2541
2542 PartEntry = CurrentPartition;
2543 DiskEntry = CurrentPartition->DiskEntry;
2544
2545 MUIDisplayPage(DELETE_PARTITION_PAGE);
2546
2547 /* Adjust partition type */
2548 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2549 PartTypeString,
2550 ARRAYSIZE(PartTypeString));
2551
2552 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2553 #if 0
2554 if (PartSize >= 10 * GB) /* 10 GB */
2555 {
2556 PartSize = PartSize / GB;
2557 Unit = MUIGetString(STRING_GB);
2558 }
2559 else
2560 #endif
2561 if (PartSize >= 10 * MB) /* 10 MB */
2562 {
2563 PartSize = PartSize / MB;
2564 Unit = MUIGetString(STRING_MB);
2565 }
2566 else
2567 {
2568 PartSize = PartSize / KB;
2569 Unit = MUIGetString(STRING_KB);
2570 }
2571
2572 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2573 {
2574 CONSOLE_PrintTextXY(6, 10,
2575 MUIGetString(STRING_HDDINFOUNK2),
2576 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2577 (PartEntry->DriveLetter == 0) ? '-' : ':',
2578 PartEntry->PartitionType,
2579 PartSize,
2580 Unit);
2581 }
2582 else
2583 {
2584 CONSOLE_PrintTextXY(6, 10,
2585 " %c%c %s %I64u %s",
2586 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2587 (PartEntry->DriveLetter == 0) ? '-' : ':',
2588 PartTypeString,
2589 PartSize,
2590 Unit);
2591 }
2592
2593 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2594 #if 0
2595 if (DiskSize >= 10 * GB) /* 10 GB */
2596 {
2597 DiskSize = DiskSize / GB;
2598 Unit = MUIGetString(STRING_GB);
2599 }
2600 else
2601 #endif
2602 {
2603 DiskSize = DiskSize / MB;
2604 if (DiskSize == 0)
2605 DiskSize = 1;
2606
2607 Unit = MUIGetString(STRING_MB);
2608 }
2609
2610 if (DiskEntry->DriverName.Length > 0)
2611 {
2612 CONSOLE_PrintTextXY(6, 12,
2613 MUIGetString(STRING_HDINFOPARTDELETE_1),
2614 DiskSize,
2615 Unit,
2616 DiskEntry->DiskNumber,
2617 DiskEntry->Port,
2618 DiskEntry->Bus,
2619 DiskEntry->Id,
2620 &DiskEntry->DriverName,
2621 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2622 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2623 "RAW");
2624 }
2625 else
2626 {
2627 CONSOLE_PrintTextXY(6, 12,
2628 MUIGetString(STRING_HDINFOPARTDELETE_2),
2629 DiskSize,
2630 Unit,
2631 DiskEntry->DiskNumber,
2632 DiskEntry->Port,
2633 DiskEntry->Bus,
2634 DiskEntry->Id,
2635 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2636 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2637 "RAW");
2638 }
2639
2640 while (TRUE)
2641 {
2642 CONSOLE_ConInKey(Ir);
2643
2644 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2645 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2646 {
2647 if (ConfirmQuit(Ir))
2648 return QUIT_PAGE;
2649
2650 break;
2651 }
2652 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2653 {
2654 return SELECT_PARTITION_PAGE;
2655 }
2656 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2657 {
2658 DeletePartition(PartitionList,
2659 CurrentPartition,
2660 &CurrentPartition);
2661 return SELECT_PARTITION_PAGE;
2662 }
2663 }
2664
2665 return DELETE_PARTITION_PAGE;
2666 }
2667
2668
2669 static VOID
2670 ResetFileSystemList(VOID)
2671 {
2672 if (!FileSystemList)
2673 return;
2674
2675 DestroyFileSystemList(FileSystemList);
2676 FileSystemList = NULL;
2677 }
2678
2679 /*
2680 * Displays the SelectFileSystemPage.
2681 *
2682 * Next pages:
2683 * CheckFileSystemPage (At once if RepairUpdate is selected)
2684 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2685 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2686 * SelectPartitionPage (If the user aborts)
2687 * FormatPartitionPage (Default)
2688 * QuitPage
2689 *
2690 * SIDEEFFECTS
2691 * Calls UpdatePartitionType()
2692 * Calls CheckActiveSystemPartition()
2693 *
2694 * RETURNS
2695 * Number of the next page.
2696 */
2697 static PAGE_NUMBER
2698 SelectFileSystemPage(PINPUT_RECORD Ir)
2699 {
2700 PPARTENTRY PartEntry;
2701 PDISKENTRY DiskEntry;
2702 ULONGLONG DiskSize;
2703 ULONGLONG PartSize;
2704 PCHAR DiskUnit;
2705 PCHAR PartUnit;
2706 CHAR PartTypeString[32];
2707 FORMATMACHINESTATE PreviousFormatState;
2708 PCWSTR DefaultFs;
2709
2710 DPRINT("SelectFileSystemPage()\n");
2711
2712 if (PartitionList == NULL || InstallPartition == NULL)
2713 {
2714 /* FIXME: show an error dialog */
2715 return QUIT_PAGE;
2716 }
2717
2718 /* Find or set the active system partition when starting formatting */
2719 if (FormatState == Start)
2720 {
2721 /* Find or set the active system partition */
2722 CheckActiveSystemPartition(PartitionList,
2723 FALSE,
2724 InstallPartition->DiskEntry,
2725 InstallPartition);
2726 if (PartitionList->SystemPartition == NULL)
2727 {
2728 /* FIXME: show an error dialog */
2729 //
2730 // Error dialog should say that we cannot find a suitable
2731 // system partition and create one on the system. At this point,
2732 // it may be nice to ask the user whether he wants to continue,
2733 // or use an external drive as the system drive/partition
2734 // (e.g. floppy, USB drive, etc...)
2735 //
2736 return QUIT_PAGE;
2737 }
2738
2739 /*
2740 * If the system partition can be created in some
2741 * non-partitioned space, create it now.
2742 */
2743 if (!PartitionList->SystemPartition->IsPartitioned)
2744 {
2745 // if (IsUnattendedSetup)
2746 {
2747 CreatePrimaryPartition(PartitionList,
2748 PartitionList->SystemPartition,
2749 0LL, // PartitionList->SystemPartition->SectorCount.QuadPart,
2750 TRUE);
2751 ASSERT(PartitionList->SystemPartition->IsPartitioned);
2752 }
2753 // else
2754 {
2755 }
2756 }
2757
2758 /* Commit all partition changes to all the disks */
2759 if (!WritePartitionsToDisk(PartitionList))
2760 {
2761 DPRINT("WritePartitionsToDisk() failed\n");
2762 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
2763 return QUIT_PAGE;
2764 }
2765
2766 /*
2767 * In all cases, whether or not we are going to perform a formatting,
2768 * we must perform a filesystem check of both the system and the
2769 * installation partitions.
2770 */
2771 InstallPartition->NeedsCheck = TRUE;
2772 if (PartitionList->SystemPartition != InstallPartition)
2773 PartitionList->SystemPartition->NeedsCheck = TRUE;
2774
2775 /*
2776 * In case we just repair an existing installation, or make
2777 * an unattended setup without formatting, just go to the
2778 * filesystem check step.
2779 */
2780 if (RepairUpdateFlag)
2781 return CHECK_FILE_SYSTEM_PAGE;
2782
2783 if (IsUnattendedSetup && !USetupData.FormatPartition)
2784 return CHECK_FILE_SYSTEM_PAGE;
2785 }
2786
2787 // ASSERT(PartitionList->SystemPartition->IsPartitioned);
2788
2789 /* Reset the filesystem list for each partition that is to be formatted */
2790 ResetFileSystemList();
2791
2792 PreviousFormatState = FormatState;
2793 switch (FormatState)
2794 {
2795 case Start:
2796 {
2797 /*
2798 * We start by formatting the system partition in case it is new
2799 * (it didn't exist before) and is not the same as the installation
2800 * partition. Otherwise we just require a filesystem check on it,
2801 * and start by formatting the installation partition instead.
2802 */
2803
2804 ASSERT(PartitionList->SystemPartition->IsPartitioned);
2805
2806 if ((PartitionList->SystemPartition != InstallPartition) &&
2807 (PartitionList->SystemPartition->FormatState == Unformatted))
2808 {
2809 TempPartition = PartitionList->SystemPartition;
2810 TempPartition->NeedsCheck = TRUE;
2811
2812 // TODO: Should we let the user using a custom file-system,
2813 // or should we always use FAT(32) for it?
2814 // For "compatibility", FAT(32) would be best indeed.
2815
2816 FormatState = FormatSystemPartition;
2817 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2818 }
2819 else
2820 {
2821 TempPartition = InstallPartition;
2822 TempPartition->NeedsCheck = TRUE;
2823
2824 if (PartitionList->SystemPartition != InstallPartition)
2825 {
2826 /* The system partition is separate, so it had better be formatted! */
2827 ASSERT((PartitionList->SystemPartition->FormatState == Preformatted) ||
2828 (PartitionList->SystemPartition->FormatState == Formatted));
2829
2830 /* Require a filesystem check on the system partition too */
2831 PartitionList->SystemPartition->NeedsCheck = TRUE;
2832 }
2833
2834 FormatState = FormatInstallPartition;
2835 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2836 }
2837 break;
2838 }
2839
2840 case FormatSystemPartition:
2841 {
2842 TempPartition = InstallPartition;
2843 TempPartition->NeedsCheck = TRUE;
2844
2845 FormatState = FormatInstallPartition;
2846 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2847 break;
2848 }
2849
2850 case FormatInstallPartition:
2851 case FormatOtherPartition:
2852 {
2853 if (GetNextUnformattedPartition(PartitionList,
2854 NULL,
2855 &TempPartition))
2856 {
2857 FormatState = FormatOtherPartition;
2858 TempPartition->NeedsCheck = TRUE;
2859
2860 if (FormatState == FormatInstallPartition)
2861 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2862 else
2863 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2864 }
2865 else
2866 {
2867 FormatState = FormatDone;
2868
2869 if (FormatState == FormatInstallPartition)
2870 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2871 else
2872 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2873
2874 return CHECK_FILE_SYSTEM_PAGE;
2875 }
2876 break;
2877 }
2878
2879 case FormatDone:
2880 {
2881 DPRINT1("FormatState: FormatDone\n");
2882 return CHECK_FILE_SYSTEM_PAGE;
2883 }
2884
2885 default:
2886 {
2887 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2888 /* FIXME: show an error dialog */
2889 return QUIT_PAGE;
2890 }
2891 }
2892
2893 PartEntry = TempPartition;
2894 DiskEntry = TempPartition->DiskEntry;
2895
2896 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
2897
2898 /* Adjust disk size */
2899 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2900 if (DiskSize >= 10 * GB) /* 10 GB */
2901 {
2902 DiskSize = DiskSize / GB;
2903 DiskUnit = MUIGetString(STRING_GB);
2904 }
2905 else
2906 {
2907 DiskSize = DiskSize / MB;
2908 DiskUnit = MUIGetString(STRING_MB);
2909 }
2910
2911 /* Adjust partition size */
2912 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2913 if (PartSize >= 10 * GB) /* 10 GB */
2914 {
2915 PartSize = PartSize / GB;
2916 PartUnit = MUIGetString(STRING_GB);
2917 }
2918 else
2919 {
2920 PartSize = PartSize / MB;
2921 PartUnit = MUIGetString(STRING_MB);
2922 }
2923
2924 /* Adjust partition type */
2925 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2926 PartTypeString,
2927 ARRAYSIZE(PartTypeString));
2928
2929 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2930
2931 if (PartEntry->AutoCreate)
2932 {
2933 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2934
2935 #if 0
2936 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2937 PartEntry->PartitionNumber,
2938 PartSize,
2939 PartUnit,
2940 PartTypeString);
2941 #endif
2942
2943 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
2944 DiskEntry->DiskNumber,
2945 DiskSize,
2946 DiskUnit,
2947 DiskEntry->Port,
2948 DiskEntry->Bus,
2949 DiskEntry->Id,
2950 &DiskEntry->DriverName,
2951 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2952 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2953 "RAW");
2954
2955 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2956
2957 PartEntry->AutoCreate = FALSE;
2958 }
2959 else if (PartEntry->New)
2960 {
2961 switch (FormatState)
2962 {
2963 case FormatSystemPartition:
2964 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2965 break;
2966
2967 case FormatInstallPartition:
2968 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2969 break;
2970
2971 case FormatOtherPartition:
2972 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2973 break;
2974
2975 default:
2976 break;
2977 }
2978
2979 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2980 }
2981 else
2982 {
2983 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2984
2985 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2986 {
2987 CONSOLE_PrintTextXY(8, 10,
2988 MUIGetString(STRING_HDDINFOUNK4),
2989 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2990 (PartEntry->DriveLetter == 0) ? '-' : ':',
2991 PartEntry->PartitionType,
2992 PartSize,
2993 PartUnit);
2994 }
2995 else
2996 {
2997 CONSOLE_PrintTextXY(8, 10,
2998 "%c%c %s %I64u %s",
2999 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
3000 (PartEntry->DriveLetter == 0) ? '-' : ':',
3001 PartTypeString,
3002 PartSize,
3003 PartUnit);
3004 }
3005
3006 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
3007 DiskEntry->DiskNumber,
3008 DiskSize,
3009 DiskUnit,
3010 DiskEntry->Port,
3011 DiskEntry->Bus,
3012 DiskEntry->Id,
3013 &DiskEntry->DriverName,
3014 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
3015 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
3016 "RAW");
3017 }
3018
3019 ASSERT(FileSystemList == NULL);
3020
3021 if (IsUnattendedSetup)
3022 {
3023 ASSERT(USetupData.FormatPartition);
3024
3025 switch (USetupData.FsType)
3026 {
3027 /* 1 is for BtrFS */
3028 case 1:
3029 DefaultFs = L"BTRFS";
3030 break;
3031
3032 /* If we don't understand input, default to FAT */
3033 default:
3034 DefaultFs = L"FAT";
3035 break;
3036 }
3037 }
3038 else
3039 {
3040 /* By default select the "FAT" file system */
3041 DefaultFs = L"FAT";
3042 }
3043
3044 /* Create the file system list */
3045 // TODO: Display only the FSes compatible with the selected partition!
3046 FileSystemList = CreateFileSystemList(6, 26,
3047 PartEntry->New ||
3048 PartEntry->FormatState == Unformatted,
3049 DefaultFs);
3050 if (FileSystemList == NULL)
3051 {
3052 /* FIXME: show an error dialog */
3053 return QUIT_PAGE;
3054 }
3055
3056 if (IsUnattendedSetup)
3057 {
3058 ASSERT(USetupData.FormatPartition);
3059 return FORMAT_PARTITION_PAGE;
3060 }
3061
3062 DrawFileSystemList(FileSystemList);
3063
3064 while (TRUE)
3065 {
3066 CONSOLE_ConInKey(Ir);
3067
3068 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3069 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3070 {
3071 if (ConfirmQuit(Ir))
3072 {
3073 /* Reset the filesystem list */
3074 ResetFileSystemList();
3075 return QUIT_PAGE;
3076 }
3077
3078 break;
3079 }
3080 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3081 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
3082 {
3083 /* Reset the formatter machine state */
3084 TempPartition = NULL;
3085 FormatState = Start;
3086
3087 /* Reset the filesystem list */
3088 ResetFileSystemList();
3089
3090 return SELECT_PARTITION_PAGE;
3091 }
3092 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3093 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
3094 {
3095 ScrollDownFileSystemList(FileSystemList);
3096 }
3097 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3098 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
3099 {
3100 ScrollUpFileSystemList(FileSystemList);
3101 }
3102 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
3103 {
3104 if (!FileSystemList->Selected->FileSystem)
3105 {
3106 ASSERT(!TempPartition->New && TempPartition->FormatState != Unformatted);
3107
3108 /*
3109 * Skip formatting this partition. We will also ignore
3110 * filesystem checks on it, unless it is either the system
3111 * or the installation partition.
3112 */
3113 if (TempPartition != PartitionList->SystemPartition &&
3114 TempPartition != InstallPartition)
3115 {
3116 PartEntry->NeedsCheck = FALSE;
3117 }
3118
3119 return SELECT_FILE_SYSTEM_PAGE;
3120 }
3121 else
3122 {
3123 /* Format this partition */
3124 return FORMAT_PARTITION_PAGE;
3125 }
3126 }
3127 }
3128
3129 FormatState = PreviousFormatState;
3130
3131 return SELECT_FILE_SYSTEM_PAGE;
3132 }
3133
3134
3135 /*
3136 * Displays the FormatPartitionPage.
3137 *
3138 * Next pages:
3139 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
3140 * SelectPartitionPage (At once)
3141 * QuitPage
3142 *
3143 * SIDEEFFECTS
3144 * Sets InstallPartition->FormatState
3145 * Sets USetupData.DestinationRootPath
3146 *
3147 * RETURNS
3148 * Number of the next page.
3149 */
3150 static PAGE_NUMBER
3151 FormatPartitionPage(PINPUT_RECORD Ir)
3152 {
3153 NTSTATUS Status;
3154 PPARTENTRY PartEntry;
3155 PDISKENTRY DiskEntry;
3156 PFILE_SYSTEM_ITEM SelectedFileSystem;
3157 UNICODE_STRING PartitionRootPath;
3158 WCHAR PathBuffer[MAX_PATH];
3159 CHAR Buffer[MAX_PATH];
3160
3161 #ifndef NDEBUG
3162 ULONG Line;
3163 ULONG i;
3164 PPARTITION_INFORMATION PartitionInfo;
3165 #endif
3166
3167 DPRINT("FormatPartitionPage()\n");
3168
3169 MUIDisplayPage(FORMAT_PARTITION_PAGE);
3170
3171 if (PartitionList == NULL || TempPartition == NULL)
3172 {
3173 /* FIXME: show an error dialog */
3174 return QUIT_PAGE;
3175 }
3176
3177 PartEntry = TempPartition;
3178 DiskEntry = TempPartition->DiskEntry;
3179
3180 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
3181
3182 SelectedFileSystem = FileSystemList->Selected;
3183 ASSERT(SelectedFileSystem && SelectedFileSystem->FileSystem);
3184
3185 while (TRUE)
3186 {
3187 if (!IsUnattendedSetup)
3188 CONSOLE_ConInKey(Ir);
3189
3190 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3191 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3192 {
3193 if (ConfirmQuit(Ir))
3194 {
3195 /* Reset the filesystem list */
3196 ResetFileSystemList();
3197 return QUIT_PAGE;
3198 }
3199
3200 break;
3201 }
3202 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
3203 {
3204 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3205
3206 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
3207 {
3208 /* FIXME: show an error dialog */
3209
3210 /* Reset the filesystem list */
3211 ResetFileSystemList();
3212
3213 return QUIT_PAGE;
3214 }
3215
3216 #ifndef NDEBUG
3217 CONSOLE_PrintTextXY(6, 12,
3218 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3219 DiskEntry->Cylinders,
3220 DiskEntry->TracksPerCylinder,
3221 DiskEntry->SectorsPerTrack,
3222 DiskEntry->BytesPerSector,
3223 DiskEntry->Dirty ? '*' : ' ');
3224
3225 Line = 13;
3226
3227 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
3228 {
3229 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
3230
3231 CONSOLE_PrintTextXY(6, Line,
3232 "%2u: %2lu %c %12I64u %12I64u %02x",
3233 i,
3234 PartitionInfo->PartitionNumber,
3235 PartitionInfo->BootIndicator ? 'A' : '-',
3236 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
3237 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
3238 PartitionInfo->PartitionType);
3239 Line++;
3240 }
3241 #endif
3242
3243 /* Commit the partition changes to the disk */
3244 Status = WritePartitions(DiskEntry);
3245 if (!NT_SUCCESS(Status))
3246 {
3247 DPRINT1("WritePartitions(disk %lu) failed, Status 0x%08lx\n",
3248 DiskEntry->DiskNumber, Status);
3249
3250 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3251
3252 /* Reset the filesystem list */
3253 ResetFileSystemList();
3254
3255 return QUIT_PAGE;
3256 }
3257
3258 /* Set PartitionRootPath */
3259 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3260 L"\\Device\\Harddisk%lu\\Partition%lu",
3261 DiskEntry->DiskNumber,
3262 PartEntry->PartitionNumber);
3263 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3264 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3265
3266 /* Format the partition */
3267 Status = FormatPartition(&PartitionRootPath,
3268 SelectedFileSystem->FileSystem,
3269 SelectedFileSystem->QuickFormat);
3270 if (Status == STATUS_NOT_SUPPORTED)
3271 {
3272 sprintf(Buffer,
3273 "Setup is currently unable to format a partition in %S.\n"
3274 "\n"
3275 " \x07 Press ENTER to continue Setup.\n"
3276 " \x07 Press F3 to quit Setup.",
3277 SelectedFileSystem->FileSystem);
3278
3279 PopupError(Buffer,
3280 MUIGetString(STRING_QUITCONTINUE),
3281 NULL, POPUP_WAIT_NONE);
3282
3283 while (TRUE)
3284 {
3285 CONSOLE_ConInKey(Ir);
3286
3287 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3288 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3289 {
3290 if (ConfirmQuit(Ir))
3291 {
3292 /* Reset the filesystem list */
3293 ResetFileSystemList();
3294 return QUIT_PAGE;
3295 }
3296 else
3297 {
3298 return SELECT_FILE_SYSTEM_PAGE;
3299 }
3300 }
3301 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3302 {
3303 return SELECT_FILE_SYSTEM_PAGE;
3304 }
3305 }
3306 }
3307 else if (!NT_SUCCESS(Status))
3308 {
3309 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3310 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3311
3312 /* Reset the filesystem list */
3313 ResetFileSystemList();
3314
3315 return QUIT_PAGE;
3316 }
3317
3318 //
3319 // TODO: Here, call a partlist.c function that update the actual FS name
3320 // and the label fields of the volume.
3321 //
3322 PartEntry->FormatState = Formatted;
3323 // PartEntry->FileSystem = FileSystem;
3324 PartEntry->New = FALSE;
3325
3326 #ifndef NDEBUG
3327 CONSOLE_SetStatusText(" Done. Press any key ...");
3328 CONSOLE_ConInKey(Ir);
3329 #endif
3330
3331 return SELECT_FILE_SYSTEM_PAGE;
3332 }
3333 }
3334
3335 return FORMAT_PARTITION_PAGE;
3336 }
3337
3338
3339 /*
3340 * Displays the CheckFileSystemPage.
3341 *
3342 * Next pages:
3343 * InstallDirectoryPage (At once)
3344 * QuitPage
3345 *
3346 * SIDEEFFECTS
3347 * Inits or reloads FileSystemList
3348 *
3349 * RETURNS
3350 * Number of the next page.
3351 */
3352 static PAGE_NUMBER
3353 CheckFileSystemPage(PINPUT_RECORD Ir)
3354 {
3355 NTSTATUS Status;
3356 PDISKENTRY DiskEntry;
3357 PPARTENTRY PartEntry;
3358 UNICODE_STRING PartitionRootPath;
3359 WCHAR PathBuffer[MAX_PATH];
3360 CHAR Buffer[MAX_PATH];
3361
3362 if (PartitionList == NULL)
3363 {
3364 /* FIXME: show an error dialog */
3365 return QUIT_PAGE;
3366 }
3367
3368 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3369 {
3370 return INSTALL_DIRECTORY_PAGE;
3371 }
3372
3373 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
3374
3375 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3376
3377 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3378
3379 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystem: %S\n",
3380 PartEntry->PartitionType, (*PartEntry->FileSystem ? PartEntry->FileSystem : L"n/a"));
3381
3382 /* HACK: Do not try to check a partition with an unknown filesystem */
3383 if (!*PartEntry->FileSystem)
3384 {
3385 PartEntry->NeedsCheck = FALSE;
3386 return CHECK_FILE_SYSTEM_PAGE;
3387 }
3388
3389 /* Set PartitionRootPath */
3390 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3391 L"\\Device\\Harddisk%lu\\Partition%lu",
3392 DiskEntry->DiskNumber,
3393 PartEntry->PartitionNumber);
3394 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3395 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3396
3397 /* Check the partition */
3398 Status = ChkdskPartition(&PartitionRootPath, PartEntry->FileSystem);
3399 if (Status == STATUS_NOT_SUPPORTED)
3400 {
3401 /*
3402 * Partition checking is not supported with the current filesystem,
3403 * so disable FS checks on it.
3404 */
3405 PartEntry->NeedsCheck = FALSE;
3406
3407 RtlStringCbPrintfA(Buffer,
3408 sizeof(Buffer),
3409 "Setup is currently unable to check a partition formatted in %S.\n"
3410 "\n"
3411 " \x07 Press ENTER to continue Setup.\n"
3412 " \x07 Press F3 to quit Setup.",
3413 PartEntry->FileSystem);
3414
3415 PopupError(Buffer,
3416 MUIGetString(STRING_QUITCONTINUE),
3417 NULL, POPUP_WAIT_NONE);
3418
3419 while (TRUE)
3420 {
3421 CONSOLE_ConInKey(Ir);
3422
3423 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3424 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3425 {
3426 if (ConfirmQuit(Ir))
3427 return QUIT_PAGE;
3428 else
3429 return CHECK_FILE_SYSTEM_PAGE;
3430 }
3431 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3432 {
3433 return CHECK_FILE_SYSTEM_PAGE;
3434 }
3435 }
3436 }
3437 else if (!NT_SUCCESS(Status))
3438 {
3439 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3440 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3441 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3442 "(Status 0x%08lx).\n", Status);
3443 PopupError(Buffer,
3444 // MUIGetString(STRING_REBOOTCOMPUTER),
3445 MUIGetString(STRING_CONTINUE),
3446 Ir, POPUP_WAIT_ENTER);
3447
3448 // return QUIT_PAGE;
3449 }
3450
3451 PartEntry->NeedsCheck = FALSE;
3452 return CHECK_FILE_SYSTEM_PAGE;
3453 }
3454
3455
3456 static NTSTATUS
3457 BuildInstallPaths(
3458 IN PCWSTR InstallDir,
3459 IN PPARTENTRY PartEntry)
3460 {
3461 NTSTATUS Status;
3462
3463 Status = InitDestinationPaths(&USetupData, InstallDir, PartEntry);
3464
3465 if (!NT_SUCCESS(Status))
3466 {
3467 DPRINT1("InitDestinationPaths() failed with status 0x%08lx\n", Status);
3468 return Status;
3469 }
3470
3471 /* Initialize DestinationDriveLetter */
3472 DestinationDriveLetter = PartEntry->DriveLetter;
3473
3474 return STATUS_SUCCESS;
3475 }
3476
3477
3478 static BOOLEAN
3479 IsValidPath(
3480 IN PCWSTR InstallDir)
3481 {
3482 UINT i, Length;
3483
3484 Length = wcslen(InstallDir);
3485
3486 // TODO: Add check for 8.3 too.
3487
3488 /* Path must be at least 2 characters long */
3489 // if (Length < 2)
3490 // return FALSE;
3491
3492 /* Path must start with a backslash */
3493 // if (InstallDir[0] != L'\\')
3494 // return FALSE;
3495
3496 /* Path must not end with a backslash */
3497 if (InstallDir[Length - 1] == L'\\')
3498 return FALSE;
3499
3500 /* Path must not contain whitespace characters */
3501 for (i = 0; i < Length; i++)
3502 {
3503 if (iswspace(InstallDir[i]))
3504 return FALSE;
3505 }
3506
3507 /* Path component must not end with a dot */
3508 for (i = 0; i < Length; i++)
3509 {
3510 if (InstallDir[i] == L'\\' && i > 0)
3511 {
3512 if (InstallDir[i - 1] == L'.')
3513 return FALSE;
3514 }
3515 }
3516
3517 if (InstallDir[Length - 1] == L'.')
3518 return FALSE;
3519
3520 return TRUE;
3521 }
3522
3523
3524 /*
3525 * Displays the InstallDirectoryPage.
3526 *
3527 * Next pages:
3528 * PrepareCopyPage
3529 * QuitPage
3530 *
3531 * RETURNS
3532 * Number of the next page.
3533 */
3534 static PAGE_NUMBER
3535 InstallDirectoryPage(PINPUT_RECORD Ir)
3536 {
3537 NTSTATUS Status;
3538 ULONG Length, Pos;
3539 WCHAR c;
3540 WCHAR InstallDir[MAX_PATH];
3541
3542 /* We do not need the filesystem list anymore */
3543 ResetFileSystemList();
3544
3545 if (PartitionList == NULL || InstallPartition == NULL)
3546 {
3547 /* FIXME: show an error dialog */
3548 return QUIT_PAGE;
3549 }
3550
3551 // if (IsUnattendedSetup)
3552 if (RepairUpdateFlag)
3553 wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
3554 else if (USetupData.InstallationDirectory[0])
3555 wcscpy(InstallDir, USetupData.InstallationDirectory);
3556 else
3557 wcscpy(InstallDir, L"\\ReactOS");
3558
3559 /*
3560 * Check the validity of the predefined 'InstallDir'. If we are either
3561 * in unattended setup or in update/repair mode, and the installation path
3562 * is valid, just perform the installation. Otherwise (either in the case
3563 * of an invalid path, or we are in regular setup), display the UI and allow
3564 * the user to specify a new installation path.
3565 */
3566 if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
3567 {
3568 Status = BuildInstallPaths(InstallDir, InstallPartition);
3569 if (!NT_SUCCESS(Status))
3570 {
3571 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status);
3572 PopupError("Failed to build the installation paths for the ReactOS installation directory!",
3573 MUIGetString(STRING_CONTINUE),
3574 Ir, POPUP_WAIT_ENTER);
3575 return QUIT_PAGE;
3576 }
3577
3578 /*
3579 * Check whether the user attempts to install ReactOS within the
3580 * installation source directory, or in a subdirectory thereof.
3581 * If so, fail with an error.
3582 */
3583 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3584 {
3585 PopupError("You cannot install ReactOS within the installation source directory!",
3586 MUIGetString(STRING_CONTINUE),
3587 Ir, POPUP_WAIT_ENTER);
3588 return INSTALL_DIRECTORY_PAGE;
3589 }
3590
3591 return PREPARE_COPY_PAGE;
3592 }
3593
3594 Length = wcslen(InstallDir);
3595 Pos = Length;
3596
3597 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3598 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3599 CONSOLE_SetCursorXY(8 + Pos, 11);
3600 CONSOLE_SetCursorType(TRUE, TRUE);
3601
3602 while (TRUE)
3603 {
3604 CONSOLE_ConInKey(Ir);
3605
3606 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3607 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3608 {
3609 CONSOLE_SetCursorType(TRUE, FALSE);
3610
3611 if (ConfirmQuit(Ir))
3612 return QUIT_PAGE;
3613
3614 CONSOLE_SetCursorType(TRUE, TRUE);
3615 break;
3616 }
3617 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3618 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3619 {
3620 if (Pos < Length)
3621 {
3622 memmove(&InstallDir[Pos],
3623 &InstallDir[Pos + 1],
3624 (Length - Pos - 1) * sizeof(WCHAR));
3625 InstallDir[Length - 1] = UNICODE_NULL;
3626
3627 Length--;
3628 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3629 CONSOLE_SetCursorXY(8 + Pos, 11);
3630 }
3631 }
3632 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3633 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3634 {
3635 Pos = 0;
3636 CONSOLE_SetCursorXY(8 + Pos, 11);
3637 }
3638 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3639 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3640 {
3641 Pos = Length;
3642 CONSOLE_SetCursorXY(8 + Pos, 11);
3643 }
3644 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3645 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3646 {
3647 if (Pos > 0)
3648 {
3649 Pos--;
3650 CONSOLE_SetCursorXY(8 + Pos, 11);
3651 }
3652 }
3653 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3654 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3655 {
3656 if (Pos < Length)
3657 {
3658 Pos++;
3659 CONSOLE_SetCursorXY(8 + Pos, 11);
3660 }
3661 }
3662 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3663 {
3664 CONSOLE_SetCursorType(TRUE, FALSE);
3665
3666 /*
3667 * Check for the validity of the installation directory and pop up
3668 * an error if it is not the case. Then the user can fix its input.
3669 */
3670 if (!IsValidPath(InstallDir))
3671 {
3672 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3673 return INSTALL_DIRECTORY_PAGE;
3674 }
3675
3676 Status = BuildInstallPaths(InstallDir, InstallPartition);
3677 if (!NT_SUCCESS(Status))
3678 {
3679 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status);
3680 PopupError("Failed to build the installation paths for the ReactOS installation directory!",
3681 MUIGetString(STRING_CONTINUE),
3682 Ir, POPUP_WAIT_ENTER);
3683 return QUIT_PAGE;
3684 }
3685
3686 /*
3687 * Check whether the user attempts to install ReactOS within the
3688 * installation source directory, or in a subdirectory thereof.
3689 * If so, fail with an error.
3690 */
3691 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3692 {
3693 PopupError("You cannot install ReactOS within the installation source directory!",
3694 MUIGetString(STRING_CONTINUE),
3695 Ir, POPUP_WAIT_ENTER);
3696 return INSTALL_DIRECTORY_PAGE;
3697 }
3698
3699 return PREPARE_COPY_PAGE;
3700 }
3701 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3702 {
3703 if (Pos > 0)
3704 {
3705 if (Pos < Length)
3706 memmove(&InstallDir[Pos - 1],
3707 &InstallDir[Pos],
3708 (Length - Pos) * sizeof(WCHAR));
3709 InstallDir[Length - 1] = UNICODE_NULL;
3710
3711 Pos--;
3712 Length--;
3713 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3714 CONSOLE_SetCursorXY(8 + Pos, 11);
3715 }
3716 }
3717 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3718 {
3719 if (Length < 50)
3720 {
3721 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
3722 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3723 {
3724 if (Pos < Length)
3725 memmove(&InstallDir[Pos + 1],
3726 &InstallDir[Pos],
3727 (Length - Pos) * sizeof(WCHAR));
3728 InstallDir[Length + 1] = UNICODE_NULL;
3729 InstallDir[Pos] = c;
3730
3731 Pos++;
3732 Length++;
3733 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3734 CONSOLE_SetCursorXY(8 + Pos, 11);
3735 }
3736 }
3737 }
3738 }
3739
3740 return INSTALL_DIRECTORY_PAGE;
3741 }
3742
3743
3744 // PSETUP_ERROR_ROUTINE
3745 static VOID
3746 __cdecl
3747 USetupErrorRoutine(
3748 IN PUSETUP_DATA pSetupData,
3749 ...)
3750 {
3751 INPUT_RECORD Ir;
3752 va_list arg_ptr;
3753
3754 va_start(arg_ptr, pSetupData);
3755
3756 if (pSetupData->LastErrorNumber >= ERROR_SUCCESS &&
3757 pSetupData->LastErrorNumber < ERROR_LAST_ERROR_CODE)
3758 {
3759 // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
3760 MUIDisplayErrorV(pSetupData->LastErrorNumber, &Ir, POPUP_WAIT_ENTER, arg_ptr);
3761 }
3762
3763 va_end(arg_ptr);
3764 }
3765
3766 /*
3767 * Displays the PrepareCopyPage.
3768 *
3769 * Next pages:
3770 * FileCopyPage(At once)
3771 * QuitPage
3772 *
3773 * SIDEEFFECTS
3774 * Calls PrepareFileCopy
3775 *
3776 * RETURNS
3777 * Number of the next page.
3778 */
3779 static PAGE_NUMBER
3780 PrepareCopyPage(PINPUT_RECORD Ir)
3781 {
3782 // ERROR_NUMBER ErrorNumber;
3783 BOOLEAN Success;
3784
3785 MUIDisplayPage(PREPARE_COPY_PAGE);
3786
3787 /* ErrorNumber = */ Success = PrepareFileCopy(&USetupData, NULL);
3788 if (/*ErrorNumber != ERROR_SUCCESS*/ !Success)
3789 {
3790 // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER);
3791 return QUIT_PAGE;
3792 }
3793
3794 return FILE_COPY_PAGE;
3795 }
3796
3797 typedef struct _COPYCONTEXT
3798 {
3799 ULONG TotalOperations;
3800 ULONG CompletedOperations;
3801 PPROGRESSBAR ProgressBar;
3802 PPROGRESSBAR MemoryBars[4];
3803 } COPYCONTEXT, *PCOPYCONTEXT;
3804
3805 static VOID
3806 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3807 IN BOOLEAN First)
3808 {
3809 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3810
3811 /* Get the memory information from the system */
3812 NtQuerySystemInformation(SystemPerformanceInformation,
3813 &PerfInfo,
3814 sizeof(PerfInfo),
3815 NULL);
3816
3817 /* Check if this is initial setup */
3818 if (First)
3819 {
3820 /* Set maximum limits to be total RAM pages */
3821 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
3822 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
3823 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
3824 }
3825
3826 /* Set current values */
3827 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
3828 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
3829 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
3830 }
3831
3832 static UINT
3833 CALLBACK
3834 FileCopyCallback(PVOID Context,
3835 UINT Notification,
3836 UINT_PTR Param1,
3837 UINT_PTR Param2)
3838 {
3839 PCOPYCONTEXT CopyContext = (PCOPYCONTEXT)Context;
3840 PFILEPATHS_W FilePathInfo;
3841 PCWSTR SrcFileName, DstFileName;
3842
3843 switch (Notification)
3844 {
3845 case SPFILENOTIFY_STARTSUBQUEUE:
3846 {
3847 CopyContext->TotalOperations = (ULONG)Param2;
3848 CopyContext->CompletedOperations = 0;
3849 ProgressSetStepCount(CopyContext->ProgressBar,
3850 CopyContext->TotalOperations);
3851 SetupUpdateMemoryInfo(CopyContext, TRUE);
3852 break;
3853 }
3854
3855 case SPFILENOTIFY_STARTDELETE:
3856 case SPFILENOTIFY_STARTRENAME:
3857 case SPFILENOTIFY_STARTCOPY:
3858 {
3859 FilePathInfo = (PFILEPATHS_W)Param1;
3860
3861 if (Notification == SPFILENOTIFY_STARTDELETE)
3862 {
3863 /* Display delete message */
3864 ASSERT(Param2 == FILEOP_DELETE);
3865
3866 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3867 if (DstFileName) ++DstFileName;
3868 else DstFileName = FilePathInfo->Target;
3869
3870 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING),
3871 DstFileName);
3872 }
3873 else if (Notification == SPFILENOTIFY_STARTRENAME)
3874 {
3875 /* Display move/rename message */
3876 ASSERT(Param2 == FILEOP_RENAME);
3877
3878 SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
3879 if (SrcFileName) ++SrcFileName;
3880 else SrcFileName = FilePathInfo->Source;
3881
3882 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3883 if (DstFileName) ++DstFileName;
3884 else DstFileName = FilePathInfo->Target;
3885
3886 if (!wcsicmp(SrcFileName, DstFileName))
3887 Param2 = STRING_MOVING;
3888 else
3889 Param2 = STRING_RENAMING;
3890
3891 CONSOLE_SetStatusText(MUIGetString(Param2),
3892 SrcFileName, DstFileName);
3893 }
3894 else if (Notification == SPFILENOTIFY_STARTCOPY)
3895 {
3896 /* Display copy message */
3897 ASSERT(Param2 == FILEOP_COPY);
3898
3899 /* NOTE: When extracting from CABs the Source is the CAB name */
3900 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3901 if (DstFileName) ++DstFileName;
3902 else DstFileName = FilePathInfo->Target;
3903
3904 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING),
3905 DstFileName);
3906 }
3907
3908 SetupUpdateMemoryInfo(CopyContext, FALSE);
3909 break;
3910 }
3911
3912 case SPFILENOTIFY_COPYERROR:
3913 {
3914 FilePathInfo = (PFILEPATHS_W)Param1;
3915
3916 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
3917 FilePathInfo->Target, FilePathInfo->Win32Error);
3918 return FILEOP_SKIP;
3919 }
3920
3921 case SPFILENOTIFY_ENDDELETE:
3922 case SPFILENOTIFY_ENDRENAME:
3923 case SPFILENOTIFY_ENDCOPY:
3924 {
3925 CopyContext->CompletedOperations++;
3926
3927 /* SYSREG checkpoint */
3928 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations)
3929 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3930
3931 ProgressNextStep(CopyContext->ProgressBar);
3932 SetupUpdateMemoryInfo(CopyContext, FALSE);
3933 break;
3934 }
3935 }
3936
3937 return FILEOP_DOIT;
3938 }
3939
3940
3941 /*
3942 * Displays the FileCopyPage.
3943 *
3944 * Next pages:
3945 * RegistryPage(At once)
3946 *
3947 * SIDEEFFECTS
3948 * Calls DoFileCopy
3949 *
3950 * RETURNS
3951 * Number of the next page.
3952 */
3953 static PAGE_NUMBER
3954 FileCopyPage(PINPUT_RECORD Ir)
3955 {
3956 COPYCONTEXT CopyContext;
3957 UINT MemBarWidth;
3958
3959 MUIDisplayPage(FILE_COPY_PAGE);
3960
3961 /* Create context for the copy process */
3962 CopyContext.TotalOperations = 0;
3963 CopyContext.CompletedOperations = 0;
3964
3965 /* Create the progress bar as well */
3966 CopyContext.ProgressBar = CreateProgressBar(13,
3967 26,
3968 xScreen - 13,
3969 yScreen - 20,
3970 10,
3971 24,
3972 TRUE,
3973 MUIGetString(STRING_SETUPCOPYINGFILES));
3974
3975 // fit memory bars to screen width, distribute them uniform
3976 MemBarWidth = (xScreen - 26) / 5;
3977 MemBarWidth -= MemBarWidth % 2; // make even
3978 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3979 /* Create the paged pool progress bar */
3980 CopyContext.MemoryBars[0] = CreateProgressBar(13,
3981 40,
3982 13 + MemBarWidth,
3983 43,
3984 13,
3985 44,
3986 FALSE,
3987 "Kernel Pool");
3988
3989 /* Create the non paged pool progress bar */
3990 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (MemBarWidth / 2),
3991 40,
3992 (xScreen / 2) + (MemBarWidth / 2),
3993 43,
3994 (xScreen / 2)- (MemBarWidth / 2),
3995 44,
3996 FALSE,
3997 "Kernel Cache");
3998
3999 /* Create the global memory progress bar */
4000 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - MemBarWidth,
4001 40,
4002 xScreen - 13,
4003 43,
4004 xScreen - 13 - MemBarWidth,
4005 44,
4006 FALSE,
4007 "Free Memory");
4008
4009 /* Do the file copying */
4010 DoFileCopy(&USetupData, FileCopyCallback, &CopyContext);
4011
4012 /* If we get here, we're done, so cleanup the progress bar */
4013 DestroyProgressBar(CopyContext.ProgressBar);
4014 DestroyProgressBar(CopyContext.MemoryBars[0]);
4015 DestroyProgressBar(CopyContext.MemoryBars[1]);
4016 DestroyProgressBar(CopyContext.MemoryBars[2]);
4017
4018 /* Create the $winnt$.inf file */
4019 InstallSetupInfFile(&USetupData);
4020
4021 /* Go display the next page */
4022 return REGISTRY_PAGE;
4023 }
4024
4025
4026 static VOID
4027 __cdecl
4028 RegistryStatus(IN REGISTRY_STATUS RegStatus, ...)
4029 {
4030 /* WARNING: Please keep this lookup table in sync with the resources! */
4031 static const UINT StringIDs[] =
4032 {
4033 STRING_DONE, /* Success */
4034 STRING_REGHIVEUPDATE, /* RegHiveUpdate */
4035 STRING_IMPORTFILE, /* ImportRegHive */
4036 STRING_DISPLAYSETTINGSUPDATE, /* DisplaySettingsUpdate */
4037 STRING_LOCALESETTINGSUPDATE, /* LocaleSettingsUpdate */
4038 STRING_ADDKBLAYOUTS, /* KeybLayouts */
4039 STRING_KEYBOARDSETTINGSUPDATE, /* KeybSettingsUpdate */
4040 STRING_CODEPAGEINFOUPDATE, /* CodePageInfoUpdate */
4041 };
4042
4043 va_list args;
4044
4045 if (RegStatus < ARRAYSIZE(StringIDs))
4046 {
4047 va_start(args, RegStatus);
4048 CONSOLE_SetStatusTextV(MUIGetString(StringIDs[RegStatus]), args);
4049 va_end(args);
4050 }
4051 else
4052 {
4053 CONSOLE_SetStatusText("Unknown status %d", RegStatus);
4054 }
4055 }
4056
4057 /*
4058 * Displays the RegistryPage.
4059 *
4060 * Next pages:
4061 * SuccessPage (if RepairUpdate)
4062 * BootLoaderPage (default)
4063 * QuitPage
4064 *
4065 * SIDEEFFECTS
4066 * Calls UpdateRegistry
4067 *
4068 * RETURNS
4069 * Number of the next page.
4070 */
4071 static PAGE_NUMBER
4072 RegistryPage(PINPUT_RECORD Ir)
4073 {
4074 ULONG Error;
4075
4076 MUIDisplayPage(REGISTRY_PAGE);
4077
4078 Error = UpdateRegistry(&USetupData,
4079 RepairUpdateFlag,
4080 PartitionList,
4081 DestinationDriveLetter,
4082 SelectedLanguageId,
4083 RegistryStatus);
4084 if (Error != ERROR_SUCCESS)
4085 {
4086 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
4087 return QUIT_PAGE;
4088 }
4089 else
4090 {
4091 CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
4092 return BOOT_LOADER_PAGE;
4093 }
4094 }
4095
4096
4097 /*
4098 * Displays the BootLoaderPage.
4099 *
4100 * Next pages:
4101 * SuccessPage (if RepairUpdate)
4102 * BootLoaderHarddiskMbrPage
4103 * BootLoaderHarddiskVbrPage
4104 * BootLoaderFloppyPage
4105 * SuccessPage
4106 * QuitPage
4107 *
4108 * SIDEEFFECTS
4109 * Calls RegInitializeRegistry
4110 * Calls ImportRegistryFile
4111 * Calls SetDefaultPagefile
4112 * Calls SetMountedDeviceValues
4113 *
4114 * RETURNS
4115 * Number of the next page.
4116 */
4117 static PAGE_NUMBER
4118 BootLoaderPage(PINPUT_RECORD Ir)
4119 {
4120 UCHAR PartitionType;
4121 BOOLEAN InstallOnFloppy;
4122 USHORT Line = 12;
4123 WCHAR PathBuffer[MAX_PATH];
4124
4125 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4126
4127 ASSERT(PartitionList->SystemPartition->IsPartitioned && PartitionList->SystemPartition->PartitionNumber != 0);
4128
4129 RtlFreeUnicodeString(&USetupData.SystemRootPath);
4130 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
4131 L"\\Device\\Harddisk%lu\\Partition%lu\\",
4132 PartitionList->SystemPartition->DiskEntry->DiskNumber,
4133 PartitionList->SystemPartition->PartitionNumber);
4134 RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer);
4135 DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath);
4136
4137 PartitionType = PartitionList->SystemPartition->PartitionType;
4138
4139 /* For unattended setup, skip MBR installation or install on floppy if needed */
4140 if (IsUnattendedSetup)
4141 {
4142 if ((USetupData.MBRInstallType == 0) ||
4143 (USetupData.MBRInstallType == 1))
4144 {
4145 goto Quit;
4146 }
4147 }
4148
4149 /*
4150 * We may install an MBR or VBR, but before that, check whether
4151 * we need to actually install the VBR on floppy.
4152 */
4153 if (PartitionType == PARTITION_ENTRY_UNUSED)
4154 {
4155 DPRINT("Error: system partition invalid (unused)\n");
4156 InstallOnFloppy = TRUE;
4157 }
4158 else if (PartitionType == PARTITION_OS2BOOTMGR)
4159 {
4160 /* OS/2 boot manager partition */
4161 DPRINT("Found OS/2 boot manager partition\n");
4162 InstallOnFloppy = TRUE;
4163 }
4164 else if (PartitionType == PARTITION_LINUX)
4165 {
4166 /* Linux partition */
4167 DPRINT("Found Linux native partition (ext2/ext3/ReiserFS/BTRFS/etc)\n");
4168 InstallOnFloppy = FALSE;
4169 }
4170 else if (PartitionType == PARTITION_IFS)
4171 {
4172 /* NTFS partition */
4173 DPRINT("Found NTFS partition\n");
4174
4175 // FIXME: Make it FALSE when we'll support NTFS installation!
4176 InstallOnFloppy = TRUE;
4177 }
4178 else if ((PartitionType == PARTITION_FAT_12) ||
4179 (PartitionType == PARTITION_FAT_16) ||
4180 (PartitionType == PARTITION_HUGE) ||
4181 (PartitionType == PARTITION_XINT13) ||
4182 (PartitionType == PARTITION_FAT32) ||
4183 (PartitionType == PARTITION_FAT32_XINT13))
4184 {
4185 DPRINT("Found FAT partition\n");
4186 InstallOnFloppy = FALSE;
4187 }
4188 else
4189 {
4190 /* Unknown partition */
4191 DPRINT("Unknown partition found\n");
4192 InstallOnFloppy = TRUE;
4193 }
4194
4195 /* We should install on floppy */
4196 if (InstallOnFloppy)
4197 {
4198 USetupData.MBRInstallType = 1;
4199 goto Quit;
4200 }
4201
4202 /* Is it an unattended install on hdd? */
4203 if (IsUnattendedSetup)
4204 {
4205 if ((USetupData.MBRInstallType == 2) ||
4206 (USetupData.MBRInstallType == 3))
4207 {
4208 goto Quit;
4209 }
4210 }
4211
4212 MUIDisplayPage(BOOT_LOADER_PAGE);
4213 CONSOLE_InvertTextXY(8, Line, 60, 1);
4214
4215 while (TRUE)
4216 {
4217 CONSOLE_ConInKey(Ir);
4218
4219 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4220 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
4221 {
4222 CONSOLE_NormalTextXY(8, Line, 60, 1);
4223
4224 Line++;
4225 if (Line < 12)
4226 Line = 15;
4227
4228 if (Line > 15)
4229 Line = 12;
4230
4231 CONSOLE_InvertTextXY(8, Line, 60, 1);
4232 }
4233 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4234 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
4235 {
4236 CONSOLE_NormalTextXY(8, Line, 60, 1);
4237
4238 Line--;
4239 if (Line < 12)
4240 Line = 15;
4241
4242 if (Line > 15)
4243 Line = 12;
4244
4245 CONSOLE_InvertTextXY(8, Line, 60, 1);
4246 }
4247 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4248 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
4249 {
4250 CONSOLE_NormalTextXY(8, Line, 60, 1);
4251
4252 Line = 12;
4253
4254 CONSOLE_InvertTextXY(8, Line, 60, 1);
4255 }
4256 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4257 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
4258 {
4259 CONSOLE_NormalTextXY(8, Line, 60, 1);
4260
4261 Line = 15;
4262
4263 CONSOLE_InvertTextXY(8, Line, 60, 1);
4264 }
4265 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4266 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4267 {
4268 if (ConfirmQuit(Ir))
4269 return QUIT_PAGE;
4270
4271 break;
4272 }
4273 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4274 {
4275 if (Line == 12)
4276 {
4277 /* Install on both MBR and VBR */
4278 USetupData.MBRInstallType = 2;
4279 break;
4280 }
4281 else if (Line == 13)
4282 {
4283 /* Install on VBR only */
4284 USetupData.MBRInstallType = 3;
4285 break;
4286 }
4287 else if (Line == 14)
4288 {
4289 /* Install on floppy */
4290 USetupData.MBRInstallType = 1;
4291 break;
4292 }
4293 else if (Line == 15)
4294 {
4295 /* Skip MBR installation */
4296 USetupData.MBRInstallType = 0;
4297 break;
4298 }
4299
4300 return BOOT_LOADER_PAGE;
4301 }
4302 }
4303
4304 Quit:
4305 switch (USetupData.MBRInstallType)
4306 {
4307 /* Skip MBR installation */
4308 case 0:
4309 return SUCCESS_PAGE;
4310
4311 /* Install on floppy */
4312 case 1:
4313 return BOOT_LOADER_FLOPPY_PAGE;
4314
4315 /* Install on both MBR and VBR */
4316 case 2:
4317 return BOOT_LOADER_HARDDISK_MBR_PAGE;
4318
4319 /* Install on VBR only */
4320 case 3:
4321 return BOOT_LOADER_HARDDISK_VBR_PAGE;
4322 }
4323
4324 return BOOT_LOADER_PAGE;
4325 }
4326
4327
4328 /*
4329 * Displays the BootLoaderFloppyPage.
4330 *
4331 * Next pages:
4332 * SuccessPage (At once)
4333 * QuitPage
4334 *
4335 * SIDEEFFECTS
4336 * Calls InstallFatBootcodeToFloppy()
4337 *
4338 * RETURNS
4339 * Number of the next page.
4340 */
4341 static PAGE_NUMBER
4342 BootLoaderFloppyPage(PINPUT_RECORD Ir)
4343 {
4344 NTSTATUS Status;
4345
4346 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE);
4347
4348 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4349
4350 while (TRUE)
4351 {
4352 CONSOLE_ConInKey(Ir);
4353
4354 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4355 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4356 {
4357 if (ConfirmQuit(Ir))
4358 return QUIT_PAGE;
4359
4360 break;
4361 }
4362 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4363 {
4364 Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath,
4365 &USetupData.DestinationArcPath);
4366 if (!NT_SUCCESS(Status))
4367 {
4368 if (Status == STATUS_DEVICE_NOT_READY)
4369 MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
4370
4371 /* TODO: Print error message */
4372 return BOOT_LOADER_FLOPPY_PAGE;
4373 }
4374
4375 return SUCCESS_PAGE;
4376 }
4377 }
4378
4379 return BOOT_LOADER_FLOPPY_PAGE;
4380 }
4381
4382
4383 /*
4384 * Displays the BootLoaderHarddiskVbrPage.
4385 *
4386 * Next pages:
4387 * SuccessPage (At once)
4388 * QuitPage
4389 *
4390 * SIDEEFFECTS
4391 * Calls InstallVBRToPartition()
4392 *
4393 * RETURNS
4394 * Number of the next page.
4395 */
4396 static PAGE_NUMBER
4397 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
4398 {
4399 NTSTATUS Status;
4400
4401 // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
4402 Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4403 &USetupData.SourceRootPath,
4404 &USetupData.DestinationArcPath,
4405 PartitionList->SystemPartition->PartitionType);
4406 if (!NT_SUCCESS(Status))
4407 {
4408 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER,
4409 PartitionList->SystemPartition->FileSystem);
4410 return QUIT_PAGE;
4411 }
4412
4413 return SUCCESS_PAGE;
4414 }
4415
4416
4417 /*
4418 * Displays the BootLoaderHarddiskMbrPage.
4419 *
4420 * Next pages:
4421 * SuccessPage (At once)
4422 * QuitPage
4423 *
4424 * SIDEEFFECTS
4425 * Calls InstallVBRToPartition()
4426 * Calls InstallMbrBootCodeToDisk()
4427 *
4428 * RETURNS
4429 * Number of the next page.
4430 */
4431 static PAGE_NUMBER
4432 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
4433 {
4434 NTSTATUS Status;
4435 WCHAR DestinationDevicePathBuffer[MAX_PATH];
4436
4437 /* Step 1: Write the VBR */
4438 // FIXME! We must not use the partition type, but instead use the partition FileSystem!!
4439 Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4440 &USetupData.SourceRootPath,
4441 &USetupData.DestinationArcPath,
4442 PartitionList->SystemPartition->PartitionType);
4443 if (!NT_SUCCESS(Status))
4444 {
4445 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER,
4446 PartitionList->SystemPartition->FileSystem);
4447 return QUIT_PAGE;
4448 }
4449
4450 /* Step 2: Write the MBR if the disk containing the system partition is not a super-floppy */
4451 if (!IsSuperFloppy(PartitionList->SystemPartition->DiskEntry))
4452 {
4453 RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
4454 L"\\Device\\Harddisk%d\\Partition0",
4455 PartitionList->SystemPartition->DiskEntry->DiskNumber);
4456 Status = InstallMbrBootCodeToDisk(&USetupData.SystemRootPath,
4457 &USetupData.SourceRootPath,
4458 DestinationDevicePathBuffer);
4459 if (!NT_SUCCESS(Status))
4460 {
4461 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status);
4462 MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER, L"MBR");
4463 return QUIT_PAGE;
4464 }
4465 }
4466
4467 return SUCCESS_PAGE;
4468 }
4469
4470
4471 /**
4472 * @name ProgressTimeOutStringHandler
4473 *
4474 * Handles the generation (displaying) of the timeout
4475 * countdown to the screen dynamically.
4476 *
4477 * @param Bar
4478 * A pointer to a progress bar.
4479 *
4480 * @param AlwaysUpdate
4481 * Constantly update the progress bar (boolean type).
4482 *
4483 * @param Buffer
4484 * A pointer to a string buffer.
4485 *
4486 * @param cchBufferSize
4487 * The buffer's size in number of characters.
4488 *
4489 * @return
4490 * TRUE or FALSE on function termination.
4491 *
4492 */
4493 static
4494 BOOLEAN NTAPI
4495 ProgressTimeOutStringHandler(
4496 IN PPROGRESSBAR Bar,
4497 IN BOOLEAN AlwaysUpdate,
4498 OUT PSTR Buffer,
4499 IN SIZE_T cchBufferSize)
4500 {
4501 ULONG OldProgress = Bar->Progress;
4502
4503 if (Bar->StepCount == 0)
4504 {
4505 Bar->Progress = 0;
4506 }
4507 else
4508 {
4509 Bar->Progress = Bar->StepCount - Bar->CurrentStep;
4510 }
4511
4512 /* Build the progress string if it has changed */
4513 if (Bar->ProgressFormatText &&
4514 (AlwaysUpdate || (Bar->Progress != OldProgress)))
4515 {
4516 RtlStringCchPrintfA(Buffer, cchBufferSize,
4517 Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1);
4518
4519 return TRUE;
4520 }
4521
4522 return FALSE;
4523 }
4524
4525 /**
4526 * @name ProgressCountdown
4527 *
4528 * Displays and draws a red-coloured progress bar with a countdown.
4529 * When the timeout is reached, the flush page is displayed for reboot.
4530 *
4531 * @param Ir
4532 * A pointer to an input keyboard record.
4533 *
4534 * @param TimeOut
4535 * Initial countdown value in seconds.
4536 *
4537 * @return
4538 * Nothing.
4539 *
4540 */
4541 static VOID
4542 ProgressCountdown(
4543 IN PINPUT_RECORD Ir,
4544 IN LONG TimeOut)
4545 {
4546 NTSTATUS Status;
4547 ULONG StartTime, BarWidth, TimerDiv;
4548 LONG TimeElapsed;
4549 LONG TimerValue, OldTimerValue;
4550 LARGE_INTEGER Timeout;
4551 PPROGRESSBAR ProgressBar;
4552 BOOLEAN RefreshProgress = TRUE;
4553
4554 /* Bail out if the timeout is already zero */
4555 if (TimeOut <= 0)
4556 return;
4557
4558 /* Create the timeout progress bar and set it up */
4559 ProgressBar = CreateProgressBarEx(13,
4560 26,
4561 xScreen - 13,
4562 yScreen - 20,
4563 10,
4564 24,
4565 TRUE,
4566 FOREGROUND_RED | BACKGROUND_BLUE,
4567 0,
4568 NULL,
4569 MUIGetString(STRING_REBOOTPROGRESSBAR),
4570 ProgressTimeOutStringHandler);
4571
4572 BarWidth = max(1, ProgressBar->Width);
4573 TimerValue = TimeOut * BarWidth;
4574 ProgressSetStepCount(ProgressBar, TimerValue);
4575
4576 StartTime = NtGetTickCount();
4577 CONSOLE_Flush();
4578
4579 TimerDiv = 1000 / BarWidth;
4580 TimerDiv = max(1, TimerDiv);
4581 OldTimerValue = TimerValue;
4582 while (TRUE)
4583 {
4584 /* Decrease the timer */
4585
4586 /*
4587 * Compute how much time the previous operations took.
4588 * This allows us in particular to take account for any time
4589 * elapsed if something slowed down.
4590 */
4591 TimeElapsed = NtGetTickCount() - StartTime;
4592 if (TimeElapsed >= TimerDiv)
4593 {
4594 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4595 TimeElapsed /= TimerDiv;
4596 StartTime += (TimerDiv * TimeElapsed);
4597
4598 if (TimeElapsed <= TimerValue)
4599 TimerValue -= TimeElapsed;
4600 else
4601 TimerValue = 0;
4602
4603 RefreshProgress = TRUE;
4604 }
4605
4606 if (RefreshProgress)
4607 {
4608 ProgressSetStep(ProgressBar, OldTimerValue - TimerValue);
4609 RefreshProgress = FALSE;
4610 }
4611
4612 /* Stop when the timer reaches zero */
4613 if (TimerValue <= 0)
4614 break;
4615
4616 /* Check for user key presses */
4617
4618 /*
4619 * If the timer is used, use a passive wait of maximum 1 second
4620 * while monitoring for incoming console input events, so that
4621 * we are still able to display the timing count.
4622 */
4623
4624 /* Wait a maximum of 1 second for input events */
4625 TimeElapsed = NtGetTickCount() - StartTime;
4626 if (TimeElapsed < TimerDiv)
4627 {
4628 /* Convert the time to NT Format */
4629 Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL;
4630 Status = NtWaitForSingleObject(StdInput, FALSE, &Timeout);
4631 }
4632 else
4633 {
4634 Status = STATUS_TIMEOUT;
4635 }
4636
4637 /* Check whether the input event has been signaled, or a timeout happened */
4638 if (Status == STATUS_TIMEOUT)
4639 {
4640 continue;
4641 }
4642 if (Status != STATUS_WAIT_0)
4643 {
4644 /* An error happened, bail out */
4645 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status);
4646 break;
4647 }
4648
4649 /* Check for an ENTER key press */
4650 while (CONSOLE_ConInKeyPeek(Ir))
4651 {
4652 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4653 {
4654 /* Found it, stop waiting */
4655 goto Exit;
4656 }
4657 }
4658 }
4659
4660 Exit:
4661 /* Destroy the progress bar and quit */
4662 DestroyProgressBar(ProgressBar);
4663 }
4664
4665
4666 /*
4667 * Displays the QuitPage.
4668 *
4669 * Next pages:
4670 * FlushPage (At once)
4671 *
4672 * SIDEEFFECTS
4673 * Destroy the Lists
4674 *
4675 * RETURNS
4676 * Number of the next page.
4677 */
4678 static PAGE_NUMBER
4679 QuitPage(PINPUT_RECORD Ir)
4680 {
4681 MUIDisplayPage(QUIT_PAGE);
4682
4683 /* Destroy the NTOS installations list */
4684 if (NtOsInstallsList != NULL)
4685 {
4686 DestroyGenericList(NtOsInstallsList, TRUE);
4687 NtOsInstallsList = NULL;
4688 }
4689
4690 /* Destroy the partition list */
4691 if (PartitionList != NULL)
4692 {
4693 DestroyPartitionList(PartitionList);
4694 PartitionList = NULL;
4695 }
4696
4697 /* Reset the formatter machine state */
4698 TempPartition = NULL;
4699 FormatState = Start;
4700
4701 /* Destroy the filesystem list */
4702 ResetFileSystemList();
4703
4704 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2));
4705
4706 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4707 ProgressCountdown(Ir, 15);
4708 return FLUSH_PAGE;
4709 }
4710
4711
4712 /*
4713 * Displays the SuccessPage.
4714 *
4715 * Next pages:
4716 * FlushPage (At once)
4717 *
4718 * SIDEEFFECTS
4719 * Destroy the Lists
4720 *
4721 * RETURNS
4722 * Number of the next page.
4723 */
4724 static PAGE_NUMBER
4725 SuccessPage(PINPUT_RECORD Ir)
4726 {
4727 MUIDisplayPage(SUCCESS_PAGE);
4728
4729 if (IsUnattendedSetup)
4730 return FLUSH_PAGE;
4731
4732 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4733 ProgressCountdown(Ir, 15);
4734 return FLUSH_PAGE;
4735 }
4736
4737
4738 /*
4739 * Displays the FlushPage.
4740 *
4741 * Next pages:
4742 * RebootPage (At once)
4743 *
4744 * RETURNS
4745 * Number of the next page.
4746 */
4747 static PAGE_NUMBER
4748 FlushPage(PINPUT_RECORD Ir)
4749 {
4750 MUIDisplayPage(FLUSH_PAGE);
4751 return REBOOT_PAGE;
4752 }
4753
4754
4755 /*
4756 * The start routine and page management
4757 */
4758 NTSTATUS
4759 RunUSetup(VOID)
4760 {
4761 NTSTATUS Status;
4762 INPUT_RECORD Ir;
4763 PAGE_NUMBER Page;
4764 BOOLEAN Old;
4765
4766 InfSetHeap(ProcessHeap);
4767
4768 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4769 Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
4770 if (!NT_SUCCESS(Status))
4771 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status);
4772
4773 /* Initialize the user-mode PnP manager */
4774 Status = InitializeUserModePnpManager(&USetupData.SetupInf);
4775 if (!NT_SUCCESS(Status))
4776 {
4777 // PrintString(??);
4778 DPRINT1("The user-mode PnP manager could not initialize (Status 0x%08lx), expect unavailable devices!\n", Status);
4779 }
4780
4781 if (!CONSOLE_Init())
4782 {
4783 PrintString(MUIGetString(STRING_CONSOLEFAIL1));
4784 PrintString(MUIGetString(STRING_CONSOLEFAIL2));
4785 PrintString(MUIGetString(STRING_CONSOLEFAIL3));
4786
4787 /* We failed to initialize the video, just quit the installer */
4788 return STATUS_APP_INIT_FAILURE;
4789 }
4790
4791 /* Initialize Setup, phase 0 */
4792 InitializeSetup(&USetupData, 0);
4793 USetupData.ErrorRoutine = USetupErrorRoutine;
4794
4795 /* Hide the cursor and clear the screen and keyboard buffer */
4796 CONSOLE_SetCursorType(TRUE, FALSE);
4797 CONSOLE_ClearScreen();
4798 CONSOLE_Flush();
4799
4800 /* Global Initialization page */
4801 Page = SetupStartPage(&Ir);
4802
4803 while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
4804 {
4805 CONSOLE_ClearScreen();
4806 CONSOLE_Flush();
4807
4808 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4809 // CONSOLE_Flush();
4810
4811 switch (Page)
4812 {
4813 /* Language page */
4814 case LANGUAGE_PAGE:
4815 Page = LanguagePage(&Ir);
4816 break;
4817
4818 /* Welcome page */
4819 case WELCOME_PAGE:
4820 Page = WelcomePage(&Ir);
4821 break;
4822
4823 /* License page */
4824 case LICENSE_PAGE:
4825 Page = LicensePage(&Ir);
4826 break;
4827
4828 /* Install pages */
4829 case INSTALL_INTRO_PAGE:
4830 Page = InstallIntroPage(&Ir);
4831 break;
4832
4833 #if 0
4834 case SCSI_CONTROLLER_PAGE:
4835 Page = ScsiControllerPage(&Ir);
4836 break;
4837
4838 case OEM_DRIVER_PAGE:
4839 Page = OemDriverPage(&Ir);
4840 break;
4841 #endif
4842
4843 case DEVICE_SETTINGS_PAGE:
4844 Page = DeviceSettingsPage(&Ir);
4845 break;
4846
4847 case COMPUTER_SETTINGS_PAGE:
4848 Page = ComputerSettingsPage(&Ir);
4849 break;
4850
4851 case DISPLAY_SETTINGS_PAGE:
4852 Page = DisplaySettingsPage(&Ir);
4853 break;
4854
4855 case KEYBOARD_SETTINGS_PAGE:
4856 Page = KeyboardSettingsPage(&Ir);
4857 break;
4858
4859 case LAYOUT_SETTINGS_PAGE:
4860 Page = LayoutSettingsPage(&Ir);
4861 break;
4862
4863 case SELECT_PARTITION_PAGE:
4864 Page = SelectPartitionPage(&Ir);
4865 break;
4866
4867 case CREATE_PRIMARY_PARTITION_PAGE:
4868 Page = CreatePrimaryPartitionPage(&Ir);
4869 break;
4870
4871 case CREATE_EXTENDED_PARTITION_PAGE:
4872 Page = CreateExtendedPartitionPage(&Ir);
4873 break;
4874
4875 case CREATE_LOGICAL_PARTITION_PAGE:
4876 Page = CreateLogicalPartitionPage(&Ir);
4877 break;
4878
4879 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE:
4880 Page = ConfirmDeleteSystemPartitionPage(&Ir);
4881 break;
4882
4883 case DELETE_PARTITION_PAGE:
4884 Page = DeletePartitionPage(&Ir);
4885 break;
4886
4887 case SELECT_FILE_SYSTEM_PAGE:
4888 Page = SelectFileSystemPage(&Ir);
4889 break;
4890
4891 case FORMAT_PARTITION_PAGE:
4892 Page = FormatPartitionPage(&Ir);
4893 break;
4894
4895 case CHECK_FILE_SYSTEM_PAGE:
4896 Page = CheckFileSystemPage(&Ir);
4897 break;
4898
4899 case INSTALL_DIRECTORY_PAGE:
4900 Page = InstallDirectoryPage(&Ir);
4901 break;
4902
4903 case PREPARE_COPY_PAGE:
4904 Page = PrepareCopyPage(&Ir);
4905 break;
4906
4907 case FILE_COPY_PAGE:
4908 Page = FileCopyPage(&Ir);
4909 break;
4910
4911 case REGISTRY_PAGE:
4912 Page = RegistryPage(&Ir);
4913 break;
4914
4915 case BOOT_LOADER_PAGE:
4916 Page = BootLoaderPage(&Ir);
4917 break;
4918
4919 case BOOT_LOADER_FLOPPY_PAGE:
4920 Page = BootLoaderFloppyPage(&Ir);
4921 break;
4922
4923 case BOOT_LOADER_HARDDISK_MBR_PAGE:
4924 Page = BootLoaderHarddiskMbrPage(&Ir);
4925 break;
4926
4927 case BOOT_LOADER_HARDDISK_VBR_PAGE:
4928 Page = BootLoaderHarddiskVbrPage(&Ir);
4929 break;
4930
4931 /* Repair pages */
4932 case REPAIR_INTRO_PAGE:
4933 Page = RepairIntroPage(&Ir);
4934 break;
4935
4936 case UPGRADE_REPAIR_PAGE:
4937 Page = UpgradeRepairPage(&Ir);
4938 break;
4939
4940 case SUCCESS_PAGE:
4941 Page = SuccessPage(&Ir);
4942 break;
4943
4944 case FLUSH_PAGE:
4945 Page = FlushPage(&Ir);
4946 break;
4947
4948 case QUIT_PAGE:
4949 Page = QuitPage(&Ir);
4950 break;
4951
4952 /* Virtual pages */
4953 case SETUP_INIT_PAGE:
4954 case REBOOT_PAGE:
4955 case RECOVERY_PAGE:
4956 break;
4957 }
4958 }
4959
4960 /* Terminate the user-mode PnP manager */
4961 TerminateUserModePnpManager();
4962
4963 /* Setup has finished */
4964 FinishSetup(&USetupData);
4965
4966 if (Page == RECOVERY_PAGE)
4967 RecoveryConsole();
4968
4969 FreeConsole();
4970
4971 /* Reboot */
4972 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
4973 NtShutdownSystem(ShutdownReboot);
4974 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
4975
4976 return STATUS_SUCCESS;
4977 }
4978
4979
4980 VOID NTAPI
4981 NtProcessStartup(PPEB Peb)
4982 {
4983 NTSTATUS Status;
4984 LARGE_INTEGER Time;
4985
4986 RtlNormalizeProcessParams(Peb->ProcessParameters);
4987
4988 ProcessHeap = Peb->ProcessHeap;
4989
4990 NtQuerySystemTime(&Time);
4991
4992 Status = RunUSetup();
4993
4994 if (NT_SUCCESS(Status))
4995 {
4996 /*
4997 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
4998 * a protective waiting.
4999 * This wait is needed because, since we are started as SMSS.EXE,
5000 * the NT kernel explicitly waits 5 seconds for the initial process
5001 * SMSS.EXE to initialize (as a protective measure), and otherwise
5002 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5003 */
5004 Time.QuadPart += 50000000;
5005 NtDelayExecution(FALSE, &Time);
5006 }
5007 else
5008 {
5009 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5010 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
5011 0, 0, NULL, 0, NULL);
5012 }
5013
5014 NtTerminateProcess(NtCurrentProcess(), Status);
5015 }
5016
5017 /* EOF */