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