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