[SETUPLIB][USETUP] Improve disk HW numbering, removable disk support, and "super...
[reactos.git] / base / setup / usetup / usetup.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2003, 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/usetup.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hervé Poussineau (hpoussin@reactos.org)
26 */
27
28 #include <usetup.h>
29 #include <math.h>
30
31 #include "bootsup.h"
32 #include "chkdsk.h"
33 #include "cmdcons.h"
34 #include "devinst.h"
35 #include "format.h"
36
37 #define NDEBUG
38 #include <debug.h>
39
40
41 /* GLOBALS & LOCALS *********************************************************/
42
43 HANDLE ProcessHeap;
44 BOOLEAN IsUnattendedSetup = FALSE;
45
46 static USETUP_DATA USetupData;
47
48 /* Partition where to perform the installation */
49 static PPARTENTRY InstallPartition = NULL;
50 // static PPARTENTRY SystemPartition = NULL; // The system partition we will actually use (can be different from PartitionList->SystemPartition in case we install on removable disk)
51
52 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
53 static WCHAR DestinationDriveLetter;
54
55
56 /* OTHER Stuff *****/
57
58 PCWSTR SelectedLanguageId;
59 static WCHAR DefaultLanguage[20]; // Copy of string inside LanguageList
60 static WCHAR DefaultKBLayout[20]; // Copy of string inside KeyboardList
61
62 static BOOLEAN RepairUpdateFlag = FALSE;
63
64 /* Global partition list on the system */
65 static PPARTLIST PartitionList = NULL;
66
67 /* Currently selected partition entry in the list */
68 static PPARTENTRY CurrentPartition = NULL;
69
70 /* List of supported file systems for the partition to be formatted */
71 static PFILE_SYSTEM_LIST FileSystemList = NULL;
72
73 /* Machine state for the formatter */
74 static PPARTENTRY TempPartition = NULL;
75 static FORMATMACHINESTATE FormatState = Start;
76
77 /*****************************************************/
78
79 static PNTOS_INSTALLATION CurrentInstallation = NULL;
80 static PGENERIC_LIST NtOsInstallsList = NULL;
81
82
83 /* FUNCTIONS ****************************************************************/
84
85 static VOID
86 PrintString(char* fmt,...)
87 {
88 char buffer[512];
89 va_list ap;
90 UNICODE_STRING UnicodeString;
91 ANSI_STRING AnsiString;
92
93 va_start(ap, fmt);
94 vsprintf(buffer, fmt, ap);
95 va_end(ap);
96
97 RtlInitAnsiString(&AnsiString, buffer);
98 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
99 NtDisplayString(&UnicodeString);
100 RtlFreeUnicodeString(&UnicodeString);
101 }
102
103
104 static VOID
105 DrawBox(IN SHORT xLeft,
106 IN SHORT yTop,
107 IN SHORT Width,
108 IN SHORT Height)
109 {
110 COORD coPos;
111 DWORD Written;
112
113 /* Draw upper left corner */
114 coPos.X = xLeft;
115 coPos.Y = yTop;
116 FillConsoleOutputCharacterA(StdOutput,
117 0xDA, // '+',
118 1,
119 coPos,
120 &Written);
121
122 /* Draw upper edge */
123 coPos.X = xLeft + 1;
124 coPos.Y = yTop;
125 FillConsoleOutputCharacterA(StdOutput,
126 0xC4, // '-',
127 Width - 2,
128 coPos,
129 &Written);
130
131 /* Draw upper right corner */
132 coPos.X = xLeft + Width - 1;
133 coPos.Y = yTop;
134 FillConsoleOutputCharacterA(StdOutput,
135 0xBF, // '+',
136 1,
137 coPos,
138 &Written);
139
140 /* Draw right edge, inner space and left edge */
141 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
142 {
143 coPos.X = xLeft;
144 FillConsoleOutputCharacterA(StdOutput,
145 0xB3, // '|',
146 1,
147 coPos,
148 &Written);
149
150 coPos.X = xLeft + 1;
151 FillConsoleOutputCharacterA(StdOutput,
152 ' ',
153 Width - 2,
154 coPos,
155 &Written);
156
157 coPos.X = xLeft + Width - 1;
158 FillConsoleOutputCharacterA(StdOutput,
159 0xB3, // '|',
160 1,
161 coPos,
162 &Written);
163 }
164
165 /* Draw lower left corner */
166 coPos.X = xLeft;
167 coPos.Y = yTop + Height - 1;
168 FillConsoleOutputCharacterA(StdOutput,
169 0xC0, // '+',
170 1,
171 coPos,
172 &Written);
173
174 /* Draw lower edge */
175 coPos.X = xLeft + 1;
176 coPos.Y = yTop + Height - 1;
177 FillConsoleOutputCharacterA(StdOutput,
178 0xC4, // '-',
179 Width - 2,
180 coPos,
181 &Written);
182
183 /* Draw lower right corner */
184 coPos.X = xLeft + Width - 1;
185 coPos.Y = yTop + Height - 1;
186 FillConsoleOutputCharacterA(StdOutput,
187 0xD9, // '+',
188 1,
189 coPos,
190 &Written);
191 }
192
193
194 VOID
195 PopupError(PCCH Text,
196 PCCH Status,
197 PINPUT_RECORD Ir,
198 ULONG WaitEvent)
199 {
200 SHORT yTop;
201 SHORT xLeft;
202 COORD coPos;
203 DWORD Written;
204 ULONG Length;
205 ULONG MaxLength;
206 ULONG Lines;
207 PCHAR p;
208 PCCH pnext;
209 BOOLEAN LastLine;
210 SHORT Width;
211 SHORT Height;
212
213 /* Count text lines and longest line */
214 MaxLength = 0;
215 Lines = 0;
216 pnext = Text;
217
218 while (TRUE)
219 {
220 p = strchr(pnext, '\n');
221
222 if (p == NULL)
223 {
224 Length = strlen(pnext);
225 LastLine = TRUE;
226 }
227 else
228 {
229 Length = (ULONG)(p - pnext);
230 LastLine = FALSE;
231 }
232
233 Lines++;
234
235 if (Length > MaxLength)
236 MaxLength = Length;
237
238 if (LastLine)
239 break;
240
241 pnext = p + 1;
242 }
243
244 /* Check length of status line */
245 if (Status != NULL)
246 {
247 Length = strlen(Status);
248
249 if (Length > MaxLength)
250 MaxLength = Length;
251 }
252
253 Width = MaxLength + 4;
254 Height = Lines + 2;
255
256 if (Status != NULL)
257 Height += 2;
258
259 yTop = (yScreen - Height) / 2;
260 xLeft = (xScreen - Width) / 2;
261
262
263 /* Set screen attributes */
264 coPos.X = xLeft;
265 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
266 {
267 FillConsoleOutputAttribute(StdOutput,
268 FOREGROUND_RED | BACKGROUND_WHITE,
269 Width,
270 coPos,
271 &Written);
272 }
273
274 DrawBox(xLeft, yTop, Width, Height);
275
276 /* Print message text */
277 coPos.Y = yTop + 1;
278 pnext = Text;
279 while (TRUE)
280 {
281 p = strchr(pnext, '\n');
282
283 if (p == NULL)
284 {
285 Length = strlen(pnext);
286 LastLine = TRUE;
287 }
288 else
289 {
290 Length = (ULONG)(p - pnext);
291 LastLine = FALSE;
292 }
293
294 if (Length != 0)
295 {
296 coPos.X = xLeft + 2;
297 WriteConsoleOutputCharacterA(StdOutput,
298 pnext,
299 Length,
300 coPos,
301 &Written);
302 }
303
304 if (LastLine)
305 break;
306
307 coPos.Y++;
308 pnext = p + 1;
309 }
310
311 /* Print separator line and status text */
312 if (Status != NULL)
313 {
314 coPos.Y = yTop + Height - 3;
315 coPos.X = xLeft;
316 FillConsoleOutputCharacterA(StdOutput,
317 0xC3, // '+',
318 1,
319 coPos,
320 &Written);
321
322 coPos.X = xLeft + 1;
323 FillConsoleOutputCharacterA(StdOutput,
324 0xC4, // '-',
325 Width - 2,
326 coPos,
327 &Written);
328
329 coPos.X = xLeft + Width - 1;
330 FillConsoleOutputCharacterA(StdOutput,
331 0xB4, // '+',
332 1,
333 coPos,
334 &Written);
335
336 coPos.Y++;
337 coPos.X = xLeft + 2;
338 WriteConsoleOutputCharacterA(StdOutput,
339 Status,
340 min(strlen(Status), (SIZE_T)Width - 4),
341 coPos,
342 &Written);
343 }
344
345 if (WaitEvent == POPUP_WAIT_NONE)
346 return;
347
348 while (TRUE)
349 {
350 CONSOLE_ConInKey(Ir);
351
352 if (WaitEvent == POPUP_WAIT_ANY_KEY ||
353 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
354 {
355 return;
356 }
357 }
358 }
359
360
361 /*
362 * Confirm quit setup
363 * RETURNS
364 * TRUE: Quit setup.
365 * FALSE: Don't quit setup.
366 */
367 static BOOL
368 ConfirmQuit(PINPUT_RECORD Ir)
369 {
370 BOOL Result = FALSE;
371 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE);
372
373 while (TRUE)
374 {
375 CONSOLE_ConInKey(Ir);
376
377 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
378 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
379 {
380 Result = TRUE;
381 break;
382 }
383 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
384 {
385 Result = FALSE;
386 break;
387 }
388 }
389
390 return Result;
391 }
392
393
394 static VOID
395 UpdateKBLayout(VOID)
396 {
397 PGENERIC_LIST_ENTRY ListEntry;
398 PCWSTR pszNewLayout;
399
400 pszNewLayout = MUIDefaultKeyboardLayout(SelectedLanguageId);
401
402 if (USetupData.LayoutList == NULL)
403 {
404 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
405 if (USetupData.LayoutList == NULL)
406 {
407 /* FIXME: Handle error! */
408 return;
409 }
410 }
411
412 /* Search for default layout (if provided) */
413 if (pszNewLayout != NULL)
414 {
415 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
416 ListEntry = GetNextListEntry(ListEntry))
417 {
418 if (!wcscmp(pszNewLayout, ((PGENENTRY)GetListEntryData(ListEntry))->Id))
419 {
420 SetCurrentListEntry(USetupData.LayoutList, ListEntry);
421 break;
422 }
423 }
424 }
425 }
426
427
428 static NTSTATUS
429 NTAPI
430 GetSettingDescription(
431 IN PGENERIC_LIST_ENTRY Entry,
432 OUT PSTR Buffer,
433 IN SIZE_T cchBufferSize)
434 {
435 return RtlStringCchPrintfA(Buffer, cchBufferSize, "%S",
436 ((PGENENTRY)GetListEntryData(Entry))->Value);
437 }
438
439 static NTSTATUS
440 NTAPI
441 GetNTOSInstallationName(
442 IN PGENERIC_LIST_ENTRY Entry,
443 OUT PSTR Buffer,
444 IN SIZE_T cchBufferSize)
445 {
446 PNTOS_INSTALLATION NtOsInstall = (PNTOS_INSTALLATION)GetListEntryData(Entry);
447 PPARTENTRY PartEntry = NtOsInstall->PartEntry;
448
449 if (PartEntry && PartEntry->DriveLetter)
450 {
451 /* We have retrieved a partition that is mounted */
452 return RtlStringCchPrintfA(Buffer, cchBufferSize,
453 "%C:%S \"%S\"",
454 PartEntry->DriveLetter,
455 NtOsInstall->PathComponent,
456 NtOsInstall->InstallationName);
457 }
458 else
459 {
460 /* We failed somewhere, just show the NT path */
461 return RtlStringCchPrintfA(Buffer, cchBufferSize,
462 "%wZ \"%S\"",
463 &NtOsInstall->SystemNtPath,
464 NtOsInstall->InstallationName);
465 }
466 }
467
468
469 /*
470 * Displays the LanguagePage.
471 *
472 * Next pages: WelcomePage, QuitPage
473 *
474 * SIDEEFFECTS
475 * Init SelectedLanguageId
476 * Init USetupData.LanguageId
477 *
478 * RETURNS
479 * Number of the next page.
480 */
481 static PAGE_NUMBER
482 LanguagePage(PINPUT_RECORD Ir)
483 {
484 GENERIC_LIST_UI ListUi;
485 PCWSTR NewLanguageId;
486 BOOL RefreshPage = FALSE;
487
488 /* Initialize the computer settings list */
489 if (USetupData.LanguageList == NULL)
490 {
491 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
492 if (USetupData.LanguageList == NULL)
493 {
494 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
495 return WELCOME_PAGE;
496 }
497 }
498
499 SelectedLanguageId = DefaultLanguage;
500 USetupData.LanguageId = 0;
501
502 /* Load the font */
503 SetConsoleCodePage();
504 UpdateKBLayout();
505
506 /*
507 * If there is no language or just a single one in the list,
508 * skip the language selection process altogether.
509 */
510 if (GetNumberOfListEntries(USetupData.LanguageList) <= 1)
511 {
512 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
513 return WELCOME_PAGE;
514 }
515
516 InitGenericListUi(&ListUi, USetupData.LanguageList, GetSettingDescription);
517 DrawGenericList(&ListUi,
518 2, 18,
519 xScreen - 3,
520 yScreen - 3);
521
522 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex());
523
524 MUIDisplayPage(LANGUAGE_PAGE);
525
526 while (TRUE)
527 {
528 CONSOLE_ConInKey(Ir);
529
530 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
531 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
532 {
533 ScrollDownGenericList(&ListUi);
534 RefreshPage = TRUE;
535 }
536 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
537 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
538 {
539 ScrollUpGenericList(&ListUi);
540 RefreshPage = TRUE;
541 }
542 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
543 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
544 {
545 ScrollPageDownGenericList(&ListUi);
546 RefreshPage = TRUE;
547 }
548 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
549 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
550 {
551 ScrollPageUpGenericList(&ListUi);
552 RefreshPage = TRUE;
553 }
554 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
555 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
556 {
557 if (ConfirmQuit(Ir))
558 return QUIT_PAGE;
559 else
560 RedrawGenericList(&ListUi);
561 }
562 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
563 {
564 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
565
566 SelectedLanguageId =
567 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
568
569 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
570
571 if (wcscmp(SelectedLanguageId, DefaultLanguage))
572 {
573 UpdateKBLayout();
574 }
575
576 /* Load the font */
577 SetConsoleCodePage();
578
579 return WELCOME_PAGE;
580 }
581 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
582 {
583 /* a-z */
584 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
585 RefreshPage = TRUE;
586 }
587
588 if (RefreshPage)
589 {
590 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
591
592 NewLanguageId =
593 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
594
595 if (wcscmp(SelectedLanguageId, NewLanguageId))
596 {
597 /* Clear the language page */
598 MUIClearPage(LANGUAGE_PAGE);
599
600 SelectedLanguageId = NewLanguageId;
601
602 /* Load the font */
603 SetConsoleCodePage();
604
605 /* Redraw language selection page in native language */
606 MUIDisplayPage(LANGUAGE_PAGE);
607 }
608
609 RefreshPage = FALSE;
610 }
611 }
612
613 return WELCOME_PAGE;
614 }
615
616
617 /*
618 * Start page
619 *
620 * Next pages:
621 * LanguagePage (at once, default)
622 * InstallIntroPage (at once, if unattended)
623 * QuitPage
624 *
625 * SIDEEFFECTS
626 * Init Sdi
627 * Init USetupData.SourcePath
628 * Init USetupData.SourceRootPath
629 * Init USetupData.SourceRootDir
630 * Init USetupData.SetupInf
631 * Init USetupData.RequiredPartitionDiskSpace
632 * Init IsUnattendedSetup
633 * If unattended, init *List and sets the Codepage
634 * If unattended, init SelectedLanguageId
635 * If unattended, init USetupData.LanguageId
636 *
637 * RETURNS
638 * Number of the next page.
639 */
640 static PAGE_NUMBER
641 SetupStartPage(PINPUT_RECORD Ir)
642 {
643 ULONG Error;
644 PGENERIC_LIST_ENTRY ListEntry;
645 PCWSTR LocaleId;
646
647 MUIDisplayPage(SETUP_INIT_PAGE);
648
649 /* Initialize Setup, phase 1 */
650 Error = InitializeSetup(&USetupData, 1);
651 if (Error != ERROR_SUCCESS)
652 {
653 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
654 return QUIT_PAGE;
655 }
656
657 /* Initialize the user-mode PnP manager */
658 if (!EnableUserModePnpManager())
659 DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n");
660
661 /* Wait for any immediate pending installations to finish */
662 if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0)
663 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n");
664
665 CheckUnattendedSetup(&USetupData);
666
667 if (IsUnattendedSetup)
668 {
669 // TODO: Read options from inf
670 /* Load the hardware, language and keyboard layout lists */
671
672 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
673 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
674 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
675
676 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
677
678 /* new part */
679 SelectedLanguageId = DefaultLanguage;
680 wcscpy(DefaultLanguage, USetupData.LocaleID);
681 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
682
683 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
684
685 /* first we hack LanguageList */
686 for (ListEntry = GetFirstListEntry(USetupData.LanguageList); ListEntry;
687 ListEntry = GetNextListEntry(ListEntry))
688 {
689 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
690 if (!wcsicmp(USetupData.LocaleID, LocaleId))
691 {
692 DPRINT("found %S in LanguageList\n", LocaleId);
693 SetCurrentListEntry(USetupData.LanguageList, ListEntry);
694 break;
695 }
696 }
697
698 /* now LayoutList */
699 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
700 ListEntry = GetNextListEntry(ListEntry))
701 {
702 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id;
703 if (!wcsicmp(USetupData.LocaleID, LocaleId))
704 {
705 DPRINT("found %S in LayoutList\n", LocaleId);
706 SetCurrentListEntry(USetupData.LayoutList, ListEntry);
707 break;
708 }
709 }
710
711 SetConsoleCodePage();
712
713 return INSTALL_INTRO_PAGE;
714 }
715
716 return LANGUAGE_PAGE;
717 }
718
719
720 /*
721 * Displays the WelcomePage.
722 *
723 * Next pages:
724 * InstallIntroPage (default)
725 * RepairIntroPage
726 * RecoveryPage
727 * LicensePage
728 * QuitPage
729 *
730 * RETURNS
731 * Number of the next page.
732 */
733 static PAGE_NUMBER
734 WelcomePage(PINPUT_RECORD Ir)
735 {
736 MUIDisplayPage(WELCOME_PAGE);
737
738 while (TRUE)
739 {
740 CONSOLE_ConInKey(Ir);
741
742 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
743 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
744 {
745 if (ConfirmQuit(Ir))
746 return QUIT_PAGE;
747
748 break;
749 }
750 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
751 {
752 return INSTALL_INTRO_PAGE;
753 }
754 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
755 {
756 return RECOVERY_PAGE; // REPAIR_INTRO_PAGE;
757 }
758 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */
759 {
760 return LICENSE_PAGE;
761 }
762 }
763
764 return WELCOME_PAGE;
765 }
766
767
768 /*
769 * Displays the License page.
770 *
771 * Next page:
772 * WelcomePage (default)
773 *
774 * RETURNS
775 * Number of the next page.
776 */
777 static PAGE_NUMBER
778 LicensePage(PINPUT_RECORD Ir)
779 {
780 MUIDisplayPage(LICENSE_PAGE);
781
782 while (TRUE)
783 {
784 CONSOLE_ConInKey(Ir);
785
786 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
787 {
788 return WELCOME_PAGE;
789 }
790 }
791
792 return LICENSE_PAGE;
793 }
794
795
796 /*
797 * Displays the RepairIntroPage.
798 *
799 * Next pages:
800 * RebootPage (default)
801 * InstallIntroPage
802 * RecoveryPage
803 * IntroPage
804 *
805 * RETURNS
806 * Number of the next page.
807 */
808 static PAGE_NUMBER
809 RepairIntroPage(PINPUT_RECORD Ir)
810 {
811 MUIDisplayPage(REPAIR_INTRO_PAGE);
812
813 while (TRUE)
814 {
815 CONSOLE_ConInKey(Ir);
816
817 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
818 {
819 return REBOOT_PAGE;
820 }
821 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
822 {
823 RepairUpdateFlag = TRUE;
824 return INSTALL_INTRO_PAGE;
825 }
826 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */
827 {
828 return RECOVERY_PAGE;
829 }
830 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
831 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
832 {
833 return WELCOME_PAGE;
834 }
835 }
836
837 return REPAIR_INTRO_PAGE;
838 }
839
840 /*
841 * Displays the UpgradeRepairPage.
842 *
843 * Next pages:
844 * RebootPage (default)
845 * InstallIntroPage
846 * RecoveryPage
847 * WelcomePage
848 *
849 * RETURNS
850 * Number of the next page.
851 */
852 static PAGE_NUMBER
853 UpgradeRepairPage(PINPUT_RECORD Ir)
854 {
855 GENERIC_LIST_UI ListUi;
856
857 /*** HACK!! ***/
858 if (PartitionList == NULL)
859 {
860 PartitionList = CreatePartitionList();
861 if (PartitionList == NULL)
862 {
863 /* FIXME: show an error dialog */
864 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
865 return QUIT_PAGE;
866 }
867 else if (IsListEmpty(&PartitionList->DiskListHead))
868 {
869 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
870 return QUIT_PAGE;
871 }
872
873 /* Reset the formatter machine state */
874 TempPartition = NULL;
875 FormatState = Start;
876 }
877 /**************/
878
879 NtOsInstallsList = CreateNTOSInstallationsList(PartitionList);
880 if (!NtOsInstallsList)
881 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n");
882
883 /*
884 * If there is no available installation (or just a single one??) that can
885 * be updated in the list, just continue with the regular installation.
886 */
887 if (!NtOsInstallsList || GetNumberOfListEntries(NtOsInstallsList) == 0)
888 {
889 RepairUpdateFlag = FALSE;
890
891 // return INSTALL_INTRO_PAGE;
892 return DEVICE_SETTINGS_PAGE;
893 // return SCSI_CONTROLLER_PAGE;
894 }
895
896 MUIDisplayPage(UPGRADE_REPAIR_PAGE);
897
898 InitGenericListUi(&ListUi, NtOsInstallsList, GetNTOSInstallationName);
899 DrawGenericList(&ListUi,
900 2, 23,
901 xScreen - 3,
902 yScreen - 3);
903
904 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
905 while (TRUE)
906 {
907 CONSOLE_ConInKey(Ir);
908
909 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00)
910 {
911 switch (Ir->Event.KeyEvent.wVirtualKeyCode)
912 {
913 case VK_DOWN: /* DOWN */
914 ScrollDownGenericList(&ListUi);
915 break;
916 case VK_UP: /* UP */
917 ScrollUpGenericList(&ListUi);
918 break;
919 case VK_NEXT: /* PAGE DOWN */
920 ScrollPageDownGenericList(&ListUi);
921 break;
922 case VK_PRIOR: /* PAGE UP */
923 ScrollPageUpGenericList(&ListUi);
924 break;
925 case VK_F3: /* F3 */
926 {
927 if (ConfirmQuit(Ir))
928 return QUIT_PAGE;
929 else
930 RedrawGenericList(&ListUi);
931 break;
932 }
933 case VK_ESCAPE: /* ESC */
934 {
935 RestoreGenericListUiState(&ListUi);
936 // return nextPage; // prevPage;
937
938 // return INSTALL_INTRO_PAGE;
939 return DEVICE_SETTINGS_PAGE;
940 // return SCSI_CONTROLLER_PAGE;
941 }
942 }
943 }
944 else
945 {
946 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar))
947 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
948 if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */
949 {
950 /* Retrieve the current installation */
951 ASSERT(GetNumberOfListEntries(NtOsInstallsList) >= 1);
952
953 CurrentInstallation =
954 (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(NtOsInstallsList));
955
956 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n",
957 CurrentInstallation->InstallationName, CurrentInstallation->DiskNumber, CurrentInstallation->PartitionNumber);
958
959 RepairUpdateFlag = TRUE;
960
961 // return nextPage;
962 /***/return INSTALL_INTRO_PAGE;/***/
963 }
964 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) &&
965 (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) /* a-z */
966 {
967 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
968 }
969 }
970 }
971
972 return UPGRADE_REPAIR_PAGE;
973 }
974
975
976 /*
977 * Displays the InstallIntroPage.
978 *
979 * Next pages:
980 * DeviceSettingsPage (At once if repair or update is selected)
981 * SelectPartitionPage (At once if unattended setup)
982 * DeviceSettingsPage (default)
983 * QuitPage
984 *
985 * RETURNS
986 * Number of the next page.
987 */
988 static PAGE_NUMBER
989 InstallIntroPage(PINPUT_RECORD Ir)
990 {
991 if (RepairUpdateFlag)
992 {
993 #if 1 /* Old code that looks good */
994
995 // return SELECT_PARTITION_PAGE;
996 return DEVICE_SETTINGS_PAGE;
997
998 #else /* Possible new code? */
999
1000 return DEVICE_SETTINGS_PAGE;
1001 // return SCSI_CONTROLLER_PAGE;
1002
1003 #endif
1004 }
1005
1006 if (IsUnattendedSetup)
1007 return SELECT_PARTITION_PAGE;
1008
1009 MUIDisplayPage(INSTALL_INTRO_PAGE);
1010
1011 while (TRUE)
1012 {
1013 CONSOLE_ConInKey(Ir);
1014
1015 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1016 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1017 {
1018 if (ConfirmQuit(Ir))
1019 return QUIT_PAGE;
1020
1021 break;
1022 }
1023 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1024 {
1025 return UPGRADE_REPAIR_PAGE;
1026 }
1027 }
1028
1029 return INSTALL_INTRO_PAGE;
1030 }
1031
1032
1033 #if 0
1034 static PAGE_NUMBER
1035 ScsiControllerPage(PINPUT_RECORD Ir)
1036 {
1037 // MUIDisplayPage(SCSI_CONTROLLER_PAGE);
1038
1039 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:");
1040
1041 /* FIXME: print loaded mass storage driver descriptions */
1042 #if 0
1043 CONSOLE_SetTextXY(8, 10, "TEST device");
1044 #endif
1045
1046 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1047
1048 while (TRUE)
1049 {
1050 CONSOLE_ConInKey(Ir);
1051
1052 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1053 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1054 {
1055 if (ConfirmQuit(Ir))
1056 return QUIT_PAGE;
1057
1058 break;
1059 }
1060 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1061 {
1062 return DEVICE_SETTINGS_PAGE;
1063 }
1064 }
1065
1066 return SCSI_CONTROLLER_PAGE;
1067 }
1068
1069 static PAGE_NUMBER
1070 OemDriverPage(PINPUT_RECORD Ir)
1071 {
1072 // MUIDisplayPage(OEM_DRIVER_PAGE);
1073
1074 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!");
1075
1076 /* FIXME: Implement!! */
1077
1078 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit");
1079
1080 while (TRUE)
1081 {
1082 CONSOLE_ConInKey(Ir);
1083
1084 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1085 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1086 {
1087 if (ConfirmQuit(Ir))
1088 return QUIT_PAGE;
1089
1090 break;
1091 }
1092 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1093 {
1094 return DEVICE_SETTINGS_PAGE;
1095 }
1096 }
1097
1098 return OEM_DRIVER_PAGE;
1099 }
1100 #endif
1101
1102
1103 /*
1104 * Displays the DeviceSettingsPage.
1105 *
1106 * Next pages:
1107 * SelectPartitionPage (At once if repair or update is selected)
1108 * ComputerSettingsPage
1109 * DisplaySettingsPage
1110 * KeyboardSettingsPage
1111 * LayoutsettingsPage
1112 * SelectPartitionPage
1113 * QuitPage
1114 *
1115 * SIDEEFFECTS
1116 * Init USetupData.ComputerList
1117 * Init USetupData.DisplayList
1118 * Init USetupData.KeyboardList
1119 * Init USetupData.LayoutList
1120 *
1121 * RETURNS
1122 * Number of the next page.
1123 */
1124 static PAGE_NUMBER
1125 DeviceSettingsPage(PINPUT_RECORD Ir)
1126 {
1127 static ULONG Line = 16;
1128
1129 /* Initialize the computer settings list */
1130 if (USetupData.ComputerList == NULL)
1131 {
1132 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf);
1133 if (USetupData.ComputerList == NULL)
1134 {
1135 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER);
1136 return QUIT_PAGE;
1137 }
1138 }
1139
1140 /* Initialize the display settings list */
1141 if (USetupData.DisplayList == NULL)
1142 {
1143 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf);
1144 if (USetupData.DisplayList == NULL)
1145 {
1146 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER);
1147 return QUIT_PAGE;
1148 }
1149 }
1150
1151 /* Initialize the keyboard settings list */
1152 if (USetupData.KeyboardList == NULL)
1153 {
1154 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf);
1155 if (USetupData.KeyboardList == NULL)
1156 {
1157 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER);
1158 return QUIT_PAGE;
1159 }
1160 }
1161
1162 /* Initialize the keyboard layout list */
1163 if (USetupData.LayoutList == NULL)
1164 {
1165 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
1166 if (USetupData.LayoutList == NULL)
1167 {
1168 /* FIXME: report error */
1169 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER);
1170 return QUIT_PAGE;
1171 }
1172 }
1173
1174 if (RepairUpdateFlag)
1175 return SELECT_PARTITION_PAGE;
1176
1177 // if (IsUnattendedSetup)
1178 // return SELECT_PARTITION_PAGE;
1179
1180 MUIDisplayPage(DEVICE_SETTINGS_PAGE);
1181
1182 DrawGenericListCurrentItem(USetupData.ComputerList, GetSettingDescription, 25, 11);
1183 DrawGenericListCurrentItem(USetupData.DisplayList , GetSettingDescription, 25, 12);
1184 DrawGenericListCurrentItem(USetupData.KeyboardList, GetSettingDescription, 25, 13);
1185 DrawGenericListCurrentItem(USetupData.LayoutList , GetSettingDescription, 25, 14);
1186
1187 CONSOLE_InvertTextXY(24, Line, 48, 1);
1188
1189 while (TRUE)
1190 {
1191 CONSOLE_ConInKey(Ir);
1192
1193 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1194 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1195 {
1196 CONSOLE_NormalTextXY(24, Line, 48, 1);
1197
1198 if (Line == 14)
1199 Line = 16;
1200 else if (Line == 16)
1201 Line = 11;
1202 else
1203 Line++;
1204
1205 CONSOLE_InvertTextXY(24, Line, 48, 1);
1206 }
1207 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1208 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1209 {
1210 CONSOLE_NormalTextXY(24, Line, 48, 1);
1211
1212 if (Line == 11)
1213 Line = 16;
1214 else if (Line == 16)
1215 Line = 14;
1216 else
1217 Line--;
1218
1219 CONSOLE_InvertTextXY(24, Line, 48, 1);
1220 }
1221 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1222 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1223 {
1224 if (ConfirmQuit(Ir))
1225 return QUIT_PAGE;
1226
1227 break;
1228 }
1229 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1230 {
1231 if (Line == 11)
1232 return COMPUTER_SETTINGS_PAGE;
1233 else if (Line == 12)
1234 return DISPLAY_SETTINGS_PAGE;
1235 else if (Line == 13)
1236 return KEYBOARD_SETTINGS_PAGE;
1237 else if (Line == 14)
1238 return LAYOUT_SETTINGS_PAGE;
1239 else if (Line == 16)
1240 return SELECT_PARTITION_PAGE;
1241 }
1242 }
1243
1244 return DEVICE_SETTINGS_PAGE;
1245 }
1246
1247
1248 /*
1249 * Handles generic selection lists.
1250 *
1251 * PARAMS
1252 * GenericList: The list to handle.
1253 * nextPage: The page it needs to jump to after this page.
1254 * Ir: The PINPUT_RECORD
1255 */
1256 static PAGE_NUMBER
1257 HandleGenericList(PGENERIC_LIST_UI ListUi,
1258 PAGE_NUMBER nextPage,
1259 PINPUT_RECORD Ir)
1260 {
1261 while (TRUE)
1262 {
1263 CONSOLE_ConInKey(Ir);
1264
1265 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1266 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1267 {
1268 ScrollDownGenericList(ListUi);
1269 }
1270 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1271 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1272 {
1273 ScrollUpGenericList(ListUi);
1274 }
1275 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1276 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
1277 {
1278 ScrollPageDownGenericList(ListUi);
1279 }
1280 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1281 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
1282 {
1283 ScrollPageUpGenericList(ListUi);
1284 }
1285 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1286 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1287 {
1288 if (ConfirmQuit(Ir))
1289 return QUIT_PAGE;
1290 else
1291 RedrawGenericList(ListUi);
1292 }
1293 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1294 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
1295 {
1296 RestoreGenericListUiState(ListUi);
1297 return nextPage; // Use some "prevPage;" instead?
1298 }
1299 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
1300 {
1301 return nextPage;
1302 }
1303 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
1304 {
1305 /* a-z */
1306 GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
1307 }
1308 }
1309 }
1310
1311
1312 /*
1313 * Displays the ComputerSettingsPage.
1314 *
1315 * Next pages:
1316 * DeviceSettingsPage
1317 * QuitPage
1318 *
1319 * RETURNS
1320 * Number of the next page.
1321 */
1322 static PAGE_NUMBER
1323 ComputerSettingsPage(PINPUT_RECORD Ir)
1324 {
1325 GENERIC_LIST_UI ListUi;
1326 MUIDisplayPage(COMPUTER_SETTINGS_PAGE);
1327
1328 InitGenericListUi(&ListUi, USetupData.ComputerList, GetSettingDescription);
1329 DrawGenericList(&ListUi,
1330 2, 18,
1331 xScreen - 3,
1332 yScreen - 3);
1333
1334 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1335 }
1336
1337
1338 /*
1339 * Displays the DisplaySettingsPage.
1340 *
1341 * Next pages:
1342 * DeviceSettingsPage
1343 * QuitPage
1344 *
1345 * RETURNS
1346 * Number of the next page.
1347 */
1348 static PAGE_NUMBER
1349 DisplaySettingsPage(PINPUT_RECORD Ir)
1350 {
1351 GENERIC_LIST_UI ListUi;
1352 MUIDisplayPage(DISPLAY_SETTINGS_PAGE);
1353
1354 InitGenericListUi(&ListUi, USetupData.DisplayList, GetSettingDescription);
1355 DrawGenericList(&ListUi,
1356 2, 18,
1357 xScreen - 3,
1358 yScreen - 3);
1359
1360 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1361 }
1362
1363
1364 /*
1365 * Displays the KeyboardSettingsPage.
1366 *
1367 * Next pages:
1368 * DeviceSettingsPage
1369 * QuitPage
1370 *
1371 * RETURNS
1372 * Number of the next page.
1373 */
1374 static PAGE_NUMBER
1375 KeyboardSettingsPage(PINPUT_RECORD Ir)
1376 {
1377 GENERIC_LIST_UI ListUi;
1378 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE);
1379
1380 InitGenericListUi(&ListUi, USetupData.KeyboardList, GetSettingDescription);
1381 DrawGenericList(&ListUi,
1382 2, 18,
1383 xScreen - 3,
1384 yScreen - 3);
1385
1386 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1387 }
1388
1389
1390 /*
1391 * Displays the LayoutSettingsPage.
1392 *
1393 * Next pages:
1394 * DeviceSettingsPage
1395 * QuitPage
1396 *
1397 * RETURNS
1398 * Number of the next page.
1399 */
1400 static PAGE_NUMBER
1401 LayoutSettingsPage(PINPUT_RECORD Ir)
1402 {
1403 GENERIC_LIST_UI ListUi;
1404 MUIDisplayPage(LAYOUT_SETTINGS_PAGE);
1405
1406 InitGenericListUi(&ListUi, USetupData.LayoutList, GetSettingDescription);
1407 DrawGenericList(&ListUi,
1408 2, 18,
1409 xScreen - 3,
1410 yScreen - 3);
1411
1412 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir);
1413 }
1414
1415
1416 static BOOL
1417 IsDiskSizeValid(PPARTENTRY PartEntry)
1418 {
1419 ULONGLONG size;
1420
1421 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector;
1422 size = (size + (512 * KB)) / MB; /* in MBytes */
1423
1424 if (size < USetupData.RequiredPartitionDiskSpace)
1425 {
1426 /* Partition is too small so ask for another one */
1427 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, USetupData.RequiredPartitionDiskSpace);
1428 return FALSE;
1429 }
1430 else
1431 {
1432 return TRUE;
1433 }
1434 }
1435
1436
1437 /*
1438 * Displays the SelectPartitionPage.
1439 *
1440 * Next pages:
1441 * SelectFileSystemPage (At once if unattended)
1442 * SelectFileSystemPage (Default if free space is selected)
1443 * CreatePrimaryPartitionPage
1444 * CreateExtendedPartitionPage
1445 * CreateLogicalPartitionPage
1446 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set)
1447 * DeletePartitionPage
1448 * QuitPage
1449 *
1450 * SIDEEFFECTS
1451 * Set InstallShortcut (only if not unattended + free space is selected)
1452 *
1453 * RETURNS
1454 * Number of the next page.
1455 */
1456 static PAGE_NUMBER
1457 SelectPartitionPage(PINPUT_RECORD Ir)
1458 {
1459 PARTLIST_UI ListUi;
1460 ULONG Error;
1461
1462 if (PartitionList == NULL)
1463 {
1464 PartitionList = CreatePartitionList();
1465 if (PartitionList == NULL)
1466 {
1467 /* FIXME: show an error dialog */
1468 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER);
1469 return QUIT_PAGE;
1470 }
1471 else if (IsListEmpty(&PartitionList->DiskListHead))
1472 {
1473 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER);
1474 return QUIT_PAGE;
1475 }
1476
1477 /* Reset the formatter machine state */
1478 TempPartition = NULL;
1479 FormatState = Start;
1480 }
1481
1482 if (RepairUpdateFlag)
1483 {
1484 ASSERT(CurrentInstallation);
1485
1486 /* Determine the selected installation disk & partition */
1487 InstallPartition = SelectPartition(PartitionList,
1488 CurrentInstallation->DiskNumber,
1489 CurrentInstallation->PartitionNumber);
1490 if (!InstallPartition)
1491 {
1492 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
1493 ASSERT(FALSE);
1494 }
1495 ASSERT(!IsContainerPartition(InstallPartition->PartitionType));
1496
1497 return SELECT_FILE_SYSTEM_PAGE;
1498 }
1499
1500 MUIDisplayPage(SELECT_PARTITION_PAGE);
1501
1502 InitPartitionListUi(&ListUi, PartitionList,
1503 CurrentPartition,
1504 2, 23,
1505 xScreen - 3,
1506 yScreen - 3);
1507 DrawPartitionList(&ListUi);
1508
1509 if (IsUnattendedSetup)
1510 {
1511 /* Determine the selected installation disk & partition */
1512 InstallPartition = SelectPartition(PartitionList,
1513 USetupData.DestinationDiskNumber,
1514 USetupData.DestinationPartitionNumber);
1515 if (!InstallPartition)
1516 {
1517 CurrentPartition = ListUi.CurrentPartition;
1518
1519 if (USetupData.AutoPartition)
1520 {
1521 ASSERT(CurrentPartition != NULL);
1522 ASSERT(!IsContainerPartition(CurrentPartition->PartitionType));
1523
1524 if (CurrentPartition->LogicalPartition)
1525 {
1526 CreateLogicalPartition(PartitionList,
1527 CurrentPartition,
1528 CurrentPartition->SectorCount.QuadPart,
1529 TRUE);
1530 }
1531 else
1532 {
1533 CreatePrimaryPartition(PartitionList,
1534 CurrentPartition,
1535 CurrentPartition->SectorCount.QuadPart,
1536 TRUE);
1537 }
1538
1539 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1540 if (!IsDiskSizeValid(CurrentPartition))
1541 {
1542 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1543 USetupData.RequiredPartitionDiskSpace);
1544 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1545 }
1546
1547 InstallPartition = CurrentPartition;
1548 return SELECT_FILE_SYSTEM_PAGE;
1549 }
1550 }
1551 else
1552 {
1553 ASSERT(!IsContainerPartition(InstallPartition->PartitionType));
1554
1555 DrawPartitionList(&ListUi); // FIXME: Doesn't make much sense...
1556
1557 // FIXME?? Aren't we going to enter an infinite loop, if this test fails??
1558 if (!IsDiskSizeValid(InstallPartition))
1559 {
1560 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1561 USetupData.RequiredPartitionDiskSpace);
1562 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1563 }
1564
1565 return SELECT_FILE_SYSTEM_PAGE;
1566 }
1567 }
1568
1569 while (TRUE)
1570 {
1571 CurrentPartition = ListUi.CurrentPartition;
1572
1573 /* Update status text */
1574 if (CurrentPartition == NULL)
1575 {
1576 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1577 }
1578 else if (CurrentPartition->LogicalPartition)
1579 {
1580 if (CurrentPartition->IsPartitioned)
1581 {
1582 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1583 }
1584 else
1585 {
1586 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL));
1587 }
1588 }
1589 else
1590 {
1591 if (CurrentPartition->IsPartitioned)
1592 {
1593 if (IsContainerPartition(CurrentPartition->PartitionType))
1594 {
1595 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION));
1596 }
1597 else
1598 {
1599 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION));
1600 }
1601 }
1602 else
1603 {
1604 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION));
1605 }
1606 }
1607
1608 CONSOLE_ConInKey(Ir);
1609
1610 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1611 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1612 {
1613 if (ConfirmQuit(Ir))
1614 {
1615 DestroyPartitionList(PartitionList);
1616 PartitionList = NULL;
1617 return QUIT_PAGE;
1618 }
1619
1620 break;
1621 }
1622 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1623 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
1624 {
1625 ScrollDownPartitionList(&ListUi);
1626 }
1627 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1628 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
1629 {
1630 ScrollUpPartitionList(&ListUi);
1631 }
1632 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1633 {
1634 ASSERT(CurrentPartition != NULL);
1635
1636 if (IsContainerPartition(CurrentPartition->PartitionType))
1637 continue; // return SELECT_PARTITION_PAGE;
1638
1639 /*
1640 * Check whether the user wants to install ReactOS on a disk that
1641 * is not recognized by the computer's firmware and if so, display
1642 * a warning since such disks may not be bootable.
1643 */
1644 if (CurrentPartition->DiskEntry->MediaType == FixedMedia &&
1645 !CurrentPartition->DiskEntry->BiosFound)
1646 {
1647 PopupError("The disk you have selected for installing ReactOS\n"
1648 "is not visible by the firmware of your computer,\n"
1649 "and so may not be bootable.\n"
1650 "Press ENTER to continue nonetheless.",
1651 MUIGetString(STRING_CONTINUE),
1652 Ir, POPUP_WAIT_ENTER);
1653 // return SELECT_PARTITION_PAGE;
1654 }
1655
1656 if (CurrentPartition->IsPartitioned == FALSE)
1657 {
1658 if (CurrentPartition->LogicalPartition)
1659 {
1660 Error = LogicalPartitionCreationChecks(CurrentPartition);
1661 if (Error != NOT_AN_ERROR)
1662 {
1663 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1664 return SELECT_PARTITION_PAGE;
1665 }
1666
1667 CreateLogicalPartition(PartitionList,
1668 CurrentPartition,
1669 0ULL,
1670 TRUE);
1671 }
1672 else
1673 {
1674 Error = PrimaryPartitionCreationChecks(CurrentPartition);
1675 if (Error != NOT_AN_ERROR)
1676 {
1677 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1678 return SELECT_PARTITION_PAGE;
1679 }
1680
1681 CreatePrimaryPartition(PartitionList,
1682 CurrentPartition,
1683 0ULL,
1684 TRUE);
1685 }
1686 }
1687
1688 if (!IsDiskSizeValid(CurrentPartition))
1689 {
1690 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1691 USetupData.RequiredPartitionDiskSpace);
1692 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1693 }
1694
1695 InstallPartition = CurrentPartition;
1696 return SELECT_FILE_SYSTEM_PAGE;
1697 }
1698 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1699 {
1700 ASSERT(CurrentPartition != NULL);
1701
1702 if (CurrentPartition->LogicalPartition == FALSE)
1703 {
1704 Error = PrimaryPartitionCreationChecks(CurrentPartition);
1705 if (Error != NOT_AN_ERROR)
1706 {
1707 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1708 return SELECT_PARTITION_PAGE;
1709 }
1710
1711 return CREATE_PRIMARY_PARTITION_PAGE;
1712 }
1713 }
1714 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1715 {
1716 ASSERT(CurrentPartition != NULL);
1717
1718 if (CurrentPartition->LogicalPartition == FALSE)
1719 {
1720 Error = ExtendedPartitionCreationChecks(CurrentPartition);
1721 if (Error != NOT_AN_ERROR)
1722 {
1723 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1724 return SELECT_PARTITION_PAGE;
1725 }
1726
1727 return CREATE_EXTENDED_PARTITION_PAGE;
1728 }
1729 }
1730 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1731 {
1732 ASSERT(CurrentPartition != NULL);
1733
1734 if (CurrentPartition->LogicalPartition)
1735 {
1736 Error = LogicalPartitionCreationChecks(CurrentPartition);
1737 if (Error != NOT_AN_ERROR)
1738 {
1739 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1740 return SELECT_PARTITION_PAGE;
1741 }
1742
1743 return CREATE_LOGICAL_PARTITION_PAGE;
1744 }
1745 }
1746 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1747 {
1748 UNICODE_STRING CurrentPartitionU;
1749 WCHAR PathBuffer[MAX_PATH];
1750
1751 ASSERT(CurrentPartition != NULL);
1752
1753 if (CurrentPartition->IsPartitioned == FALSE)
1754 {
1755 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1756 return SELECT_PARTITION_PAGE;
1757 }
1758
1759 // TODO: Do something similar before trying to format the partition?
1760 if (!CurrentPartition->New &&
1761 !IsContainerPartition(CurrentPartition->PartitionType) &&
1762 CurrentPartition->FormatState != Unformatted)
1763 {
1764 ASSERT(CurrentPartition->PartitionNumber != 0);
1765
1766 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
1767 L"\\Device\\Harddisk%lu\\Partition%lu\\",
1768 CurrentPartition->DiskEntry->DiskNumber,
1769 CurrentPartition->PartitionNumber);
1770 RtlInitUnicodeString(&CurrentPartitionU, PathBuffer);
1771
1772 /*
1773 * Check whether the user attempts to delete the partition on which
1774 * the installation source is present. If so, fail with an error.
1775 */
1776 // &USetupData.SourceRootPath
1777 if (RtlPrefixUnicodeString(&CurrentPartitionU, &USetupData.SourcePath, TRUE))
1778 {
1779 PopupError("You cannot delete the partition containing the installation source!",
1780 MUIGetString(STRING_CONTINUE),
1781 Ir, POPUP_WAIT_ENTER);
1782 return SELECT_PARTITION_PAGE;
1783 }
1784 }
1785
1786 // FIXME TODO: PartitionList->SystemPartition is not yet initialized!!!!
1787 if (CurrentPartition == PartitionList->SystemPartition ||
1788 CurrentPartition->BootIndicator)
1789 {
1790 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1791 }
1792
1793 return DELETE_PARTITION_PAGE;
1794 }
1795 }
1796
1797 return SELECT_PARTITION_PAGE;
1798 }
1799
1800
1801 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1802 /* Restriction for MaxSize */
1803 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1804
1805 static VOID
1806 ShowPartitionSizeInputBox(SHORT Left,
1807 SHORT Top,
1808 SHORT Right,
1809 SHORT Bottom,
1810 ULONG MaxSize,
1811 PWSTR InputBuffer,
1812 PBOOLEAN Quit,
1813 PBOOLEAN Cancel)
1814 {
1815 INPUT_RECORD Ir;
1816 COORD coPos;
1817 DWORD Written;
1818 CHAR Buffer[128];
1819 INT Length, Pos;
1820 WCHAR ch;
1821 SHORT iLeft;
1822 SHORT iTop;
1823
1824 if (Quit != NULL)
1825 *Quit = FALSE;
1826
1827 if (Cancel != NULL)
1828 *Cancel = FALSE;
1829
1830 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1831
1832 /* Print message */
1833 coPos.X = Left + 2;
1834 coPos.Y = Top + 2;
1835 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1836 iLeft = coPos.X + strlen(Buffer) + 1;
1837 iTop = coPos.Y;
1838
1839 WriteConsoleOutputCharacterA(StdOutput,
1840 Buffer,
1841 strlen(Buffer),
1842 coPos,
1843 &Written);
1844
1845 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1846 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1847 coPos.Y = iTop;
1848 WriteConsoleOutputCharacterA(StdOutput,
1849 Buffer,
1850 strlen(Buffer),
1851 coPos,
1852 &Written);
1853
1854 swprintf(InputBuffer, L"%lu", MaxSize);
1855 Length = wcslen(InputBuffer);
1856 Pos = Length;
1857 CONSOLE_SetInputTextXY(iLeft,
1858 iTop,
1859 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1860 InputBuffer);
1861 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1862 CONSOLE_SetCursorType(TRUE, TRUE);
1863
1864 while (TRUE)
1865 {
1866 CONSOLE_ConInKey(&Ir);
1867
1868 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1869 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1870 {
1871 if (Quit != NULL)
1872 *Quit = TRUE;
1873
1874 InputBuffer[0] = UNICODE_NULL;
1875 CONSOLE_SetCursorType(TRUE, FALSE);
1876 break;
1877 }
1878 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1879 {
1880 CONSOLE_SetCursorType(TRUE, FALSE);
1881 break;
1882 }
1883 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1884 {
1885 if (Cancel != NULL)
1886 *Cancel = TRUE;
1887
1888 InputBuffer[0] = UNICODE_NULL;
1889 CONSOLE_SetCursorType(TRUE, FALSE);
1890 break;
1891 }
1892 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1893 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1894 {
1895 Pos = 0;
1896 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1897 }
1898 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1899 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1900 {
1901 Pos = Length;
1902 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1903 }
1904 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1905 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1906 {
1907 if (Pos > 0)
1908 {
1909 Pos--;
1910 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1911 }
1912 }
1913 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1914 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1915 {
1916 if (Pos < Length)
1917 {
1918 Pos++;
1919 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1920 }
1921 }
1922 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1923 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1924 {
1925 if (Pos < Length)
1926 {
1927 memmove(&InputBuffer[Pos],
1928 &InputBuffer[Pos + 1],
1929 (Length - Pos - 1) * sizeof(WCHAR));
1930 InputBuffer[Length - 1] = UNICODE_NULL;
1931
1932 Length--;
1933 CONSOLE_SetInputTextXY(iLeft,
1934 iTop,
1935 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1936 InputBuffer);
1937 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1938 }
1939 }
1940 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
1941 {
1942 if (Pos > 0)
1943 {
1944 if (Pos < Length)
1945 memmove(&InputBuffer[Pos - 1],
1946 &InputBuffer[Pos],
1947 (Length - Pos) * sizeof(WCHAR));
1948 InputBuffer[Length - 1] = UNICODE_NULL;
1949
1950 Pos--;
1951 Length--;
1952 CONSOLE_SetInputTextXY(iLeft,
1953 iTop,
1954 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1955 InputBuffer);
1956 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1957 }
1958 }
1959 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
1960 {
1961 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
1962 {
1963 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1964
1965 if ((ch >= L'0') && (ch <= L'9'))
1966 {
1967 if (Pos < Length)
1968 memmove(&InputBuffer[Pos + 1],
1969 &InputBuffer[Pos],
1970 (Length - Pos) * sizeof(WCHAR));
1971 InputBuffer[Length + 1] = UNICODE_NULL;
1972 InputBuffer[Pos] = ch;
1973
1974 Pos++;
1975 Length++;
1976 CONSOLE_SetInputTextXY(iLeft,
1977 iTop,
1978 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1979 InputBuffer);
1980 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1981 }
1982 }
1983 }
1984 }
1985 }
1986
1987
1988 /*
1989 * Displays the CreatePrimaryPartitionPage.
1990 *
1991 * Next pages:
1992 * SelectPartitionPage
1993 * SelectFileSystemPage (default)
1994 * QuitPage
1995 *
1996 * RETURNS
1997 * Number of the next page.
1998 */
1999 static PAGE_NUMBER
2000 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
2001 {
2002 PPARTENTRY PartEntry;
2003 PDISKENTRY DiskEntry;
2004 BOOLEAN Quit;
2005 BOOLEAN Cancel;
2006 WCHAR InputBuffer[50];
2007 ULONG MaxSize;
2008 ULONGLONG PartSize;
2009 ULONGLONG DiskSize;
2010 ULONGLONG SectorCount;
2011 PCHAR Unit;
2012
2013 if (PartitionList == NULL || CurrentPartition == NULL)
2014 {
2015 /* FIXME: show an error dialog */
2016 return QUIT_PAGE;
2017 }
2018
2019 PartEntry = CurrentPartition;
2020 DiskEntry = CurrentPartition->DiskEntry;
2021
2022 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2023
2024 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
2025
2026 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2027 #if 0
2028 if (DiskSize >= 10 * GB) /* 10 GB */
2029 {
2030 DiskSize = DiskSize / GB;
2031 Unit = MUIGetString(STRING_GB);
2032 }
2033 else
2034 #endif
2035 {
2036 DiskSize = DiskSize / MB;
2037 if (DiskSize == 0)
2038 DiskSize = 1;
2039
2040 Unit = MUIGetString(STRING_MB);
2041 }
2042
2043 if (DiskEntry->DriverName.Length > 0)
2044 {
2045 CONSOLE_PrintTextXY(6, 10,
2046 MUIGetString(STRING_HDINFOPARTCREATE_1),
2047 DiskSize,
2048 Unit,
2049 DiskEntry->DiskNumber,
2050 DiskEntry->Port,
2051 DiskEntry->Bus,
2052 DiskEntry->Id,
2053 &DiskEntry->DriverName,
2054 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2055 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2056 "RAW");
2057 }
2058 else
2059 {
2060 CONSOLE_PrintTextXY(6, 10,
2061 MUIGetString(STRING_HDINFOPARTCREATE_2),
2062 DiskSize,
2063 Unit,
2064 DiskEntry->DiskNumber,
2065 DiskEntry->Port,
2066 DiskEntry->Bus,
2067 DiskEntry->Id,
2068 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2069 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2070 "RAW");
2071 }
2072
2073 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2074
2075 #if 0
2076 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2077 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2078 #endif
2079
2080 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2081
2082 PartEntry = CurrentPartition;
2083 while (TRUE)
2084 {
2085 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2086
2087 if (MaxSize > PARTITION_MAXSIZE)
2088 MaxSize = PARTITION_MAXSIZE;
2089
2090 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2091 MaxSize, InputBuffer, &Quit, &Cancel);
2092
2093 if (Quit)
2094 {
2095 if (ConfirmQuit(Ir))
2096 return QUIT_PAGE;
2097
2098 break;
2099 }
2100 else if (Cancel)
2101 {
2102 return SELECT_PARTITION_PAGE;
2103 }
2104 else
2105 {
2106 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2107
2108 if (PartSize < 1)
2109 {
2110 /* Too small */
2111 continue;
2112 }
2113
2114 if (PartSize > MaxSize)
2115 {
2116 /* Too large */
2117 continue;
2118 }
2119
2120 /* Convert to bytes */
2121 if (PartSize == MaxSize)
2122 {
2123 /* Use all of the unpartitioned disk space */
2124 SectorCount = PartEntry->SectorCount.QuadPart;
2125 }
2126 else
2127 {
2128 /* Calculate the sector count from the size in MB */
2129 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2130
2131 /* But never get larger than the unpartitioned disk space */
2132 if (SectorCount > PartEntry->SectorCount.QuadPart)
2133 SectorCount = PartEntry->SectorCount.QuadPart;
2134 }
2135
2136 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2137
2138 CreatePrimaryPartition(PartitionList,
2139 CurrentPartition,
2140 SectorCount,
2141 FALSE);
2142
2143 return SELECT_PARTITION_PAGE;
2144 }
2145 }
2146
2147 return CREATE_PRIMARY_PARTITION_PAGE;
2148 }
2149
2150
2151 /*
2152 * Displays the CreateExtendedPartitionPage.
2153 *
2154 * Next pages:
2155 * SelectPartitionPage (default)
2156 * QuitPage
2157 *
2158 * RETURNS
2159 * Number of the next page.
2160 */
2161 static PAGE_NUMBER
2162 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2163 {
2164 PPARTENTRY PartEntry;
2165 PDISKENTRY DiskEntry;
2166 BOOLEAN Quit;
2167 BOOLEAN Cancel;
2168 WCHAR InputBuffer[50];
2169 ULONG MaxSize;
2170 ULONGLONG PartSize;
2171 ULONGLONG DiskSize;
2172 ULONGLONG SectorCount;
2173 PCHAR Unit;
2174
2175 if (PartitionList == NULL || CurrentPartition == NULL)
2176 {
2177 /* FIXME: show an error dialog */
2178 return QUIT_PAGE;
2179 }
2180
2181 PartEntry = CurrentPartition;
2182 DiskEntry = CurrentPartition->DiskEntry;
2183
2184 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2185
2186 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2187
2188 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2189 #if 0
2190 if (DiskSize >= 10 * GB) /* 10 GB */
2191 {
2192 DiskSize = DiskSize / GB;
2193 Unit = MUIGetString(STRING_GB);
2194 }
2195 else
2196 #endif
2197 {
2198 DiskSize = DiskSize / MB;
2199 if (DiskSize == 0)
2200 DiskSize = 1;
2201
2202 Unit = MUIGetString(STRING_MB);
2203 }
2204
2205 if (DiskEntry->DriverName.Length > 0)
2206 {
2207 CONSOLE_PrintTextXY(6, 10,
2208 MUIGetString(STRING_HDINFOPARTCREATE_1),
2209 DiskSize,
2210 Unit,
2211 DiskEntry->DiskNumber,
2212 DiskEntry->Port,
2213 DiskEntry->Bus,
2214 DiskEntry->Id,
2215 &DiskEntry->DriverName,
2216 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2217 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2218 "RAW");
2219 }
2220 else
2221 {
2222 CONSOLE_PrintTextXY(6, 10,
2223 MUIGetString(STRING_HDINFOPARTCREATE_2),
2224 DiskSize,
2225 Unit,
2226 DiskEntry->DiskNumber,
2227 DiskEntry->Port,
2228 DiskEntry->Bus,
2229 DiskEntry->Id,
2230 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2231 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2232 "RAW");
2233 }
2234
2235 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2236
2237 #if 0
2238 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2239 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2240 #endif
2241
2242 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2243
2244 PartEntry = CurrentPartition;
2245 while (TRUE)
2246 {
2247 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2248
2249 if (MaxSize > PARTITION_MAXSIZE)
2250 MaxSize = PARTITION_MAXSIZE;
2251
2252 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2253 MaxSize, InputBuffer, &Quit, &Cancel);
2254
2255 if (Quit)
2256 {
2257 if (ConfirmQuit(Ir))
2258 return QUIT_PAGE;
2259
2260 break;
2261 }
2262 else if (Cancel)
2263 {
2264 return SELECT_PARTITION_PAGE;
2265 }
2266 else
2267 {
2268 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2269
2270 if (PartSize < 1)
2271 {
2272 /* Too small */
2273 continue;
2274 }
2275
2276 if (PartSize > MaxSize)
2277 {
2278 /* Too large */
2279 continue;
2280 }
2281
2282 /* Convert to bytes */
2283 if (PartSize == MaxSize)
2284 {
2285 /* Use all of the unpartitioned disk space */
2286 SectorCount = PartEntry->SectorCount.QuadPart;
2287 }
2288 else
2289 {
2290 /* Calculate the sector count from the size in MB */
2291 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2292
2293 /* But never get larger than the unpartitioned disk space */
2294 if (SectorCount > PartEntry->SectorCount.QuadPart)
2295 SectorCount = PartEntry->SectorCount.QuadPart;
2296 }
2297
2298 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2299
2300 CreateExtendedPartition(PartitionList,
2301 CurrentPartition,
2302 SectorCount);
2303
2304 return SELECT_PARTITION_PAGE;
2305 }
2306 }
2307
2308 return CREATE_EXTENDED_PARTITION_PAGE;
2309 }
2310
2311
2312 /*
2313 * Displays the CreateLogicalPartitionPage.
2314 *
2315 * Next pages:
2316 * SelectFileSystemPage (default)
2317 * QuitPage
2318 *
2319 * RETURNS
2320 * Number of the next page.
2321 */
2322 static PAGE_NUMBER
2323 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2324 {
2325 PPARTENTRY PartEntry;
2326 PDISKENTRY DiskEntry;
2327 BOOLEAN Quit;
2328 BOOLEAN Cancel;
2329 WCHAR InputBuffer[50];
2330 ULONG MaxSize;
2331 ULONGLONG PartSize;
2332 ULONGLONG DiskSize;
2333 ULONGLONG SectorCount;
2334 PCHAR Unit;
2335
2336 if (PartitionList == NULL || CurrentPartition == NULL)
2337 {
2338 /* FIXME: show an error dialog */
2339 return QUIT_PAGE;
2340 }
2341
2342 PartEntry = CurrentPartition;
2343 DiskEntry = CurrentPartition->DiskEntry;
2344
2345 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2346
2347 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2348
2349 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2350 #if 0
2351 if (DiskSize >= 10 * GB) /* 10 GB */
2352 {
2353 DiskSize = DiskSize / GB;
2354 Unit = MUIGetString(STRING_GB);
2355 }
2356 else
2357 #endif
2358 {
2359 DiskSize = DiskSize / MB;
2360 if (DiskSize == 0)
2361 DiskSize = 1;
2362
2363 Unit = MUIGetString(STRING_MB);
2364 }
2365
2366 if (DiskEntry->DriverName.Length > 0)
2367 {
2368 CONSOLE_PrintTextXY(6, 10,
2369 MUIGetString(STRING_HDINFOPARTCREATE_1),
2370 DiskSize,
2371 Unit,
2372 DiskEntry->DiskNumber,
2373 DiskEntry->Port,
2374 DiskEntry->Bus,
2375 DiskEntry->Id,
2376 &DiskEntry->DriverName,
2377 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2378 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2379 "RAW");
2380 }
2381 else
2382 {
2383 CONSOLE_PrintTextXY(6, 10,
2384 MUIGetString(STRING_HDINFOPARTCREATE_2),
2385 DiskSize,
2386 Unit,
2387 DiskEntry->DiskNumber,
2388 DiskEntry->Port,
2389 DiskEntry->Bus,
2390 DiskEntry->Id,
2391 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2392 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2393 "RAW");
2394 }
2395
2396 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2397
2398 #if 0
2399 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2400 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2401 #endif
2402
2403 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2404
2405 PartEntry = CurrentPartition;
2406 while (TRUE)
2407 {
2408 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2409
2410 if (MaxSize > PARTITION_MAXSIZE)
2411 MaxSize = PARTITION_MAXSIZE;
2412
2413 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2414 MaxSize, InputBuffer, &Quit, &Cancel);
2415
2416 if (Quit)
2417 {
2418 if (ConfirmQuit(Ir))
2419 return QUIT_PAGE;
2420
2421 break;
2422 }
2423 else if (Cancel)
2424 {
2425 return SELECT_PARTITION_PAGE;
2426 }
2427 else
2428 {
2429 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2430
2431 if (PartSize < 1)
2432 {
2433 /* Too small */
2434 continue;
2435 }
2436
2437 if (PartSize > MaxSize)
2438 {
2439 /* Too large */
2440 continue;
2441 }
2442
2443 /* Convert to bytes */
2444 if (PartSize == MaxSize)
2445 {
2446 /* Use all of the unpartitioned disk space */
2447 SectorCount = PartEntry->SectorCount.QuadPart;
2448 }
2449 else
2450 {
2451 /* Calculate the sector count from the size in MB */
2452 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2453
2454 /* But never get larger than the unpartitioned disk space */
2455 if (SectorCount > PartEntry->SectorCount.QuadPart)
2456 SectorCount = PartEntry->SectorCount.QuadPart;
2457 }
2458
2459 DPRINT("Partition size: %I64u bytes\n", PartSize);
2460
2461 CreateLogicalPartition(PartitionList,
2462 CurrentPartition,
2463 SectorCount,
2464 FALSE);
2465
2466 return SELECT_PARTITION_PAGE;
2467 }
2468 }
2469
2470 return CREATE_LOGICAL_PARTITION_PAGE;
2471 }
2472
2473
2474 /*
2475 * Displays the ConfirmDeleteSystemPartitionPage.
2476 *
2477 * Next pages:
2478 * DeletePartitionPage (default)
2479 * SelectPartitionPage
2480 *
2481 * RETURNS
2482 * Number of the next page.
2483 */
2484 static PAGE_NUMBER
2485 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2486 {
2487 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2488
2489 while (TRUE)
2490 {
2491 CONSOLE_ConInKey(Ir);
2492
2493 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2494 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2495 {
2496 if (ConfirmQuit(Ir))
2497 return QUIT_PAGE;
2498
2499 break;
2500 }
2501 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2502 {
2503 return DELETE_PARTITION_PAGE;
2504 }
2505 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2506 {
2507 return SELECT_PARTITION_PAGE;
2508 }
2509 }
2510
2511 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2512 }
2513
2514
2515 /*
2516 * Displays the DeletePartitionPage.
2517 *
2518 * Next pages:
2519 * SelectPartitionPage (default)
2520 * QuitPage
2521 *
2522 * RETURNS
2523 * Number of the next page.
2524 */
2525 static PAGE_NUMBER
2526 DeletePartitionPage(PINPUT_RECORD Ir)
2527 {
2528 PPARTENTRY PartEntry;
2529 PDISKENTRY DiskEntry;
2530 ULONGLONG DiskSize;
2531 ULONGLONG PartSize;
2532 PCHAR Unit;
2533 CHAR PartTypeString[32];
2534
2535 if (PartitionList == NULL || CurrentPartition == NULL)
2536 {
2537 /* FIXME: show an error dialog */
2538 return QUIT_PAGE;
2539 }
2540
2541 PartEntry = CurrentPartition;
2542 DiskEntry = CurrentPartition->DiskEntry;
2543
2544 MUIDisplayPage(DELETE_PARTITION_PAGE);
2545
2546 /* Adjust partition type */
2547 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2548 PartTypeString,
2549 ARRAYSIZE(PartTypeString));
2550
2551 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2552 #if 0
2553 if (PartSize >= 10 * GB) /* 10 GB */
2554 {
2555 PartSize = PartSize / GB;
2556 Unit = MUIGetString(STRING_GB);
2557 }
2558 else
2559 #endif
2560 if (PartSize >= 10 * MB) /* 10 MB */
2561 {
2562 PartSize = PartSize / MB;
2563 Unit = MUIGetString(STRING_MB);
2564 }
2565 else
2566 {
2567 PartSize = PartSize / KB;
2568 Unit = MUIGetString(STRING_KB);
2569 }
2570
2571 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2572 {
2573 CONSOLE_PrintTextXY(6, 10,
2574 MUIGetString(STRING_HDDINFOUNK2),
2575 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2576 (PartEntry->DriveLetter == 0) ? '-' : ':',
2577 PartEntry->PartitionType,
2578 PartSize,
2579 Unit);
2580 }
2581 else
2582 {
2583 CONSOLE_PrintTextXY(6, 10,
2584 " %c%c %s %I64u %s",
2585 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2586 (PartEntry->DriveLetter == 0) ? '-' : ':',
2587 PartTypeString,
2588 PartSize,
2589 Unit);
2590 }
2591
2592 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2593 #if 0
2594 if (DiskSize >= 10 * GB) /* 10 GB */
2595 {
2596 DiskSize = DiskSize / GB;
2597 Unit = MUIGetString(STRING_GB);
2598 }
2599 else
2600 #endif
2601 {
2602 DiskSize = DiskSize / MB;
2603 if (DiskSize == 0)
2604 DiskSize = 1;
2605
2606 Unit = MUIGetString(STRING_MB);
2607 }
2608
2609 if (DiskEntry->DriverName.Length > 0)
2610 {
2611 CONSOLE_PrintTextXY(6, 12,
2612 MUIGetString(STRING_HDINFOPARTDELETE_1),
2613 DiskSize,
2614 Unit,
2615 DiskEntry->DiskNumber,
2616 DiskEntry->Port,
2617 DiskEntry->Bus,
2618 DiskEntry->Id,
2619 &DiskEntry->DriverName,
2620 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2621 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2622 "RAW");
2623 }
2624 else
2625 {
2626 CONSOLE_PrintTextXY(6, 12,
2627 MUIGetString(STRING_HDINFOPARTDELETE_2),
2628 DiskSize,
2629 Unit,
2630 DiskEntry->DiskNumber,
2631 DiskEntry->Port,
2632 DiskEntry->Bus,
2633 DiskEntry->Id,
2634 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2635 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2636 "RAW");
2637 }
2638
2639 while (TRUE)
2640 {
2641 CONSOLE_ConInKey(Ir);
2642
2643 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2644 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2645 {
2646 if (ConfirmQuit(Ir))
2647 return QUIT_PAGE;
2648
2649 break;
2650 }
2651 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2652 {
2653 return SELECT_PARTITION_PAGE;
2654 }
2655 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2656 {
2657 DeletePartition(PartitionList,
2658 CurrentPartition,
2659 &CurrentPartition);
2660 return SELECT_PARTITION_PAGE;
2661 }
2662 }
2663
2664 return DELETE_PARTITION_PAGE;
2665 }
2666
2667
2668 static VOID
2669 ResetFileSystemList(VOID)
2670 {
2671 if (!FileSystemList)
2672 return;
2673
2674 DestroyFileSystemList(FileSystemList);
2675 FileSystemList = NULL;
2676 }
2677
2678 /*
2679 * Displays the SelectFileSystemPage.
2680 *
2681 * Next pages:
2682 * CheckFileSystemPage (At once if RepairUpdate is selected)
2683 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2684 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2685 * SelectPartitionPage (If the user aborts)
2686 * FormatPartitionPage (Default)
2687 * QuitPage
2688 *
2689 * SIDEEFFECTS
2690 * Calls UpdatePartitionType()
2691 * Calls CheckActiveSystemPartition()
2692 *
2693 * RETURNS
2694 * Number of the next page.
2695 */
2696 static PAGE_NUMBER
2697 SelectFileSystemPage(PINPUT_RECORD Ir)
2698 {
2699 PPARTENTRY PartEntry;
2700 PDISKENTRY DiskEntry;
2701 ULONGLONG DiskSize;
2702 ULONGLONG PartSize;
2703 PCHAR DiskUnit;
2704 PCHAR PartUnit;
2705 CHAR PartTypeString[32];
2706 FORMATMACHINESTATE PreviousFormatState;
2707 PCWSTR DefaultFs;
2708
2709 DPRINT("SelectFileSystemPage()\n");
2710
2711 if (PartitionList == NULL || InstallPartition == NULL)
2712 {
2713 /* FIXME: show an error dialog */
2714 return QUIT_PAGE;
2715 }
2716
2717 /* Find or set the active system partition when starting formatting */
2718 if (FormatState == Start)
2719 {
2720 /* Find or set the active system partition */
2721 CheckActiveSystemPartition(PartitionList,
2722 FALSE,
2723 InstallPartition->DiskEntry,
2724 InstallPartition);
2725 if (PartitionList->SystemPartition == NULL)
2726 {
2727 /* FIXME: show an error dialog */
2728 //
2729 // Error dialog should say that we cannot find a suitable
2730 // system partition and create one on the system. At this point,
2731 // it may be nice to ask the user whether he wants to continue,
2732 // or use an external drive as the system drive/partition
2733 // (e.g. floppy, USB drive, etc...)
2734 //
2735 return QUIT_PAGE;
2736 }
2737
2738 /*
2739 * If the system partition can be created in some
2740 * non-partitioned space, create it now.
2741 */
2742 if (!PartitionList->SystemPartition->IsPartitioned)
2743 {
2744 // if (IsUnattendedSetup)
2745 {
2746 CreatePrimaryPartition(PartitionList,
2747 PartitionList->SystemPartition,
2748 0LL, // PartitionList->SystemPartition->SectorCount.QuadPart,
2749 TRUE);
2750 ASSERT(PartitionList->SystemPartition->IsPartitioned);
2751 }
2752 // else
2753 {
2754 }
2755 }
2756
2757 /* Commit all partition changes to all the disks */
2758 if (!WritePartitionsToDisk(PartitionList))
2759 {
2760 DPRINT("WritePartitionsToDisk() failed\n");
2761 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
2762 return QUIT_PAGE;
2763 }
2764
2765 /*
2766 * In all cases, whether or not we are going to perform a formatting,
2767 * we must perform a filesystem check of both the system and the
2768 * installation partitions.
2769 */
2770 InstallPartition->NeedsCheck = TRUE;
2771 if (PartitionList->SystemPartition != InstallPartition)
2772 PartitionList->SystemPartition->NeedsCheck = TRUE;
2773
2774 /*
2775 * In case we just repair an existing installation, or make
2776 * an unattended setup without formatting, just go to the
2777 * filesystem check step.
2778 */
2779 if (RepairUpdateFlag)
2780 return CHECK_FILE_SYSTEM_PAGE;
2781
2782 if (IsUnattendedSetup && !USetupData.FormatPartition)
2783 return CHECK_FILE_SYSTEM_PAGE;
2784 }
2785
2786 // ASSERT(PartitionList->SystemPartition->IsPartitioned);
2787
2788 /* Reset the filesystem list for each partition that is to be formatted */
2789 ResetFileSystemList();
2790
2791 PreviousFormatState = FormatState;
2792 switch (FormatState)
2793 {
2794 case Start:
2795 {
2796 /*
2797 * We start by formatting the system partition in case it is new
2798 * (it didn't exist before) and is not the same as the installation
2799 * partition. Otherwise we just require a filesystem check on it,
2800 * and start by formatting the installation partition instead.
2801 */
2802
2803 ASSERT(PartitionList->SystemPartition->IsPartitioned);
2804
2805 if ((PartitionList->SystemPartition != InstallPartition) &&
2806 (PartitionList->SystemPartition->FormatState == Unformatted))
2807 {
2808 TempPartition = PartitionList->SystemPartition;
2809 TempPartition->NeedsCheck = TRUE;
2810
2811 // TODO: Should we let the user using a custom file-system,
2812 // or should we always use FAT(32) for it?
2813 // For "compatibility", FAT(32) would be best indeed.
2814
2815 FormatState = FormatSystemPartition;
2816 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2817 }
2818 else
2819 {
2820 TempPartition = InstallPartition;
2821 TempPartition->NeedsCheck = TRUE;
2822
2823 if (PartitionList->SystemPartition != InstallPartition)
2824 {
2825 /* The system partition is separate, so it had better be formatted! */
2826 ASSERT((PartitionList->SystemPartition->FormatState == Preformatted) ||
2827 (PartitionList->SystemPartition->FormatState == Formatted));
2828
2829 /* Require a filesystem check on the system partition too */
2830 PartitionList->SystemPartition->NeedsCheck = TRUE;
2831 }
2832
2833 FormatState = FormatInstallPartition;
2834 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2835 }
2836 break;
2837 }
2838
2839 case FormatSystemPartition:
2840 {
2841 TempPartition = InstallPartition;
2842 TempPartition->NeedsCheck = TRUE;
2843
2844 FormatState = FormatInstallPartition;
2845 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2846 break;
2847 }
2848
2849 case FormatInstallPartition:
2850 case FormatOtherPartition:
2851 {
2852 if (GetNextUnformattedPartition(PartitionList,
2853 NULL,
2854 &TempPartition))
2855 {
2856 FormatState = FormatOtherPartition;
2857 TempPartition->NeedsCheck = TRUE;
2858
2859 if (FormatState == FormatInstallPartition)
2860 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2861 else
2862 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2863 }
2864 else
2865 {
2866 FormatState = FormatDone;
2867
2868 if (FormatState == FormatInstallPartition)
2869 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2870 else
2871 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2872
2873 return CHECK_FILE_SYSTEM_PAGE;
2874 }
2875 break;
2876 }
2877
2878 case FormatDone:
2879 {
2880 DPRINT1("FormatState: FormatDone\n");
2881 return CHECK_FILE_SYSTEM_PAGE;
2882 }
2883
2884 default:
2885 {
2886 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2887 /* FIXME: show an error dialog */
2888 return QUIT_PAGE;
2889 }
2890 }
2891
2892 PartEntry = TempPartition;
2893 DiskEntry = TempPartition->DiskEntry;
2894
2895 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
2896
2897 /* Adjust disk size */
2898 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2899 if (DiskSize >= 10 * GB) /* 10 GB */
2900 {
2901 DiskSize = DiskSize / GB;
2902 DiskUnit = MUIGetString(STRING_GB);
2903 }
2904 else
2905 {
2906 DiskSize = DiskSize / MB;
2907 DiskUnit = MUIGetString(STRING_MB);
2908 }
2909
2910 /* Adjust partition size */
2911 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2912 if (PartSize >= 10 * GB) /* 10 GB */
2913 {
2914 PartSize = PartSize / GB;
2915 PartUnit = MUIGetString(STRING_GB);
2916 }
2917 else
2918 {
2919 PartSize = PartSize / MB;
2920 PartUnit = MUIGetString(STRING_MB);
2921 }
2922
2923 /* Adjust partition type */
2924 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2925 PartTypeString,
2926 ARRAYSIZE(PartTypeString));
2927
2928 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2929
2930 if (PartEntry->AutoCreate)
2931 {
2932 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2933
2934 #if 0
2935 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2936 PartEntry->PartitionNumber,
2937 PartSize,
2938 PartUnit,
2939 PartTypeString);
2940 #endif
2941
2942 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
2943 DiskEntry->DiskNumber,
2944 DiskSize,
2945 DiskUnit,
2946 DiskEntry->Port,
2947 DiskEntry->Bus,
2948 DiskEntry->Id,
2949 &DiskEntry->DriverName,
2950 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
2951 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
2952 "RAW");
2953
2954 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2955
2956 PartEntry->AutoCreate = FALSE;
2957 }
2958 else if (PartEntry->New)
2959 {
2960 switch (FormatState)
2961 {
2962 case FormatSystemPartition:
2963 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2964 break;
2965
2966 case FormatInstallPartition:
2967 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2968 break;
2969
2970 case FormatOtherPartition:
2971 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2972 break;
2973
2974 default:
2975 break;
2976 }
2977
2978 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2979 }
2980 else
2981 {
2982 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2983
2984 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2985 {
2986 CONSOLE_PrintTextXY(8, 10,
2987 MUIGetString(STRING_HDDINFOUNK4),
2988 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2989 (PartEntry->DriveLetter == 0) ? '-' : ':',
2990 PartEntry->PartitionType,
2991 PartSize,
2992 PartUnit);
2993 }
2994 else
2995 {
2996 CONSOLE_PrintTextXY(8, 10,
2997 "%c%c %s %I64u %s",
2998 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2999 (PartEntry->DriveLetter == 0) ? '-' : ':',
3000 PartTypeString,
3001 PartSize,
3002 PartUnit);
3003 }
3004
3005 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
3006 DiskEntry->DiskNumber,
3007 DiskSize,
3008 DiskUnit,
3009 DiskEntry->Port,
3010 DiskEntry->Bus,
3011 DiskEntry->Id,
3012 &DiskEntry->DriverName,
3013 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" :
3014 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" :
3015 "RAW");
3016 }
3017
3018 ASSERT(FileSystemList == NULL);
3019
3020 if (IsUnattendedSetup)
3021 {
3022 ASSERT(USetupData.FormatPartition);
3023
3024 switch (USetupData.FsType)
3025 {
3026 /* 1 is for BtrFS */
3027 case 1:
3028 DefaultFs = L"BTRFS";
3029 break;
3030
3031 /* If we don't understand input, default to FAT */
3032 default:
3033 DefaultFs = L"FAT";
3034 break;
3035 }
3036 }
3037 else
3038 {
3039 /* By default select the "FAT" file system */
3040 DefaultFs = L"FAT";
3041 }
3042
3043 /* Create the file system list */
3044 // TODO: Display only the FSes compatible with the selected partition!
3045 FileSystemList = CreateFileSystemList(6, 26,
3046 PartEntry->New ||
3047 PartEntry->FormatState == Unformatted,
3048 DefaultFs);
3049 if (FileSystemList == NULL)
3050 {
3051 /* FIXME: show an error dialog */
3052 return QUIT_PAGE;
3053 }
3054
3055 if (IsUnattendedSetup)
3056 {
3057 ASSERT(USetupData.FormatPartition);
3058 return FORMAT_PARTITION_PAGE;
3059 }
3060
3061 DrawFileSystemList(FileSystemList);
3062
3063 while (TRUE)
3064 {
3065 CONSOLE_ConInKey(Ir);
3066
3067 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3068 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3069 {
3070 if (ConfirmQuit(Ir))
3071 {
3072 /* Reset the filesystem list */
3073 ResetFileSystemList();
3074 return QUIT_PAGE;
3075 }
3076
3077 break;
3078 }
3079 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3080 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
3081 {
3082 /* Reset the formatter machine state */
3083 TempPartition = NULL;
3084 FormatState = Start;
3085
3086 /* Reset the filesystem list */
3087 ResetFileSystemList();
3088
3089 return SELECT_PARTITION_PAGE;
3090 }
3091 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3092 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
3093 {
3094 ScrollDownFileSystemList(FileSystemList);
3095 }
3096 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3097 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
3098 {
3099 ScrollUpFileSystemList(FileSystemList);
3100 }
3101 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
3102 {
3103 if (!FileSystemList->Selected->FileSystem)
3104 {
3105 ASSERT(!TempPartition->New && TempPartition->FormatState != Unformatted);
3106
3107 /*
3108 * Skip formatting this partition. We will also ignore
3109 * filesystem checks on it, unless it is either the system
3110 * or the installation partition.
3111 */
3112 if (TempPartition != PartitionList->SystemPartition &&
3113 TempPartition != InstallPartition)
3114 {
3115 PartEntry->NeedsCheck = FALSE;
3116 }
3117
3118 return SELECT_FILE_SYSTEM_PAGE;
3119 }
3120 else
3121 {
3122 /* Format this partition */
3123 return FORMAT_PARTITION_PAGE;
3124 }
3125 }
3126 }
3127
3128 FormatState = PreviousFormatState;
3129
3130 return SELECT_FILE_SYSTEM_PAGE;
3131 }
3132
3133
3134 /*
3135 * Displays the FormatPartitionPage.
3136 *
3137 * Next pages:
3138 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
3139 * SelectPartitionPage (At once)
3140 * QuitPage
3141 *
3142 * SIDEEFFECTS
3143 * Sets InstallPartition->FormatState
3144 * Sets USetupData.DestinationRootPath
3145 *
3146 * RETURNS
3147 * Number of the next page.
3148 */
3149 static PAGE_NUMBER
3150 FormatPartitionPage(PINPUT_RECORD Ir)
3151 {
3152 NTSTATUS Status;
3153 PPARTENTRY PartEntry;
3154 PDISKENTRY DiskEntry;
3155 PFILE_SYSTEM_ITEM SelectedFileSystem;
3156 UNICODE_STRING PartitionRootPath;
3157 WCHAR PathBuffer[MAX_PATH];
3158 CHAR Buffer[MAX_PATH];
3159
3160 #ifndef NDEBUG
3161 ULONG Line;
3162 ULONG i;
3163 PPARTITION_INFORMATION PartitionInfo;
3164 #endif
3165
3166 DPRINT("FormatPartitionPage()\n");
3167
3168 MUIDisplayPage(FORMAT_PARTITION_PAGE);
3169
3170 if (PartitionList == NULL || TempPartition == NULL)
3171 {
3172 /* FIXME: show an error dialog */
3173 return QUIT_PAGE;
3174 }
3175
3176 PartEntry = TempPartition;
3177 DiskEntry = TempPartition->DiskEntry;
3178
3179 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
3180
3181 SelectedFileSystem = FileSystemList->Selected;
3182 ASSERT(SelectedFileSystem && SelectedFileSystem->FileSystem);
3183
3184 while (TRUE)
3185 {
3186 if (!IsUnattendedSetup)
3187 CONSOLE_ConInKey(Ir);
3188
3189 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3190 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3191 {
3192 if (ConfirmQuit(Ir))
3193 {
3194 /* Reset the filesystem list */
3195 ResetFileSystemList();
3196 return QUIT_PAGE;
3197 }
3198
3199 break;
3200 }
3201 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
3202 {
3203 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3204
3205 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
3206 {
3207 /* FIXME: show an error dialog */
3208
3209 /* Reset the filesystem list */
3210 ResetFileSystemList();
3211
3212 return QUIT_PAGE;
3213 }
3214
3215 #ifndef NDEBUG
3216 CONSOLE_PrintTextXY(6, 12,
3217 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
3218 DiskEntry->Cylinders,
3219 DiskEntry->TracksPerCylinder,
3220 DiskEntry->SectorsPerTrack,
3221 DiskEntry->BytesPerSector,
3222 DiskEntry->Dirty ? '*' : ' ');
3223
3224 Line = 13;
3225
3226 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
3227 {
3228 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
3229
3230 CONSOLE_PrintTextXY(6, Line,
3231 "%2u: %2lu %c %12I64u %12I64u %02x",
3232 i,
3233 PartitionInfo->PartitionNumber,
3234 PartitionInfo->BootIndicator ? 'A' : '-',
3235 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
3236 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
3237 PartitionInfo->PartitionType);
3238 Line++;
3239 }
3240 #endif
3241
3242 /* Commit the partition changes to the disk */
3243 Status = WritePartitions(DiskEntry);
3244 if (!NT_SUCCESS(Status))
3245 {
3246 DPRINT1("WritePartitions(disk %lu) failed, Status 0x%08lx\n",
3247 DiskEntry->DiskNumber, Status);
3248
3249 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3250
3251 /* Reset the filesystem list */
3252 ResetFileSystemList();
3253
3254 return QUIT_PAGE;
3255 }
3256
3257 /* Set PartitionRootPath */
3258 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3259 L"\\Device\\Harddisk%lu\\Partition%lu",
3260 DiskEntry->DiskNumber,
3261 PartEntry->PartitionNumber);
3262 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3263 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3264
3265 /* Format the partition */
3266 Status = FormatPartition(&PartitionRootPath,
3267 SelectedFileSystem->FileSystem,
3268 SelectedFileSystem->QuickFormat);
3269 if (Status == STATUS_NOT_SUPPORTED)
3270 {
3271 sprintf(Buffer,
3272 "Setup is currently unable to format a partition in %S.\n"
3273 "\n"
3274 " \x07 Press ENTER to continue Setup.\n"
3275 " \x07 Press F3 to quit Setup.",
3276 SelectedFileSystem->FileSystem);
3277
3278 PopupError(Buffer,
3279 MUIGetString(STRING_QUITCONTINUE),
3280 NULL, POPUP_WAIT_NONE);
3281
3282 while (TRUE)
3283 {
3284 CONSOLE_ConInKey(Ir);
3285
3286 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3287 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3288 {
3289 if (ConfirmQuit(Ir))
3290 {
3291 /* Reset the filesystem list */
3292 ResetFileSystemList();
3293 return QUIT_PAGE;
3294 }
3295 else
3296 {
3297 return SELECT_FILE_SYSTEM_PAGE;
3298 }
3299 }
3300 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3301 {
3302 return SELECT_FILE_SYSTEM_PAGE;
3303 }
3304 }
3305 }
3306 else if (!NT_SUCCESS(Status))
3307 {
3308 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3309 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3310
3311 /* Reset the filesystem list */
3312 ResetFileSystemList();
3313
3314 return QUIT_PAGE;
3315 }
3316
3317 //
3318 // TODO: Here, call a partlist.c function that update the actual FS name
3319 // and the label fields of the volume.
3320 //
3321 PartEntry->FormatState = Formatted;
3322 // PartEntry->FileSystem = FileSystem;
3323 PartEntry->New = FALSE;
3324
3325 #ifndef NDEBUG
3326 CONSOLE_SetStatusText(" Done. Press any key ...");
3327 CONSOLE_ConInKey(Ir);
3328 #endif
3329
3330 return SELECT_FILE_SYSTEM_PAGE;
3331 }
3332 }
3333
3334 return FORMAT_PARTITION_PAGE;
3335 }
3336
3337
3338 /*
3339 * Displays the CheckFileSystemPage.
3340 *
3341 * Next pages:
3342 * InstallDirectoryPage (At once)
3343 * QuitPage
3344 *
3345 * SIDEEFFECTS
3346 * Inits or reloads FileSystemList
3347 *
3348 * RETURNS
3349 * Number of the next page.
3350 */
3351 static PAGE_NUMBER
3352 CheckFileSystemPage(PINPUT_RECORD Ir)
3353 {
3354 NTSTATUS Status;
3355 PDISKENTRY DiskEntry;
3356 PPARTENTRY PartEntry;
3357 UNICODE_STRING PartitionRootPath;
3358 WCHAR PathBuffer[MAX_PATH];
3359 CHAR Buffer[MAX_PATH];
3360
3361 if (PartitionList == NULL)
3362 {
3363 /* FIXME: show an error dialog */
3364 return QUIT_PAGE;
3365 }
3366
3367 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3368 {
3369 return INSTALL_DIRECTORY_PAGE;
3370 }
3371
3372 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
3373
3374 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3375
3376 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3377
3378 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystem: %S\n",
3379 PartEntry->PartitionType, (*PartEntry->FileSystem ? PartEntry->FileSystem : L"n/a"));
3380
3381 /* HACK: Do not try to check a partition with an unknown filesystem */
3382 if (!*PartEntry->FileSystem)
3383 {
3384 PartEntry->NeedsCheck = FALSE;
3385 return CHECK_FILE_SYSTEM_PAGE;
3386 }
3387
3388 /* Set PartitionRootPath */
3389 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3390 L"\\Device\\Harddisk%lu\\Partition%lu",
3391 DiskEntry->DiskNumber,
3392 PartEntry->PartitionNumber);
3393 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3394 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3395
3396 /* Check the partition */
3397 Status = ChkdskPartition(&PartitionRootPath, PartEntry->FileSystem);
3398 if (Status == STATUS_NOT_SUPPORTED)
3399 {
3400 /*
3401 * Partition checking is not supported with the current filesystem,
3402 * so disable FS checks on it.
3403 */
3404 PartEntry->NeedsCheck = FALSE;
3405
3406 sprintf(Buffer,
3407 "Setup is currently unable to check a partition formatted in %S.\n"
3408 "\n"
3409 " \x07 Press ENTER to continue Setup.\n"
3410 " \x07 Press F3 to quit Setup.",
3411 PartEntry->FileSystem);
3412
3413 PopupError(Buffer,
3414 MUIGetString(STRING_QUITCONTINUE),
3415 NULL, POPUP_WAIT_NONE);
3416
3417 while (TRUE)
3418 {
3419 CONSOLE_ConInKey(Ir);
3420
3421 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&