48645eca32e8bd78c823ce9eb0e98b8bf5bb6010
[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 "format.h"
35
36 #define NDEBUG
37 #include <debug.h>
38
39
40 /* GLOBALS & LOCALS *********************************************************/
41
42 HANDLE ProcessHeap;
43 BOOLEAN IsUnattendedSetup = FALSE;
44
45 static USETUP_DATA USetupData;
46
47 // FIXME: Is it really useful?? Just used for SetDefaultPagefile...
48 static WCHAR DestinationDriveLetter;
49
50
51 /* OTHER Stuff *****/
52
53 PCWSTR SelectedLanguageId;
54 static WCHAR DefaultLanguage[20]; // Copy of string inside LanguageList
55 static WCHAR DefaultKBLayout[20]; // Copy of string inside KeyboardList
56
57 static BOOLEAN RepairUpdateFlag = FALSE;
58
59 static HANDLE hPnpThread = NULL;
60
61 static PPARTLIST PartitionList = NULL;
62 static PPARTENTRY TempPartition = NULL;
63 static PFILE_SYSTEM_LIST FileSystemList = NULL;
64 static FORMATMACHINESTATE FormatState = Start;
65
66 /*****************************************************/
67
68 static PNTOS_INSTALLATION CurrentInstallation = NULL;
69 static PGENERIC_LIST NtOsInstallsList = NULL;
70
71
72 /* FUNCTIONS ****************************************************************/
73
74 static VOID
75 PrintString(char* fmt,...)
76 {
77 char buffer[512];
78 va_list ap;
79 UNICODE_STRING UnicodeString;
80 ANSI_STRING AnsiString;
81
82 va_start(ap, fmt);
83 vsprintf(buffer, fmt, ap);
84 va_end(ap);
85
86 RtlInitAnsiString(&AnsiString, buffer);
87 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
88 NtDisplayString(&UnicodeString);
89 RtlFreeUnicodeString(&UnicodeString);
90 }
91
92
93 static VOID
94 DrawBox(IN SHORT xLeft,
95 IN SHORT yTop,
96 IN SHORT Width,
97 IN SHORT Height)
98 {
99 COORD coPos;
100 DWORD Written;
101
102 /* Draw upper left corner */
103 coPos.X = xLeft;
104 coPos.Y = yTop;
105 FillConsoleOutputCharacterA(StdOutput,
106 0xDA, // '+',
107 1,
108 coPos,
109 &Written);
110
111 /* Draw upper edge */
112 coPos.X = xLeft + 1;
113 coPos.Y = yTop;
114 FillConsoleOutputCharacterA(StdOutput,
115 0xC4, // '-',
116 Width - 2,
117 coPos,
118 &Written);
119
120 /* Draw upper right corner */
121 coPos.X = xLeft + Width - 1;
122 coPos.Y = yTop;
123 FillConsoleOutputCharacterA(StdOutput,
124 0xBF, // '+',
125 1,
126 coPos,
127 &Written);
128
129 /* Draw right edge, inner space and left edge */
130 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++)
131 {
132 coPos.X = xLeft;
133 FillConsoleOutputCharacterA(StdOutput,
134 0xB3, // '|',
135 1,
136 coPos,
137 &Written);
138
139 coPos.X = xLeft + 1;
140 FillConsoleOutputCharacterA(StdOutput,
141 ' ',
142 Width - 2,
143 coPos,
144 &Written);
145
146 coPos.X = xLeft + Width - 1;
147 FillConsoleOutputCharacterA(StdOutput,
148 0xB3, // '|',
149 1,
150 coPos,
151 &Written);
152 }
153
154 /* Draw lower left corner */
155 coPos.X = xLeft;
156 coPos.Y = yTop + Height - 1;
157 FillConsoleOutputCharacterA(StdOutput,
158 0xC0, // '+',
159 1,
160 coPos,
161 &Written);
162
163 /* Draw lower edge */
164 coPos.X = xLeft + 1;
165 coPos.Y = yTop + Height - 1;
166 FillConsoleOutputCharacterA(StdOutput,
167 0xC4, // '-',
168 Width - 2,
169 coPos,
170 &Written);
171
172 /* Draw lower right corner */
173 coPos.X = xLeft + Width - 1;
174 coPos.Y = yTop + Height - 1;
175 FillConsoleOutputCharacterA(StdOutput,
176 0xD9, // '+',
177 1,
178 coPos,
179 &Written);
180 }
181
182
183 VOID
184 PopupError(PCCH Text,
185 PCCH Status,
186 PINPUT_RECORD Ir,
187 ULONG WaitEvent)
188 {
189 SHORT yTop;
190 SHORT xLeft;
191 COORD coPos;
192 DWORD Written;
193 ULONG Length;
194 ULONG MaxLength;
195 ULONG Lines;
196 PCHAR p;
197 PCCH pnext;
198 BOOLEAN LastLine;
199 SHORT Width;
200 SHORT Height;
201
202 /* Count text lines and longest line */
203 MaxLength = 0;
204 Lines = 0;
205 pnext = Text;
206
207 while (TRUE)
208 {
209 p = strchr(pnext, '\n');
210
211 if (p == NULL)
212 {
213 Length = strlen(pnext);
214 LastLine = TRUE;
215 }
216 else
217 {
218 Length = (ULONG)(p - pnext);
219 LastLine = FALSE;
220 }
221
222 Lines++;
223
224 if (Length > MaxLength)
225 MaxLength = Length;
226
227 if (LastLine)
228 break;
229
230 pnext = p + 1;
231 }
232
233 /* Check length of status line */
234 if (Status != NULL)
235 {
236 Length = strlen(Status);
237
238 if (Length > MaxLength)
239 MaxLength = Length;
240 }
241
242 Width = MaxLength + 4;
243 Height = Lines + 2;
244
245 if (Status != NULL)
246 Height += 2;
247
248 yTop = (yScreen - Height) / 2;
249 xLeft = (xScreen - Width) / 2;
250
251
252 /* Set screen attributes */
253 coPos.X = xLeft;
254 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
255 {
256 FillConsoleOutputAttribute(StdOutput,
257 FOREGROUND_RED | BACKGROUND_WHITE,
258 Width,
259 coPos,
260 &Written);
261 }
262
263 DrawBox(xLeft, yTop, Width, Height);
264
265 /* Print message text */
266 coPos.Y = yTop + 1;
267 pnext = Text;
268 while (TRUE)
269 {
270 p = strchr(pnext, '\n');
271
272 if (p == NULL)
273 {
274 Length = strlen(pnext);
275 LastLine = TRUE;
276 }
277 else
278 {
279 Length = (ULONG)(p - pnext);
280 LastLine = FALSE;
281 }
282
283 if (Length != 0)
284 {
285 coPos.X = xLeft + 2;
286 WriteConsoleOutputCharacterA(StdOutput,
287 pnext,
288 Length,
289 coPos,
290 &Written);
291 }
292
293 if (LastLine)
294 break;
295
296 coPos.Y++;
297 pnext = p + 1;
298 }
299
300 /* Print separator line and status text */
301 if (Status != NULL)
302 {
303 coPos.Y = yTop + Height - 3;
304 coPos.X = xLeft;
305 FillConsoleOutputCharacterA(StdOutput,
306 0xC3, // '+',
307 1,
308 coPos,
309 &Written);
310
311 coPos.X = xLeft + 1;
312 FillConsoleOutputCharacterA(StdOutput,
313 0xC4, // '-',
314 Width - 2,
315 coPos,
316 &Written);
317
318 coPos.X = xLeft + Width - 1;
319 FillConsoleOutputCharacterA(StdOutput,
320 0xB4, // '+',
321 1,
322 coPos,
323 &Written);
324
325 coPos.Y++;
326 coPos.X = xLeft + 2;
327 WriteConsoleOutputCharacterA(StdOutput,
328 Status,
329 min(strlen(Status), (SIZE_T)Width - 4),
330 coPos,
331 &Written);
332 }
333
334 if (WaitEvent == POPUP_WAIT_NONE)
335 return;
336
337 while (TRUE)
338 {
339 CONSOLE_ConInKey(Ir);
340
341 if (WaitEvent == POPUP_WAIT_ANY_KEY ||
342 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D)
343 {
344 return;
345 }
346 }
347 }
348
349
350 /*
351 * Confirm quit setup
352 * RETURNS
353 * TRUE: Quit setup.
354 * FALSE: Don't quit setup.
355 */
356 static BOOL
357 ConfirmQuit(PINPUT_RECORD Ir)
358 {
359 BOOL Result = FALSE;
360 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE);
361
362 while (TRUE)
363 {
364 CONSOLE_ConInKey(Ir);
365
366 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
367 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
368 {
369 Result = TRUE;
370 break;
371 }
372 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
373 {
374 Result = FALSE;
375 break;
376 }
377 }
378
379 return Result;
380 }
381
382
383 static VOID
384 UpdateKBLayout(VOID)
385 {
386 PGENERIC_LIST_ENTRY ListEntry;
387 PCWSTR pszNewLayout;
388
389 pszNewLayout = MUIDefaultKeyboardLayout(SelectedLanguageId);
390
391 if (USetupData.LayoutList == NULL)
392 {
393 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout);
394 if (USetupData.LayoutList == NULL)
395 {
396 /* FIXME: Handle error! */
397 return;
398 }
399 }
400
401 /* Search for default layout (if provided) */
402 if (pszNewLayout != NULL)
403 {
404 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry;
405 ListEntry = GetNextListEntry(ListEntry))
406 {
407 if (!wcscmp(pszNewLayout, ((PGENENTRY)GetListEntryData(ListEntry))->Id))
408 {
409 SetCurrentListEntry(USetupData.LayoutList, ListEntry);
410 break;
411 }
412 }
413 }
414 }
415
416
417 static NTSTATUS
418 NTAPI
419 GetSettingDescription(
420 IN PGENERIC_LIST_ENTRY Entry,
421 OUT PSTR Buffer,
422 IN SIZE_T cchBufferSize)
423 {
424 return RtlStringCchPrintfA(Buffer, cchBufferSize, "%S",
425 ((PGENENTRY)GetListEntryData(Entry))->Value);
426 }
427
428 static NTSTATUS
429 NTAPI
430 GetNTOSInstallationName(
431 IN PGENERIC_LIST_ENTRY Entry,
432 OUT PSTR Buffer,
433 IN SIZE_T cchBufferSize)
434 {
435 PNTOS_INSTALLATION NtOsInstall = (PNTOS_INSTALLATION)GetListEntryData(Entry);
436 PPARTENTRY PartEntry = NtOsInstall->PartEntry;
437
438 if (PartEntry && PartEntry->DriveLetter)
439 {
440 /* We have retrieved a partition that is mounted */
441 return RtlStringCchPrintfA(Buffer, cchBufferSize,
442 "%C:%S \"%S\"",
443 PartEntry->DriveLetter,
444 NtOsInstall->PathComponent,
445 NtOsInstall->InstallationName);
446 }
447 else
448 {
449 /* We failed somewhere, just show the NT path */
450 return RtlStringCchPrintfA(Buffer, cchBufferSize,
451 "%wZ \"%S\"",
452 &NtOsInstall->SystemNtPath,
453 NtOsInstall->InstallationName);
454 }
455 }
456
457
458 /*
459 * Displays the LanguagePage.
460 *
461 * Next pages: WelcomePage, QuitPage
462 *
463 * SIDEEFFECTS
464 * Init SelectedLanguageId
465 * Init USetupData.LanguageId
466 *
467 * RETURNS
468 * Number of the next page.
469 */
470 static PAGE_NUMBER
471 LanguagePage(PINPUT_RECORD Ir)
472 {
473 GENERIC_LIST_UI ListUi;
474 PCWSTR NewLanguageId;
475 BOOL RefreshPage = FALSE;
476
477 /* Initialize the computer settings list */
478 if (USetupData.LanguageList == NULL)
479 {
480 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage);
481 if (USetupData.LanguageList == NULL)
482 {
483 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE);
484 return WELCOME_PAGE;
485 }
486 }
487
488 SelectedLanguageId = DefaultLanguage;
489 USetupData.LanguageId = 0;
490
491 /* Load the font */
492 SetConsoleCodePage();
493 UpdateKBLayout();
494
495 /*
496 * If there is no language or just a single one in the list,
497 * skip the language selection process altogether.
498 */
499 if (GetNumberOfListEntries(USetupData.LanguageList) <= 1)
500 {
501 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
502 return WELCOME_PAGE;
503 }
504
505 InitGenericListUi(&ListUi, USetupData.LanguageList, GetSettingDescription);
506 DrawGenericList(&ListUi,
507 2, 18,
508 xScreen - 3,
509 yScreen - 3);
510
511 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex());
512
513 MUIDisplayPage(LANGUAGE_PAGE);
514
515 while (TRUE)
516 {
517 CONSOLE_ConInKey(Ir);
518
519 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
520 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
521 {
522 ScrollDownGenericList(&ListUi);
523 RefreshPage = TRUE;
524 }
525 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
526 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
527 {
528 ScrollUpGenericList(&ListUi);
529 RefreshPage = TRUE;
530 }
531 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
532 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */
533 {
534 ScrollPageDownGenericList(&ListUi);
535 RefreshPage = TRUE;
536 }
537 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
538 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */
539 {
540 ScrollPageUpGenericList(&ListUi);
541 RefreshPage = TRUE;
542 }
543 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
544 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
545 {
546 if (ConfirmQuit(Ir))
547 return QUIT_PAGE;
548 else
549 RedrawGenericList(&ListUi);
550 }
551 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
552 {
553 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
554
555 SelectedLanguageId =
556 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
557
558 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF);
559
560 if (wcscmp(SelectedLanguageId, DefaultLanguage))
561 {
562 UpdateKBLayout();
563 }
564
565 /* Load the font */
566 SetConsoleCodePage();
567
568 return WELCOME_PAGE;
569 }
570 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b))
571 {
572 /* a-z */
573 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar);
574 RefreshPage = TRUE;
575 }
576
577 if (RefreshPage)
578 {
579 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1);
580
581 NewLanguageId =
582 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id;
583
584 if (wcscmp(SelectedLanguageId, NewLanguageId))
585 {
586 /* Clear the language page */
587 MUIClearPage(LANGUAGE_PAGE);
588
589 SelectedLanguageId = NewLanguageId;
590
591 /* Load the font */
592 SetConsoleCodePage();
593
594 /* Redraw language selection page in native language */
595 MUIDisplayPage(LANGUAGE_PAGE);
596 }
597
598 RefreshPage = FALSE;
599 }
600 }
601
602 return WELCOME_PAGE;
603 }
604
605
606 /*
607 * Start page
608 *
609 * Next pages:
610 * LanguagePage (at once, default)
611 * InstallIntroPage (at once, if unattended)
612 * QuitPage
613 *
614 * SIDEEFFECTS
615 * Init Sdi
616 * Init USetupData.SourcePath
617 * Init USetupData.SourceRootPath
618 * Init USetupData.SourceRootDir
619 * Init USetupData.SetupInf
620 * Init USetupData.RequiredPartitionDiskSpace
621 * Init IsUnattendedSetup
622 * If unattended, init *List and sets the Codepage
623 * If unattended, init SelectedLanguageId
624 * If unattended, init USetupData.LanguageId
625 *
626 * RETURNS
627 * Number of the next page.
628 */
629 static PAGE_NUMBER
630 SetupStartPage(PINPUT_RECORD Ir)
631 {
632 ULONG Error;
633 PGENERIC_LIST_ENTRY ListEntry;
634 PCWSTR LocaleId;
635
636 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
637
638 /* Initialize Setup, phase 1 */
639 Error = InitializeSetup(&USetupData, 1);
640 if (Error != ERROR_SUCCESS)
641 {
642 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
643 return QUIT_PAGE;
644 }
645
646 /* Start the PnP thread */
647 if (hPnpThread != NULL)
648 {
649 NtResumeThread(hPnpThread, NULL);
650 hPnpThread = NULL;
651 }
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->NoMbr ? "GPT" : "MBR");
1987 }
1988 else
1989 {
1990 CONSOLE_PrintTextXY(6, 10,
1991 MUIGetString(STRING_HDINFOPARTCREATE_2),
1992 DiskSize,
1993 Unit,
1994 DiskEntry->DiskNumber,
1995 DiskEntry->Port,
1996 DiskEntry->Bus,
1997 DiskEntry->Id,
1998 DiskEntry->NoMbr ? "GPT" : "MBR");
1999 }
2000
2001 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2002
2003 #if 0
2004 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2005 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2006 #endif
2007
2008 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2009
2010 PartEntry = PartitionList->CurrentPartition;
2011 while (TRUE)
2012 {
2013 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2014
2015 if (MaxSize > PARTITION_MAXSIZE)
2016 MaxSize = PARTITION_MAXSIZE;
2017
2018 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2019 MaxSize, InputBuffer, &Quit, &Cancel);
2020
2021 if (Quit)
2022 {
2023 if (ConfirmQuit(Ir))
2024 return QUIT_PAGE;
2025
2026 break;
2027 }
2028 else if (Cancel)
2029 {
2030 return SELECT_PARTITION_PAGE;
2031 }
2032 else
2033 {
2034 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2035
2036 if (PartSize < 1)
2037 {
2038 /* Too small */
2039 continue;
2040 }
2041
2042 if (PartSize > MaxSize)
2043 {
2044 /* Too large */
2045 continue;
2046 }
2047
2048 /* Convert to bytes */
2049 if (PartSize == MaxSize)
2050 {
2051 /* Use all of the unpartitioned disk space */
2052 SectorCount = PartEntry->SectorCount.QuadPart;
2053 }
2054 else
2055 {
2056 /* Calculate the sector count from the size in MB */
2057 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2058
2059 /* But never get larger than the unpartitioned disk space */
2060 if (SectorCount > PartEntry->SectorCount.QuadPart)
2061 SectorCount = PartEntry->SectorCount.QuadPart;
2062 }
2063
2064 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2065
2066 CreatePrimaryPartition(PartitionList,
2067 SectorCount,
2068 FALSE);
2069
2070 return SELECT_PARTITION_PAGE;
2071 }
2072 }
2073
2074 return CREATE_PRIMARY_PARTITION_PAGE;
2075 }
2076
2077
2078 /*
2079 * Displays the CreateExtendedPartitionPage.
2080 *
2081 * Next pages:
2082 * SelectPartitionPage (default)
2083 * QuitPage
2084 *
2085 * RETURNS
2086 * Number of the next page.
2087 */
2088 static PAGE_NUMBER
2089 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2090 {
2091 PDISKENTRY DiskEntry;
2092 PPARTENTRY PartEntry;
2093 BOOLEAN Quit;
2094 BOOLEAN Cancel;
2095 WCHAR InputBuffer[50];
2096 ULONG MaxSize;
2097 ULONGLONG PartSize;
2098 ULONGLONG DiskSize;
2099 ULONGLONG SectorCount;
2100 PCHAR Unit;
2101
2102 if (PartitionList == NULL ||
2103 PartitionList->CurrentDisk == NULL ||
2104 PartitionList->CurrentPartition == NULL)
2105 {
2106 /* FIXME: show an error dialog */
2107 return QUIT_PAGE;
2108 }
2109
2110 DiskEntry = PartitionList->CurrentDisk;
2111 PartEntry = PartitionList->CurrentPartition;
2112
2113 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2114
2115 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2116
2117 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2118 #if 0
2119 if (DiskSize >= 10 * GB) /* 10 GB */
2120 {
2121 DiskSize = DiskSize / GB;
2122 Unit = MUIGetString(STRING_GB);
2123 }
2124 else
2125 #endif
2126 {
2127 DiskSize = DiskSize / MB;
2128 if (DiskSize == 0)
2129 DiskSize = 1;
2130
2131 Unit = MUIGetString(STRING_MB);
2132 }
2133
2134 if (DiskEntry->DriverName.Length > 0)
2135 {
2136 CONSOLE_PrintTextXY(6, 10,
2137 MUIGetString(STRING_HDINFOPARTCREATE_1),
2138 DiskSize,
2139 Unit,
2140 DiskEntry->DiskNumber,
2141 DiskEntry->Port,
2142 DiskEntry->Bus,
2143 DiskEntry->Id,
2144 &DiskEntry->DriverName,
2145 DiskEntry->NoMbr ? "GPT" : "MBR");
2146 }
2147 else
2148 {
2149 CONSOLE_PrintTextXY(6, 10,
2150 MUIGetString(STRING_HDINFOPARTCREATE_2),
2151 DiskSize,
2152 Unit,
2153 DiskEntry->DiskNumber,
2154 DiskEntry->Port,
2155 DiskEntry->Bus,
2156 DiskEntry->Id,
2157 DiskEntry->NoMbr ? "GPT" : "MBR");
2158 }
2159
2160 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2161
2162 #if 0
2163 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2164 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2165 #endif
2166
2167 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2168
2169 PartEntry = PartitionList->CurrentPartition;
2170 while (TRUE)
2171 {
2172 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2173
2174 if (MaxSize > PARTITION_MAXSIZE)
2175 MaxSize = PARTITION_MAXSIZE;
2176
2177 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2178 MaxSize, InputBuffer, &Quit, &Cancel);
2179
2180 if (Quit)
2181 {
2182 if (ConfirmQuit(Ir))
2183 return QUIT_PAGE;
2184
2185 break;
2186 }
2187 else if (Cancel)
2188 {
2189 return SELECT_PARTITION_PAGE;
2190 }
2191 else
2192 {
2193 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2194
2195 if (PartSize < 1)
2196 {
2197 /* Too small */
2198 continue;
2199 }
2200
2201 if (PartSize > MaxSize)
2202 {
2203 /* Too large */
2204 continue;
2205 }
2206
2207 /* Convert to bytes */
2208 if (PartSize == MaxSize)
2209 {
2210 /* Use all of the unpartitioned disk space */
2211 SectorCount = PartEntry->SectorCount.QuadPart;
2212 }
2213 else
2214 {
2215 /* Calculate the sector count from the size in MB */
2216 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2217
2218 /* But never get larger than the unpartitioned disk space */
2219 if (SectorCount > PartEntry->SectorCount.QuadPart)
2220 SectorCount = PartEntry->SectorCount.QuadPart;
2221 }
2222
2223 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2224
2225 CreateExtendedPartition(PartitionList,
2226 SectorCount);
2227
2228 return SELECT_PARTITION_PAGE;
2229 }
2230 }
2231
2232 return CREATE_EXTENDED_PARTITION_PAGE;
2233 }
2234
2235
2236 /*
2237 * Displays the CreateLogicalPartitionPage.
2238 *
2239 * Next pages:
2240 * SelectFileSystemPage (default)
2241 * QuitPage
2242 *
2243 * RETURNS
2244 * Number of the next page.
2245 */
2246 static PAGE_NUMBER
2247 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2248 {
2249 PDISKENTRY DiskEntry;
2250 PPARTENTRY PartEntry;
2251 BOOLEAN Quit;
2252 BOOLEAN Cancel;
2253 WCHAR InputBuffer[50];
2254 ULONG MaxSize;
2255 ULONGLONG PartSize;
2256 ULONGLONG DiskSize;
2257 ULONGLONG SectorCount;
2258 PCHAR Unit;
2259
2260 if (PartitionList == NULL ||
2261 PartitionList->CurrentDisk == NULL ||
2262 PartitionList->CurrentPartition == NULL)
2263 {
2264 /* FIXME: show an error dialog */
2265 return QUIT_PAGE;
2266 }
2267
2268 DiskEntry = PartitionList->CurrentDisk;
2269 PartEntry = PartitionList->CurrentPartition;
2270
2271 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2272
2273 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2274
2275 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2276 #if 0
2277 if (DiskSize >= 10 * GB) /* 10 GB */
2278 {
2279 DiskSize = DiskSize / GB;
2280 Unit = MUIGetString(STRING_GB);
2281 }
2282 else
2283 #endif
2284 {
2285 DiskSize = DiskSize / MB;
2286 if (DiskSize == 0)
2287 DiskSize = 1;
2288
2289 Unit = MUIGetString(STRING_MB);
2290 }
2291
2292 if (DiskEntry->DriverName.Length > 0)
2293 {
2294 CONSOLE_PrintTextXY(6, 10,
2295 MUIGetString(STRING_HDINFOPARTCREATE_1),
2296 DiskSize,
2297 Unit,
2298 DiskEntry->DiskNumber,
2299 DiskEntry->Port,
2300 DiskEntry->Bus,
2301 DiskEntry->Id,
2302 &DiskEntry->DriverName,
2303 DiskEntry->NoMbr ? "GPT" : "MBR");
2304 }
2305 else
2306 {
2307 CONSOLE_PrintTextXY(6, 10,
2308 MUIGetString(STRING_HDINFOPARTCREATE_2),
2309 DiskSize,
2310 Unit,
2311 DiskEntry->DiskNumber,
2312 DiskEntry->Port,
2313 DiskEntry->Bus,
2314 DiskEntry->Id,
2315 DiskEntry->NoMbr ? "GPT" : "MBR");
2316 }
2317
2318 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2319
2320 #if 0
2321 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2322 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2323 #endif
2324
2325 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2326
2327 PartEntry = PartitionList->CurrentPartition;
2328 while (TRUE)
2329 {
2330 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2331
2332 if (MaxSize > PARTITION_MAXSIZE)
2333 MaxSize = PARTITION_MAXSIZE;
2334
2335 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2336 MaxSize, InputBuffer, &Quit, &Cancel);
2337
2338 if (Quit)
2339 {
2340 if (ConfirmQuit(Ir))
2341 return QUIT_PAGE;
2342
2343 break;
2344 }
2345 else if (Cancel)
2346 {
2347 return SELECT_PARTITION_PAGE;
2348 }
2349 else
2350 {
2351 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2352
2353 if (PartSize < 1)
2354 {
2355 /* Too small */
2356 continue;
2357 }
2358
2359 if (PartSize > MaxSize)
2360 {
2361 /* Too large */
2362 continue;
2363 }
2364
2365 /* Convert to bytes */
2366 if (PartSize == MaxSize)
2367 {
2368 /* Use all of the unpartitioned disk space */
2369 SectorCount = PartEntry->SectorCount.QuadPart;
2370 }
2371 else
2372 {
2373 /* Calculate the sector count from the size in MB */
2374 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2375
2376 /* But never get larger than the unpartitioned disk space */
2377 if (SectorCount > PartEntry->SectorCount.QuadPart)
2378 SectorCount = PartEntry->SectorCount.QuadPart;
2379 }
2380
2381 DPRINT("Partition size: %I64u bytes\n", PartSize);
2382
2383 CreateLogicalPartition(PartitionList,
2384 SectorCount,
2385 FALSE);
2386
2387 return SELECT_PARTITION_PAGE;
2388 }
2389 }
2390
2391 return CREATE_LOGICAL_PARTITION_PAGE;
2392 }
2393
2394
2395 /*
2396 * Displays the ConfirmDeleteSystemPartitionPage.
2397 *
2398 * Next pages:
2399 * DeletePartitionPage (default)
2400 * SelectPartitionPage
2401 *
2402 * RETURNS
2403 * Number of the next page.
2404 */
2405 static PAGE_NUMBER
2406 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2407 {
2408 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2409
2410 while (TRUE)
2411 {
2412 CONSOLE_ConInKey(Ir);
2413
2414 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2415 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2416 {
2417 if (ConfirmQuit(Ir))
2418 return QUIT_PAGE;
2419
2420 break;
2421 }
2422 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2423 {
2424 return DELETE_PARTITION_PAGE;
2425 }
2426 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2427 {
2428 return SELECT_PARTITION_PAGE;
2429 }
2430 }
2431
2432 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2433 }
2434
2435
2436 /*
2437 * Displays the DeletePartitionPage.
2438 *
2439 * Next pages:
2440 * SelectPartitionPage (default)
2441 * QuitPage
2442 *
2443 * RETURNS
2444 * Number of the next page.
2445 */
2446 static PAGE_NUMBER
2447 DeletePartitionPage(PINPUT_RECORD Ir)
2448 {
2449 PDISKENTRY DiskEntry;
2450 PPARTENTRY PartEntry;
2451 ULONGLONG DiskSize;
2452 ULONGLONG PartSize;
2453 PCHAR Unit;
2454 CHAR PartTypeString[32];
2455
2456 if (PartitionList == NULL ||
2457 PartitionList->CurrentDisk == NULL ||
2458 PartitionList->CurrentPartition == NULL)
2459 {
2460 /* FIXME: show an error dialog */
2461 return QUIT_PAGE;
2462 }
2463
2464 DiskEntry = PartitionList->CurrentDisk;
2465 PartEntry = PartitionList->CurrentPartition;
2466
2467 MUIDisplayPage(DELETE_PARTITION_PAGE);
2468
2469 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2470 PartTypeString,
2471 ARRAYSIZE(PartTypeString));
2472
2473 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2474 #if 0
2475 if (PartSize >= 10 * GB) /* 10 GB */
2476 {
2477 PartSize = PartSize / GB;
2478 Unit = MUIGetString(STRING_GB);
2479 }
2480 else
2481 #endif
2482 if (PartSize >= 10 * MB) /* 10 MB */
2483 {
2484 PartSize = PartSize / MB;
2485 Unit = MUIGetString(STRING_MB);
2486 }
2487 else
2488 {
2489 PartSize = PartSize / KB;
2490 Unit = MUIGetString(STRING_KB);
2491 }
2492
2493 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2494 {
2495 CONSOLE_PrintTextXY(6, 10,
2496 MUIGetString(STRING_HDDINFOUNK2),
2497 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2498 (PartEntry->DriveLetter == 0) ? '-' : ':',
2499 PartEntry->PartitionType,
2500 PartSize,
2501 Unit);
2502 }
2503 else
2504 {
2505 CONSOLE_PrintTextXY(6, 10,
2506 " %c%c %s %I64u %s",
2507 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2508 (PartEntry->DriveLetter == 0) ? '-' : ':',
2509 PartTypeString,
2510 PartSize,
2511 Unit);
2512 }
2513
2514 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2515 #if 0
2516 if (DiskSize >= 10 * GB) /* 10 GB */
2517 {
2518 DiskSize = DiskSize / GB;
2519 Unit = MUIGetString(STRING_GB);
2520 }
2521 else
2522 #endif
2523 {
2524 DiskSize = DiskSize / MB;
2525 if (DiskSize == 0)
2526 DiskSize = 1;
2527
2528 Unit = MUIGetString(STRING_MB);
2529 }
2530
2531 if (DiskEntry->DriverName.Length > 0)
2532 {
2533 CONSOLE_PrintTextXY(6, 12,
2534 MUIGetString(STRING_HDINFOPARTDELETE_1),
2535 DiskSize,
2536 Unit,
2537 DiskEntry->DiskNumber,
2538 DiskEntry->Port,
2539 DiskEntry->Bus,
2540 DiskEntry->Id,
2541 &DiskEntry->DriverName,
2542 DiskEntry->NoMbr ? "GPT" : "MBR");
2543 }
2544 else
2545 {
2546 CONSOLE_PrintTextXY(6, 12,
2547 MUIGetString(STRING_HDINFOPARTDELETE_2),
2548 DiskSize,
2549 Unit,
2550 DiskEntry->DiskNumber,
2551 DiskEntry->Port,
2552 DiskEntry->Bus,
2553 DiskEntry->Id,
2554 DiskEntry->NoMbr ? "GPT" : "MBR");
2555 }
2556
2557 while (TRUE)
2558 {
2559 CONSOLE_ConInKey(Ir);
2560
2561 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2562 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2563 {
2564 if (ConfirmQuit(Ir))
2565 return QUIT_PAGE;
2566
2567 break;
2568 }
2569 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2570 {
2571 return SELECT_PARTITION_PAGE;
2572 }
2573 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2574 {
2575 DeleteCurrentPartition(PartitionList);
2576
2577 return SELECT_PARTITION_PAGE;
2578 }
2579 }
2580
2581 return DELETE_PARTITION_PAGE;
2582 }
2583
2584
2585 /*
2586 * Displays the SelectFileSystemPage.
2587 *
2588 * Next pages:
2589 * CheckFileSystemPage (At once if RepairUpdate is selected)
2590 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2591 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2592 * SelectPartitionPage (If the user aborts)
2593 * FormatPartitionPage (Default)
2594 * QuitPage
2595 *
2596 * SIDEEFFECTS
2597 * Calls UpdatePartitionType()
2598 * Calls CheckActiveSystemPartition()
2599 *
2600 * RETURNS
2601 * Number of the next page.
2602 */
2603 static PAGE_NUMBER
2604 SelectFileSystemPage(PINPUT_RECORD Ir)
2605 {
2606 PDISKENTRY DiskEntry;
2607 PPARTENTRY PartEntry;
2608 ULONGLONG DiskSize;
2609 ULONGLONG PartSize;
2610 PCHAR DiskUnit;
2611 PCHAR PartUnit;
2612 CHAR PartTypeString[32];
2613 FORMATMACHINESTATE PreviousFormatState;
2614
2615 DPRINT("SelectFileSystemPage()\n");
2616
2617 if (PartitionList == NULL ||
2618 PartitionList->CurrentDisk == NULL ||
2619 PartitionList->CurrentPartition == NULL)
2620 {
2621 /* FIXME: show an error dialog */
2622 return QUIT_PAGE;
2623 }
2624
2625 /* Find or set the active system partition */
2626 CheckActiveSystemPartition(PartitionList);
2627 if (PartitionList->SystemPartition == NULL)
2628 {
2629 /* FIXME: show an error dialog */
2630 //
2631 // Error dialog should say that we cannot find a suitable
2632 // system partition and create one on the system. At this point,
2633 // it may be nice to ask the user whether he wants to continue,
2634 // or use an external drive as the system drive/partition
2635 // (e.g. floppy, USB drive, etc...)
2636 //
2637 return QUIT_PAGE;
2638 }
2639
2640 PreviousFormatState = FormatState;
2641 switch (FormatState)
2642 {
2643 case Start:
2644 {
2645 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2646 {
2647 TempPartition = PartitionList->SystemPartition;
2648 TempPartition->NeedsCheck = TRUE;
2649
2650 FormatState = FormatSystemPartition;
2651 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2652 }
2653 else
2654 {
2655 TempPartition = PartitionList->CurrentPartition;
2656 TempPartition->NeedsCheck = TRUE;
2657
2658 FormatState = FormatInstallPartition;
2659 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2660 }
2661 break;
2662 }
2663
2664 case FormatSystemPartition:
2665 {
2666 TempPartition = PartitionList->CurrentPartition;
2667 TempPartition->NeedsCheck = TRUE;
2668
2669 FormatState = FormatInstallPartition;
2670 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2671 break;
2672 }
2673
2674 case FormatInstallPartition:
2675 {
2676 if (GetNextUnformattedPartition(PartitionList,
2677 NULL,
2678 &TempPartition))
2679 {
2680 FormatState = FormatOtherPartition;
2681 TempPartition->NeedsCheck = TRUE;
2682 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2683 }
2684 else
2685 {
2686 FormatState = FormatDone;
2687 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2688 return CHECK_FILE_SYSTEM_PAGE;
2689 }
2690 break;
2691 }
2692
2693 case FormatOtherPartition:
2694 {
2695 if (GetNextUnformattedPartition(PartitionList,
2696 NULL,
2697 &TempPartition))
2698 {
2699 FormatState = FormatOtherPartition;
2700 TempPartition->NeedsCheck = TRUE;
2701 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2702 }
2703 else
2704 {
2705 FormatState = FormatDone;
2706 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2707 return CHECK_FILE_SYSTEM_PAGE;
2708 }
2709 break;
2710 }
2711
2712 default:
2713 {
2714 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2715 /* FIXME: show an error dialog */
2716 return QUIT_PAGE;
2717 }
2718 }
2719
2720 PartEntry = TempPartition;
2721 DiskEntry = PartEntry->DiskEntry;
2722
2723 /* Adjust disk size */
2724 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2725 if (DiskSize >= 10 * GB) /* 10 GB */
2726 {
2727 DiskSize = DiskSize / GB;
2728 DiskUnit = MUIGetString(STRING_GB);
2729 }
2730 else
2731 {
2732 DiskSize = DiskSize / MB;
2733 DiskUnit = MUIGetString(STRING_MB);
2734 }
2735
2736 /* Adjust partition size */
2737 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2738 if (PartSize >= 10 * GB) /* 10 GB */
2739 {
2740 PartSize = PartSize / GB;
2741 PartUnit = MUIGetString(STRING_GB);
2742 }
2743 else
2744 {
2745 PartSize = PartSize / MB;
2746 PartUnit = MUIGetString(STRING_MB);
2747 }
2748
2749 /* Adjust partition type */
2750 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2751 PartTypeString,
2752 ARRAYSIZE(PartTypeString));
2753
2754 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2755
2756 if (PartEntry->AutoCreate)
2757 {
2758 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2759
2760 #if 0
2761 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2762 PartEntry->PartitionNumber,
2763 PartSize,
2764 PartUnit,
2765 PartTypeString);
2766 #endif
2767
2768 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
2769 DiskEntry->DiskNumber,
2770 DiskSize,
2771 DiskUnit,
2772 DiskEntry->Port,
2773 DiskEntry->Bus,
2774 DiskEntry->Id,
2775 &DiskEntry->DriverName,
2776 DiskEntry->NoMbr ? "GPT" : "MBR");
2777
2778 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2779
2780 PartEntry->AutoCreate = FALSE;
2781 }
2782 else if (PartEntry->New)
2783 {
2784 switch (FormatState)
2785 {
2786 case FormatSystemPartition:
2787 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2788 break;
2789
2790 case FormatInstallPartition:
2791 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2792 break;
2793
2794 case FormatOtherPartition:
2795 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2796 break;
2797
2798 default:
2799 break;
2800 }
2801
2802 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2803 }
2804 else
2805 {
2806 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2807
2808 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2809 {
2810 CONSOLE_PrintTextXY(8, 10,
2811 MUIGetString(STRING_HDDINFOUNK4),
2812 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2813 (PartEntry->DriveLetter == 0) ? '-' : ':',
2814 PartEntry->PartitionType,
2815 PartSize,
2816 PartUnit);
2817 }
2818 else
2819 {
2820 CONSOLE_PrintTextXY(8, 10,
2821 "%c%c %s %I64u %s",
2822 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2823 (PartEntry->DriveLetter == 0) ? '-' : ':',
2824 PartTypeString,
2825 PartSize,
2826 PartUnit);
2827 }
2828
2829 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
2830 DiskEntry->DiskNumber,
2831 DiskSize,
2832 DiskUnit,
2833 DiskEntry->Port,
2834 DiskEntry->Bus,
2835 DiskEntry->Id,
2836 &DiskEntry->DriverName,
2837 DiskEntry->NoMbr ? "GPT" : "MBR");
2838 }
2839
2840 if (FileSystemList == NULL)
2841 {
2842 /* Create the file system list, and by default select the "FAT" file system */
2843 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2844 if (FileSystemList == NULL)
2845 {
2846 /* FIXME: show an error dialog */
2847 return QUIT_PAGE;
2848 }
2849 }
2850
2851 if (RepairUpdateFlag)
2852 {
2853 return CHECK_FILE_SYSTEM_PAGE;
2854 //return SELECT_PARTITION_PAGE;
2855 }
2856
2857 if (IsUnattendedSetup)
2858 {
2859 if (USetupData.FormatPartition)
2860 {
2861 /*
2862 * We use whatever currently selected file system we have
2863 * (by default, this is "FAT", as per the initialization
2864 * performed above). Note that it may be interesting to specify
2865 * which file system to use in unattended installations, in the
2866 * txtsetup.sif file.
2867 */
2868 return FORMAT_PARTITION_PAGE;
2869 }
2870
2871 return CHECK_FILE_SYSTEM_PAGE;
2872 }
2873
2874 DrawFileSystemList(FileSystemList);
2875
2876 while (TRUE)
2877 {
2878 CONSOLE_ConInKey(Ir);
2879
2880 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2881 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2882 {
2883 if (ConfirmQuit(Ir))
2884 return QUIT_PAGE;
2885
2886 break;
2887 }
2888 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2889 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2890 {
2891 FormatState = Start;
2892 return SELECT_PARTITION_PAGE;
2893 }
2894 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2895 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2896 {
2897 ScrollDownFileSystemList(FileSystemList);
2898 }
2899 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2900 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2901 {
2902 ScrollUpFileSystemList(FileSystemList);
2903 }
2904 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2905 {
2906 if (!FileSystemList->Selected->FileSystem)
2907 return SELECT_FILE_SYSTEM_PAGE;
2908 else
2909 return FORMAT_PARTITION_PAGE;
2910 }
2911 }
2912
2913 FormatState = PreviousFormatState;
2914
2915 return SELECT_FILE_SYSTEM_PAGE;
2916 }
2917
2918
2919 /*
2920 * Displays the FormatPartitionPage.
2921 *
2922 * Next pages:
2923 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2924 * SelectPartitionPage (At once)
2925 * QuitPage
2926 *
2927 * SIDEEFFECTS
2928 * Sets PartitionList->CurrentPartition->FormatState
2929 * Sets USetupData.DestinationRootPath
2930 *
2931 * RETURNS
2932 * Number of the next page.
2933 */
2934 static PAGE_NUMBER
2935 FormatPartitionPage(PINPUT_RECORD Ir)
2936 {
2937 NTSTATUS Status;
2938 PDISKENTRY DiskEntry;
2939 PPARTENTRY PartEntry;
2940 PFILE_SYSTEM_ITEM SelectedFileSystem;
2941 UNICODE_STRING PartitionRootPath;
2942 WCHAR PathBuffer[MAX_PATH];
2943 CHAR Buffer[MAX_PATH];
2944
2945 #ifndef NDEBUG
2946 ULONG Line;
2947 ULONG i;
2948 PPARTITION_INFORMATION PartitionInfo;
2949 #endif
2950
2951 DPRINT("FormatPartitionPage()\n");
2952
2953 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2954
2955 if (PartitionList == NULL || TempPartition == NULL)
2956 {
2957 /* FIXME: show an error dialog */
2958 return QUIT_PAGE;
2959 }
2960
2961 PartEntry = TempPartition;
2962 DiskEntry = PartEntry->DiskEntry;
2963
2964 SelectedFileSystem = FileSystemList->Selected;
2965
2966 while (TRUE)
2967 {
2968 if (!IsUnattendedSetup)
2969 {
2970 CONSOLE_ConInKey(Ir);
2971 }
2972
2973 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2974 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2975 {
2976 if (ConfirmQuit(Ir))
2977 return QUIT_PAGE;
2978
2979 break;
2980 }
2981 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
2982 {
2983 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2984
2985 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
2986 {
2987 /* FIXME: show an error dialog */
2988 return QUIT_PAGE;
2989 }
2990
2991 #ifndef NDEBUG
2992 CONSOLE_PrintTextXY(6, 12,
2993 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
2994 DiskEntry->Cylinders,
2995 DiskEntry->TracksPerCylinder,
2996 DiskEntry->SectorsPerTrack,
2997 DiskEntry->BytesPerSector,
2998 DiskEntry->Dirty ? '*' : ' ');
2999
3000 Line = 13;
3001
3002 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
3003 {
3004 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
3005
3006 CONSOLE_PrintTextXY(6, Line,
3007 "%2u: %2lu %c %12I64u %12I64u %02x",
3008 i,
3009 PartitionInfo->PartitionNumber,
3010 PartitionInfo->BootIndicator ? 'A' : '-',
3011 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
3012 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
3013 PartitionInfo->PartitionType);
3014 Line++;
3015 }
3016 #endif
3017
3018 /* Commit the partition changes to the disk */
3019 if (!WritePartitionsToDisk(PartitionList))
3020 {
3021 DPRINT("WritePartitionsToDisk() failed\n");
3022 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3023 return QUIT_PAGE;
3024 }
3025
3026 /* Set PartitionRootPath */
3027 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3028 L"\\Device\\Harddisk%lu\\Partition%lu",
3029 DiskEntry->DiskNumber,
3030 PartEntry->PartitionNumber);
3031 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3032 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3033
3034 /* Format the partition */
3035 if (SelectedFileSystem->FileSystem)
3036 {
3037 Status = FormatPartition(&PartitionRootPath,
3038 SelectedFileSystem);
3039 if (Status == STATUS_NOT_SUPPORTED)
3040 {
3041 sprintf(Buffer,
3042 "Setup is currently unable to format a partition in %S.\n"
3043 "\n"
3044 " \x07 Press ENTER to continue Setup.\n"
3045 " \x07 Press F3 to quit Setup.",
3046 SelectedFileSystem->FileSystem->FileSystemName);
3047
3048 PopupError(Buffer,
3049 MUIGetString(STRING_QUITCONTINUE),
3050 NULL, POPUP_WAIT_NONE);
3051
3052 while (TRUE)
3053 {
3054 CONSOLE_ConInKey(Ir);
3055
3056 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3057 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3058 {
3059 if (ConfirmQuit(Ir))
3060 return QUIT_PAGE;
3061 else
3062 return SELECT_FILE_SYSTEM_PAGE;
3063 }
3064 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3065 {
3066 return SELECT_FILE_SYSTEM_PAGE;
3067 }
3068 }
3069 }
3070 else if (!NT_SUCCESS(Status))
3071 {
3072 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3073 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3074 return QUIT_PAGE;
3075 }
3076
3077 PartEntry->FormatState = Formatted;
3078 // PartEntry->FileSystem = FileSystem;
3079 PartEntry->New = FALSE;
3080 }
3081
3082 #ifndef NDEBUG
3083 CONSOLE_SetStatusText(" Done. Press any key ...");
3084 CONSOLE_ConInKey(Ir);
3085 #endif
3086
3087 return SELECT_FILE_SYSTEM_PAGE;
3088 }
3089 }
3090
3091 return FORMAT_PARTITION_PAGE;
3092 }
3093
3094
3095 /*
3096 * Displays the CheckFileSystemPage.
3097 *
3098 * Next pages:
3099 * InstallDirectoryPage (At once)
3100 * QuitPage
3101 *
3102 * SIDEEFFECTS
3103 * Inits or reloads FileSystemList
3104 *
3105 * RETURNS
3106 * Number of the next page.
3107 */
3108 static PAGE_NUMBER
3109 CheckFileSystemPage(PINPUT_RECORD Ir)
3110 {
3111 NTSTATUS Status;
3112 PDISKENTRY DiskEntry;
3113 PPARTENTRY PartEntry;
3114 PFILE_SYSTEM CurrentFileSystem;
3115 UNICODE_STRING PartitionRootPath;
3116 WCHAR PathBuffer[MAX_PATH];
3117 CHAR Buffer[MAX_PATH];
3118
3119 if (PartitionList == NULL)
3120 {
3121 /* FIXME: show an error dialog */
3122 return QUIT_PAGE;
3123 }
3124
3125 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3126 {
3127 return INSTALL_DIRECTORY_PAGE;
3128 }
3129
3130 /* Set PartitionRootPath */
3131 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3132 L"\\Device\\Harddisk%lu\\Partition%lu",
3133 DiskEntry->DiskNumber,
3134 PartEntry->PartitionNumber);
3135 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3136 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3137
3138 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3139
3140 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3141
3142 CurrentFileSystem = PartEntry->FileSystem;
3143 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3144 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3145
3146 /* HACK: Do not try to check a partition with an unknown filesystem */
3147 if (CurrentFileSystem == NULL)
3148 {
3149 PartEntry->NeedsCheck = FALSE;
3150 return CHECK_FILE_SYSTEM_PAGE;
3151 }
3152
3153 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3154 if (Status == STATUS_NOT_SUPPORTED)
3155 {
3156 sprintf(Buffer,
3157 "Setup is currently unable to check a partition formatted in %S.\n"
3158 "\n"
3159 " \x07 Press ENTER to continue Setup.\n"
3160 " \x07 Press F3 to quit Setup.",
3161 CurrentFileSystem->FileSystemName);
3162
3163 PopupError(Buffer,
3164 MUIGetString(STRING_QUITCONTINUE),
3165 NULL, POPUP_WAIT_NONE);
3166
3167 while (TRUE)
3168 {
3169 CONSOLE_ConInKey(Ir);
3170
3171 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3172 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3173 {
3174 if (ConfirmQuit(Ir))
3175 return QUIT_PAGE;
3176 else
3177 return CHECK_FILE_SYSTEM_PAGE;
3178 }
3179 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3180 {
3181 PartEntry->NeedsCheck = FALSE;
3182 return CHECK_FILE_SYSTEM_PAGE;
3183 }
3184 }
3185 }
3186 else if (!NT_SUCCESS(Status))
3187 {
3188 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3189 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3190 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3191 "(Status 0x%08lx).\n", Status);
3192 PopupError(Buffer,
3193 // MUIGetString(STRING_REBOOTCOMPUTER),
3194 MUIGetString(STRING_CONTINUE),
3195 Ir, POPUP_WAIT_ENTER);
3196
3197 // return QUIT_PAGE;
3198 }
3199
3200 PartEntry->NeedsCheck = FALSE;
3201 return CHECK_FILE_SYSTEM_PAGE;
3202 }
3203
3204
3205 static VOID
3206 BuildInstallPaths(PWSTR InstallDir,
3207 PDISKENTRY DiskEntry,
3208 PPARTENTRY PartEntry)
3209 {
3210 NTSTATUS Status;
3211
3212 Status = InitDestinationPaths(&USetupData, InstallDir, DiskEntry, PartEntry);
3213 // TODO: Check Status
3214 UNREFERENCED_PARAMETER(Status);
3215
3216 /* Initialize DestinationDriveLetter */
3217 DestinationDriveLetter = PartEntry->DriveLetter;
3218 }
3219
3220
3221 static BOOLEAN
3222 IsValidPath(
3223 IN PCWSTR InstallDir)
3224 {
3225 UINT i, Length;
3226
3227 Length = wcslen(InstallDir);
3228
3229 // TODO: Add check for 8.3 too.
3230
3231 /* Path must be at least 2 characters long */
3232 // if (Length < 2)
3233 // return FALSE;
3234
3235 /* Path must start with a backslash */
3236 // if (InstallDir[0] != L'\\')
3237 // return FALSE;
3238
3239 /* Path must not end with a backslash */
3240 if (InstallDir[Length - 1] == L'\\')
3241 return FALSE;
3242
3243 /* Path must not contain whitespace characters */
3244 for (i = 0; i < Length; i++)
3245 {
3246 if (iswspace(InstallDir[i]))
3247 return FALSE;
3248 }
3249
3250 /* Path component must not end with a dot */
3251 for (i = 0; i < Length; i++)
3252 {
3253 if (InstallDir[i] == L'\\' && i > 0)
3254 {
3255 if (InstallDir[i - 1] == L'.')
3256 return FALSE;
3257 }
3258 }
3259
3260 if (InstallDir[Length - 1] == L'.')
3261 return FALSE;
3262
3263 return TRUE;
3264 }
3265
3266
3267 /*
3268 * Displays the InstallDirectoryPage.
3269 *
3270 * Next pages:
3271 * PrepareCopyPage
3272 * QuitPage
3273 *
3274 * RETURNS
3275 * Number of the next page.
3276 */
3277 static PAGE_NUMBER
3278 InstallDirectoryPage(PINPUT_RECORD Ir)
3279 {
3280 PDISKENTRY DiskEntry;
3281 PPARTENTRY PartEntry;
3282 WCHAR InstallDir[MAX_PATH];
3283 WCHAR c;
3284 ULONG Length, Pos;
3285
3286 /* We do not need the filesystem list anymore */
3287 if (FileSystemList != NULL)
3288 {
3289 DestroyFileSystemList(FileSystemList);
3290 FileSystemList = NULL;
3291 }
3292
3293 if (PartitionList == NULL ||
3294 PartitionList->CurrentDisk == NULL ||
3295 PartitionList->CurrentPartition == NULL)
3296 {
3297 /* FIXME: show an error dialog */
3298 return QUIT_PAGE;
3299 }
3300
3301 DiskEntry = PartitionList->CurrentDisk;
3302 PartEntry = PartitionList->CurrentPartition;
3303
3304 // if (IsUnattendedSetup)
3305 if (RepairUpdateFlag)
3306 wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
3307 else if (USetupData.InstallationDirectory[0])
3308 wcscpy(InstallDir, USetupData.InstallationDirectory);
3309 else
3310 wcscpy(InstallDir, L"\\ReactOS");
3311
3312 /*
3313 * Check the validity of the predefined 'InstallDir'. If we are either
3314 * in unattended setup or in update/repair mode, and the installation path
3315 * is valid, just perform the installation. Otherwise (either in the case
3316 * of an invalid path, or we are in regular setup), display the UI and allow
3317 * the user to specify a new installation path.
3318 */
3319 if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
3320 {
3321 BuildInstallPaths(InstallDir,
3322 DiskEntry,
3323 PartEntry);
3324
3325 /*
3326 * Check whether the user attempts to install ReactOS within the
3327 * installation source directory, or in a subdirectory thereof.
3328 * If so, fail with an error.
3329 */
3330 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3331 {
3332 PopupError("You cannot install ReactOS within the installation source directory!",
3333 MUIGetString(STRING_CONTINUE),
3334 Ir, POPUP_WAIT_ENTER);
3335 return INSTALL_DIRECTORY_PAGE;
3336 }
3337
3338 return PREPARE_COPY_PAGE;
3339 }
3340
3341 Length = wcslen(InstallDir);
3342 Pos = Length;
3343
3344 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3345 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3346 CONSOLE_SetCursorXY(8 + Pos, 11);
3347 CONSOLE_SetCursorType(TRUE, TRUE);
3348
3349 while (TRUE)
3350 {
3351 CONSOLE_ConInKey(Ir);
3352
3353 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3354 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3355 {
3356 CONSOLE_SetCursorType(TRUE, FALSE);
3357
3358 if (ConfirmQuit(Ir))
3359 return QUIT_PAGE;
3360
3361 CONSOLE_SetCursorType(TRUE, TRUE);
3362 break;
3363 }
3364 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3365 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3366 {
3367 if (Pos < Length)
3368 {
3369 memmove(&InstallDir[Pos],
3370 &InstallDir[Pos + 1],
3371 (Length - Pos - 1) * sizeof(WCHAR));
3372 InstallDir[Length - 1] = UNICODE_NULL;
3373
3374 Length--;
3375 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3376 CONSOLE_SetCursorXY(8 + Pos, 11);
3377 }
3378 }
3379 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3380 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3381 {
3382 Pos = 0;
3383 CONSOLE_SetCursorXY(8 + Pos, 11);
3384 }
3385 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3386 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3387 {
3388 Pos = Length;
3389 CONSOLE_SetCursorXY(8 + Pos, 11);
3390 }
3391 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3392 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3393 {
3394 if (Pos > 0)
3395 {
3396 Pos--;
3397 CONSOLE_SetCursorXY(8 + Pos, 11);
3398 }
3399 }
3400 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3401 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3402 {
3403 if (Pos < Length)
3404 {
3405 Pos++;
3406 CONSOLE_SetCursorXY(8 + Pos, 11);
3407 }
3408 }
3409 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3410 {
3411 CONSOLE_SetCursorType(TRUE, FALSE);
3412
3413 /*
3414 * Check for the validity of the installation directory and pop up
3415 * an error if it is not the case. Then the user can fix its input.
3416 */
3417 if (!IsValidPath(InstallDir))
3418 {
3419 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3420 return INSTALL_DIRECTORY_PAGE;
3421 }
3422
3423 BuildInstallPaths(InstallDir,
3424 DiskEntry,
3425 PartEntry);
3426
3427 /*
3428 * Check whether the user attempts to install ReactOS within the
3429 * installation source directory, or in a subdirectory thereof.
3430 * If so, fail with an error.
3431 */
3432 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3433 {
3434 PopupError("You cannot install ReactOS within the installation source directory!",
3435 MUIGetString(STRING_CONTINUE),
3436 Ir, POPUP_WAIT_ENTER);
3437 return INSTALL_DIRECTORY_PAGE;
3438 }
3439
3440 return PREPARE_COPY_PAGE;
3441 }
3442 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3443 {
3444 if (Pos > 0)
3445 {
3446 if (Pos < Length)
3447 memmove(&InstallDir[Pos - 1],
3448 &InstallDir[Pos],
3449 (Length - Pos) * sizeof(WCHAR));
3450 InstallDir[Length - 1] = UNICODE_NULL;
3451
3452 Pos--;
3453 Length--;
3454 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3455 CONSOLE_SetCursorXY(8 + Pos, 11);
3456 }
3457 }
3458 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3459 {
3460 if (Length < 50)
3461 {
3462 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
3463 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3464 {
3465 if (Pos < Length)
3466 memmove(&InstallDir[Pos + 1],
3467 &InstallDir[Pos],
3468 (Length - Pos) * sizeof(WCHAR));
3469 InstallDir[Length + 1] = UNICODE_NULL;
3470 InstallDir[Pos] = c;
3471
3472 Pos++;
3473 Length++;
3474 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3475 CONSOLE_SetCursorXY(8 + Pos, 11);
3476 }
3477 }
3478 }
3479 }
3480
3481 return INSTALL_DIRECTORY_PAGE;
3482 }
3483
3484
3485 // PSETUP_ERROR_ROUTINE
3486 static VOID
3487 __cdecl
3488 USetupErrorRoutine(
3489 IN PUSETUP_DATA pSetupData,
3490 ...)
3491 {
3492 INPUT_RECORD Ir;
3493 va_list arg_ptr;
3494
3495 va_start(arg_ptr, pSetupData);
3496
3497 if (pSetupData->LastErrorNumber >= ERROR_SUCCESS &&
3498 pSetupData->LastErrorNumber < ERROR_LAST_ERROR_CODE)
3499 {
3500 // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
3501 MUIDisplayErrorV(pSetupData->LastErrorNumber, &Ir, POPUP_WAIT_ENTER, arg_ptr);
3502 }
3503
3504 va_end(arg_ptr);
3505 }
3506
3507 /*
3508 * Displays the PrepareCopyPage.
3509 *
3510 * Next pages:
3511 * FileCopyPage(At once)
3512 * QuitPage
3513 *
3514 * SIDEEFFECTS
3515 * Calls PrepareFileCopy
3516 *
3517 * RETURNS
3518 * Number of the next page.
3519 */
3520 static PAGE_NUMBER
3521 PrepareCopyPage(PINPUT_RECORD Ir)
3522 {
3523 // ERROR_NUMBER ErrorNumber;
3524 BOOLEAN Success;
3525
3526 MUIDisplayPage(PREPARE_COPY_PAGE);
3527
3528 /* ErrorNumber = */ Success = PrepareFileCopy(&USetupData, NULL);
3529 if (/*ErrorNumber != ERROR_SUCCESS*/ !Success)
3530 {
3531 // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER);
3532 return QUIT_PAGE;
3533 }
3534
3535 return FILE_COPY_PAGE;
3536 }
3537
3538 typedef struct _COPYCONTEXT
3539 {
3540 ULONG TotalOperations;
3541 ULONG CompletedOperations;
3542 PPROGRESSBAR ProgressBar;
3543 PPROGRESSBAR MemoryBars[4];
3544 } COPYCONTEXT, *PCOPYCONTEXT;
3545
3546 static VOID
3547 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3548 IN BOOLEAN First)
3549 {
3550 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3551
3552 /* Get the memory information from the system */
3553 NtQuerySystemInformation(SystemPerformanceInformation,
3554 &PerfInfo,
3555 sizeof(PerfInfo),
3556 NULL);
3557
3558 /* Check if this is initial setup */
3559 if (First)
3560 {
3561 /* Set maximum limits to be total RAM pages */
3562 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
3563 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
3564 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
3565 }
3566
3567 /* Set current values */
3568 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
3569 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
3570 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
3571 }
3572
3573 static UINT
3574 CALLBACK
3575 FileCopyCallback(PVOID Context,
3576 UINT Notification,
3577 UINT_PTR Param1,
3578 UINT_PTR Param2)
3579 {
3580 PCOPYCONTEXT CopyContext = (PCOPYCONTEXT)Context;
3581 PFILEPATHS_W FilePathInfo;
3582 PCWSTR SrcFileName, DstFileName;
3583
3584 switch (Notification)
3585 {
3586 case SPFILENOTIFY_STARTSUBQUEUE:
3587 {
3588 CopyContext->TotalOperations = (ULONG)Param2;
3589 CopyContext->CompletedOperations = 0;
3590 ProgressSetStepCount(CopyContext->ProgressBar,
3591 CopyContext->TotalOperations);
3592 SetupUpdateMemoryInfo(CopyContext, TRUE);
3593 break;
3594 }
3595
3596 case SPFILENOTIFY_STARTDELETE:
3597 case SPFILENOTIFY_STARTRENAME:
3598 case SPFILENOTIFY_STARTCOPY:
3599 {
3600 FilePathInfo = (PFILEPATHS_W)Param1;
3601
3602 if (Notification == SPFILENOTIFY_STARTDELETE)
3603 {
3604 /* Display delete message */
3605 ASSERT(Param2 == FILEOP_DELETE);
3606
3607 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3608 if (DstFileName) ++DstFileName;
3609 else DstFileName = FilePathInfo->Target;
3610
3611 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING),
3612 DstFileName);
3613 }
3614 else if (Notification == SPFILENOTIFY_STARTRENAME)
3615 {
3616 /* Display move/rename message */
3617 ASSERT(Param2 == FILEOP_RENAME);
3618
3619 SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
3620 if (SrcFileName) ++SrcFileName;
3621 else SrcFileName = FilePathInfo->Source;
3622
3623 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3624 if (DstFileName) ++DstFileName;
3625 else DstFileName = FilePathInfo->Target;
3626
3627 if (!wcsicmp(SrcFileName, DstFileName))
3628 Param2 = STRING_MOVING;
3629 else
3630 Param2 = STRING_RENAMING;
3631
3632 CONSOLE_SetStatusText(MUIGetString(Param2),
3633 SrcFileName, DstFileName);
3634 }
3635 else if (Notification == SPFILENOTIFY_STARTCOPY)
3636 {
3637 /* Display copy message */
3638 ASSERT(Param2 == FILEOP_COPY);
3639
3640 /* NOTE: When extracting from CABs the Source is the CAB name */
3641 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3642 if (DstFileName) ++DstFileName;
3643 else DstFileName = FilePathInfo->Target;
3644
3645 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING),
3646 DstFileName);
3647 }
3648
3649 SetupUpdateMemoryInfo(CopyContext, FALSE);
3650 break;
3651 }
3652
3653 case SPFILENOTIFY_COPYERROR:
3654 {
3655 FilePathInfo = (PFILEPATHS_W)Param1;
3656
3657 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
3658 FilePathInfo->Target, FilePathInfo->Win32Error);
3659 return FILEOP_SKIP;
3660 }
3661
3662 case SPFILENOTIFY_ENDDELETE:
3663 case SPFILENOTIFY_ENDRENAME:
3664 case SPFILENOTIFY_ENDCOPY:
3665 {
3666 CopyContext->CompletedOperations++;
3667
3668 /* SYSREG checkpoint */
3669 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations)
3670 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3671
3672 ProgressNextStep(CopyContext->ProgressBar);
3673 SetupUpdateMemoryInfo(CopyContext, FALSE);
3674 break;
3675 }
3676 }
3677
3678 return FILEOP_DOIT;
3679 }
3680
3681
3682 /*
3683 * Displays the FileCopyPage.
3684 *
3685 * Next pages:
3686 * RegistryPage(At once)
3687 *
3688 * SIDEEFFECTS
3689 * Calls DoFileCopy
3690 *
3691 * RETURNS
3692 * Number of the next page.
3693 */
3694 static PAGE_NUMBER
3695 FileCopyPage(PINPUT_RECORD Ir)
3696 {
3697 COPYCONTEXT CopyContext;
3698 UINT MemBarWidth;
3699
3700 MUIDisplayPage(FILE_COPY_PAGE);
3701
3702 /* Create context for the copy process */
3703 CopyContext.TotalOperations = 0;
3704 CopyContext.CompletedOperations = 0;
3705
3706 /* Create the progress bar as well */
3707 CopyContext.ProgressBar = CreateProgressBar(13,
3708 26,
3709 xScreen - 13,
3710 yScreen - 20,
3711 10,
3712 24,
3713 TRUE,
3714 MUIGetString(STRING_SETUPCOPYINGFILES));
3715
3716 // fit memory bars to screen width, distribute them uniform
3717 MemBarWidth = (xScreen - 26) / 5;
3718 MemBarWidth -= MemBarWidth % 2; // make even
3719 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3720 /* Create the paged pool progress bar */
3721 CopyContext.MemoryBars[0] = CreateProgressBar(13,
3722 40,
3723 13 + MemBarWidth,
3724 43,
3725 13,
3726 44,
3727 FALSE,
3728 "Kernel Pool");
3729
3730 /* Create the non paged pool progress bar */
3731 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (MemBarWidth / 2),
3732 40,
3733 (xScreen / 2) + (MemBarWidth / 2),
3734 43,
3735 (xScreen / 2)- (MemBarWidth / 2),
3736 44,
3737 FALSE,
3738 "Kernel Cache");
3739
3740 /* Create the global memory progress bar */
3741 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - MemBarWidth,
3742 40,
3743 xScreen - 13,
3744 43,
3745 xScreen - 13 - MemBarWidth,
3746 44,
3747 FALSE,
3748 "Free Memory");
3749
3750 /* Do the file copying */
3751 DoFileCopy(&USetupData, FileCopyCallback, &CopyContext);
3752
3753 /* If we get here, we're done, so cleanup the progress bar */
3754 DestroyProgressBar(CopyContext.ProgressBar);
3755 DestroyProgressBar(CopyContext.MemoryBars[0]);
3756 DestroyProgressBar(CopyContext.MemoryBars[1]);
3757 DestroyProgressBar(CopyContext.MemoryBars[2]);
3758
3759 /* Create the $winnt$.inf file */
3760 InstallSetupInfFile(&USetupData);
3761
3762 /* Go display the next page */
3763 return REGISTRY_PAGE;
3764 }
3765
3766
3767 static VOID
3768 __cdecl
3769 RegistryStatus(IN REGISTRY_STATUS RegStatus, ...)
3770 {
3771 /* WARNING: Please keep this lookup table in sync with the resources! */
3772 static const UINT StringIDs[] =
3773 {
3774 STRING_DONE, /* Success */
3775 STRING_REGHIVEUPDATE, /* RegHiveUpdate */
3776 STRING_IMPORTFILE, /* ImportRegHive */
3777 STRING_DISPLAYSETTINGSUPDATE, /* DisplaySettingsUpdate */
3778 STRING_LOCALESETTINGSUPDATE, /* LocaleSettingsUpdate */
3779 STRING_ADDKBLAYOUTS, /* KeybLayouts */
3780 STRING_KEYBOARDSETTINGSUPDATE, /* KeybSettingsUpdate */
3781 STRING_CODEPAGEINFOUPDATE, /* CodePageInfoUpdate */
3782 };
3783
3784 va_list args;
3785
3786 if (RegStatus < ARRAYSIZE(StringIDs))
3787 {
3788 va_start(args, RegStatus);
3789 CONSOLE_SetStatusTextV(MUIGetString(StringIDs[RegStatus]), args);
3790 va_end(args);
3791 }
3792 else
3793 {
3794 CONSOLE_SetStatusText("Unknown status %d", RegStatus);
3795 }
3796 }
3797
3798 /*
3799 * Displays the RegistryPage.
3800 *
3801 * Next pages:
3802 * SuccessPage (if RepairUpdate)
3803 * BootLoaderPage (default)
3804 * QuitPage
3805 *
3806 * SIDEEFFECTS
3807 * Calls UpdateRegistry
3808 *
3809 * RETURNS
3810 * Number of the next page.
3811 */
3812 static PAGE_NUMBER
3813 RegistryPage(PINPUT_RECORD Ir)
3814 {
3815 ULONG Error;
3816
3817 MUIDisplayPage(REGISTRY_PAGE);
3818
3819 Error = UpdateRegistry(&USetupData,
3820 RepairUpdateFlag,
3821 PartitionList,
3822 DestinationDriveLetter,
3823 SelectedLanguageId,
3824 RegistryStatus);
3825 if (Error != ERROR_SUCCESS)
3826 {
3827 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
3828 return QUIT_PAGE;
3829 }
3830 else
3831 {
3832 CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
3833 return BOOT_LOADER_PAGE;
3834 }
3835 }
3836
3837
3838 /*
3839 * Displays the BootLoaderPage.
3840 *
3841 * Next pages:
3842 * SuccessPage (if RepairUpdate)
3843 * BootLoaderHarddiskMbrPage
3844 * BootLoaderHarddiskVbrPage
3845 * BootLoaderFloppyPage
3846 * SuccessPage
3847 * QuitPage
3848 *
3849 * SIDEEFFECTS
3850 * Calls RegInitializeRegistry
3851 * Calls ImportRegistryFile
3852 * Calls SetDefaultPagefile
3853 * Calls SetMountedDeviceValues
3854 *
3855 * RETURNS
3856 * Number of the next page.
3857 */
3858 static PAGE_NUMBER
3859 BootLoaderPage(PINPUT_RECORD Ir)
3860 {
3861 UCHAR PartitionType;
3862 BOOLEAN InstallOnFloppy;
3863 USHORT Line = 12;
3864 WCHAR PathBuffer[MAX_PATH];
3865
3866 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3867
3868 RtlFreeUnicodeString(&USetupData.SystemRootPath);
3869 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3870 L"\\Device\\Harddisk%lu\\Partition%lu\\",
3871 PartitionList->SystemPartition->DiskEntry->DiskNumber,
3872 PartitionList->SystemPartition->PartitionNumber);
3873 RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer);
3874 DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath);
3875
3876 PartitionType = PartitionList->SystemPartition->PartitionType;
3877
3878 /* For unattended setup, skip MBR installation or install on floppy if needed */
3879 if (IsUnattendedSetup)
3880 {
3881 if ((USetupData.MBRInstallType == 0) ||
3882 (USetupData.MBRInstallType == 1))
3883 {
3884 goto Quit;
3885 }
3886 }
3887
3888 /*
3889 * We may install an MBR or VBR, but before that, check whether
3890 * we need to actually install the VBR on floppy.
3891 */
3892 if (PartitionType == PARTITION_ENTRY_UNUSED)
3893 {
3894 DPRINT("Error: system partition invalid (unused)\n");
3895 InstallOnFloppy = TRUE;
3896 }
3897 else if (PartitionType == PARTITION_OS2BOOTMGR)
3898 {
3899 /* OS/2 boot manager partition */
3900 DPRINT("Found OS/2 boot manager partition\n");
3901 InstallOnFloppy = TRUE;
3902 }
3903 else if (PartitionType == PARTITION_LINUX)
3904 {
3905 /* Linux partition */
3906 DPRINT("Found Linux native partition (ext2/ext3/ReiserFS/BTRFS/etc)\n");
3907 InstallOnFloppy = FALSE;
3908 }
3909 else if (PartitionType == PARTITION_IFS)
3910 {
3911 /* NTFS partition */
3912 DPRINT("Found NTFS partition\n");
3913
3914 // FIXME: Make it FALSE when we'll support NTFS installation!
3915 InstallOnFloppy = TRUE;
3916 }
3917 else if ((PartitionType == PARTITION_FAT_12) ||
3918 (PartitionType == PARTITION_FAT_16) ||
3919 (PartitionType == PARTITION_HUGE) ||
3920 (PartitionType == PARTITION_XINT13) ||
3921 (PartitionType == PARTITION_FAT32) ||
3922 (PartitionType == PARTITION_FAT32_XINT13))
3923 {
3924 DPRINT("Found FAT partition\n");
3925 InstallOnFloppy = FALSE;
3926 }
3927 else
3928 {
3929 /* Unknown partition */
3930 DPRINT("Unknown partition found\n");
3931 InstallOnFloppy = TRUE;
3932 }
3933
3934 /* We should install on floppy */
3935 if (InstallOnFloppy)
3936 {
3937 USetupData.MBRInstallType = 1;
3938 goto Quit;
3939 }
3940
3941 /* Is it an unattended install on hdd? */
3942 if (IsUnattendedSetup)
3943 {
3944 if ((USetupData.MBRInstallType == 2) ||
3945 (USetupData.MBRInstallType == 3))
3946 {
3947 goto Quit;
3948 }
3949 }
3950
3951 MUIDisplayPage(BOOT_LOADER_PAGE);
3952 CONSOLE_InvertTextXY(8, Line, 60, 1);
3953
3954 while (TRUE)
3955 {
3956 CONSOLE_ConInKey(Ir);
3957
3958 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3959 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
3960 {
3961 CONSOLE_NormalTextXY(8, Line, 60, 1);
3962
3963 Line++;
3964 if (Line < 12)
3965 Line = 15;
3966
3967 if (Line > 15)
3968 Line = 12;
3969
3970 CONSOLE_InvertTextXY(8, Line, 60, 1);
3971 }
3972 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3973 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
3974 {
3975 CONSOLE_NormalTextXY(8, Line, 60, 1);
3976
3977 Line--;
3978 if (Line < 12)
3979 Line = 15;
3980
3981 if (Line > 15)
3982 Line = 12;
3983
3984 CONSOLE_InvertTextXY(8, Line, 60, 1);
3985 }
3986 else if ((Ir->Event.KeyEvent.uChar.