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