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