ae5b86be94ecd7ce221a8ae0d6d2510aca086d72
[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 CreateLogicalPartition(PartitionList,
1611 0ULL,
1612 TRUE);
1613 }
1614 else
1615 {
1616 CreatePrimaryPartition(PartitionList,
1617 0ULL,
1618 TRUE);
1619 }
1620 }
1621
1622 if (!IsDiskSizeValid(PartitionList->CurrentPartition))
1623 {
1624 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
1625 USetupData.RequiredPartitionDiskSpace);
1626 return SELECT_PARTITION_PAGE; /* let the user select another partition */
1627 }
1628
1629 return SELECT_FILE_SYSTEM_PAGE;
1630 }
1631 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */
1632 {
1633 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1634 {
1635 Error = PrimaryPartitionCreationChecks(PartitionList);
1636 if (Error != NOT_AN_ERROR)
1637 {
1638 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
1639 return SELECT_PARTITION_PAGE;
1640 }
1641
1642 return CREATE_PRIMARY_PARTITION_PAGE;
1643 }
1644 }
1645 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */
1646 {
1647 if (PartitionList->CurrentPartition->LogicalPartition == FALSE)
1648 {
1649 Error = ExtendedPartitionCreationChecks(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_EXTENDED_PARTITION_PAGE;
1657 }
1658 }
1659 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */
1660 {
1661 if (PartitionList->CurrentPartition->LogicalPartition)
1662 {
1663 Error = LogicalPartitionCreationChecks(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_LOGICAL_PARTITION_PAGE;
1671 }
1672 }
1673 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
1674 {
1675 WCHAR PathBuffer[MAX_PATH];
1676 UNICODE_STRING CurrentPartition;
1677
1678 if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
1679 {
1680 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1681 return SELECT_PARTITION_PAGE;
1682 }
1683
1684 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
1685 L"\\Device\\Harddisk%lu\\Partition%lu\\",
1686 PartitionList->CurrentDisk->DiskNumber,
1687 PartitionList->CurrentPartition->PartitionNumber);
1688 RtlInitUnicodeString(&CurrentPartition, PathBuffer);
1689
1690 /*
1691 * Check whether the user attempts to delete the partition on which
1692 * the installation source is present. If so, fail with an error.
1693 */
1694 // &USetupData.SourceRootPath
1695 if (RtlPrefixUnicodeString(&CurrentPartition, &USetupData.SourcePath, TRUE))
1696 {
1697 PopupError("You cannot delete the partition containing the installation source!",
1698 MUIGetString(STRING_CONTINUE),
1699 Ir, POPUP_WAIT_ENTER);
1700 return SELECT_PARTITION_PAGE;
1701 }
1702
1703 if (PartitionList->CurrentPartition->BootIndicator ||
1704 PartitionList->CurrentPartition == PartitionList->SystemPartition)
1705 {
1706 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1707 }
1708
1709 return DELETE_PARTITION_PAGE;
1710 }
1711 }
1712
1713 return SELECT_PARTITION_PAGE;
1714 }
1715
1716
1717 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1718 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1719 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1720
1721 static VOID
1722 ShowPartitionSizeInputBox(SHORT Left,
1723 SHORT Top,
1724 SHORT Right,
1725 SHORT Bottom,
1726 ULONG MaxSize,
1727 PWSTR InputBuffer,
1728 PBOOLEAN Quit,
1729 PBOOLEAN Cancel)
1730 {
1731 INPUT_RECORD Ir;
1732 COORD coPos;
1733 DWORD Written;
1734 CHAR Buffer[128];
1735 INT Length, Pos;
1736 WCHAR ch;
1737 SHORT iLeft;
1738 SHORT iTop;
1739
1740 if (Quit != NULL)
1741 *Quit = FALSE;
1742
1743 if (Cancel != NULL)
1744 *Cancel = FALSE;
1745
1746 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1747
1748 /* Print message */
1749 coPos.X = Left + 2;
1750 coPos.Y = Top + 2;
1751 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1752 iLeft = coPos.X + strlen(Buffer) + 1;
1753 iTop = coPos.Y;
1754
1755 WriteConsoleOutputCharacterA(StdOutput,
1756 Buffer,
1757 strlen(Buffer),
1758 coPos,
1759 &Written);
1760
1761 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1762 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1763 coPos.Y = iTop;
1764 WriteConsoleOutputCharacterA(StdOutput,
1765 Buffer,
1766 strlen(Buffer),
1767 coPos,
1768 &Written);
1769
1770 swprintf(InputBuffer, L"%lu", MaxSize);
1771 Length = wcslen(InputBuffer);
1772 Pos = Length;
1773 CONSOLE_SetInputTextXY(iLeft,
1774 iTop,
1775 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1776 InputBuffer);
1777 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1778 CONSOLE_SetCursorType(TRUE, TRUE);
1779
1780 while (TRUE)
1781 {
1782 CONSOLE_ConInKey(&Ir);
1783
1784 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1785 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1786 {
1787 if (Quit != NULL)
1788 *Quit = TRUE;
1789
1790 InputBuffer[0] = UNICODE_NULL;
1791 CONSOLE_SetCursorType(TRUE, FALSE);
1792 break;
1793 }
1794 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1795 {
1796 CONSOLE_SetCursorType(TRUE, FALSE);
1797 break;
1798 }
1799 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1800 {
1801 if (Cancel != NULL)
1802 *Cancel = TRUE;
1803
1804 InputBuffer[0] = UNICODE_NULL;
1805 CONSOLE_SetCursorType(TRUE, FALSE);
1806 break;
1807 }
1808 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1809 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1810 {
1811 Pos = 0;
1812 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1813 }
1814 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1815 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1816 {
1817 Pos = Length;
1818 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1819 }
1820 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1821 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1822 {
1823 if (Pos > 0)
1824 {
1825 Pos--;
1826 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1827 }
1828 }
1829 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1830 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1831 {
1832 if (Pos < Length)
1833 {
1834 Pos++;
1835 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1836 }
1837 }
1838 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1839 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1840 {
1841 if (Pos < Length)
1842 {
1843 memmove(&InputBuffer[Pos],
1844 &InputBuffer[Pos + 1],
1845 (Length - Pos - 1) * sizeof(WCHAR));
1846 InputBuffer[Length - 1] = UNICODE_NULL;
1847
1848 Length--;
1849 CONSOLE_SetInputTextXY(iLeft,
1850 iTop,
1851 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1852 InputBuffer);
1853 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1854 }
1855 }
1856 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
1857 {
1858 if (Pos > 0)
1859 {
1860 if (Pos < Length)
1861 memmove(&InputBuffer[Pos - 1],
1862 &InputBuffer[Pos],
1863 (Length - Pos) * sizeof(WCHAR));
1864 InputBuffer[Length - 1] = UNICODE_NULL;
1865
1866 Pos--;
1867 Length--;
1868 CONSOLE_SetInputTextXY(iLeft,
1869 iTop,
1870 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1871 InputBuffer);
1872 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1873 }
1874 }
1875 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
1876 {
1877 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
1878 {
1879 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1880
1881 if ((ch >= L'0') && (ch <= L'9'))
1882 {
1883 if (Pos < Length)
1884 memmove(&InputBuffer[Pos + 1],
1885 &InputBuffer[Pos],
1886 (Length - Pos) * sizeof(WCHAR));
1887 InputBuffer[Length + 1] = UNICODE_NULL;
1888 InputBuffer[Pos] = ch;
1889
1890 Pos++;
1891 Length++;
1892 CONSOLE_SetInputTextXY(iLeft,
1893 iTop,
1894 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1895 InputBuffer);
1896 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1897 }
1898 }
1899 }
1900 }
1901 }
1902
1903
1904 /*
1905 * Displays the CreatePrimaryPartitionPage.
1906 *
1907 * Next pages:
1908 * SelectPartitionPage
1909 * SelectFileSystemPage (default)
1910 * QuitPage
1911 *
1912 * RETURNS
1913 * Number of the next page.
1914 */
1915 static PAGE_NUMBER
1916 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
1917 {
1918 PDISKENTRY DiskEntry;
1919 PPARTENTRY PartEntry;
1920 BOOLEAN Quit;
1921 BOOLEAN Cancel;
1922 WCHAR InputBuffer[50];
1923 ULONG MaxSize;
1924 ULONGLONG PartSize;
1925 ULONGLONG DiskSize;
1926 ULONGLONG SectorCount;
1927 PCHAR Unit;
1928
1929 if (PartitionList == NULL ||
1930 PartitionList->CurrentDisk == NULL ||
1931 PartitionList->CurrentPartition == NULL)
1932 {
1933 /* FIXME: show an error dialog */
1934 return QUIT_PAGE;
1935 }
1936
1937 DiskEntry = PartitionList->CurrentDisk;
1938 PartEntry = PartitionList->CurrentPartition;
1939
1940 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
1941
1942 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
1943
1944 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1945 #if 0
1946 if (DiskSize >= 10 * GB) /* 10 GB */
1947 {
1948 DiskSize = DiskSize / GB;
1949 Unit = MUIGetString(STRING_GB);
1950 }
1951 else
1952 #endif
1953 {
1954 DiskSize = DiskSize / MB;
1955 if (DiskSize == 0)
1956 DiskSize = 1;
1957
1958 Unit = MUIGetString(STRING_MB);
1959 }
1960
1961 if (DiskEntry->DriverName.Length > 0)
1962 {
1963 CONSOLE_PrintTextXY(6, 10,
1964 MUIGetString(STRING_HDINFOPARTCREATE_1),
1965 DiskSize,
1966 Unit,
1967 DiskEntry->DiskNumber,
1968 DiskEntry->Port,
1969 DiskEntry->Bus,
1970 DiskEntry->Id,
1971 &DiskEntry->DriverName,
1972 DiskEntry->NoMbr ? "GPT" : "MBR");
1973 }
1974 else
1975 {
1976 CONSOLE_PrintTextXY(6, 10,
1977 MUIGetString(STRING_HDINFOPARTCREATE_2),
1978 DiskSize,
1979 Unit,
1980 DiskEntry->DiskNumber,
1981 DiskEntry->Port,
1982 DiskEntry->Bus,
1983 DiskEntry->Id,
1984 DiskEntry->NoMbr ? "GPT" : "MBR");
1985 }
1986
1987 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
1988
1989 #if 0
1990 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
1991 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
1992 #endif
1993
1994 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
1995
1996 PartEntry = PartitionList->CurrentPartition;
1997 while (TRUE)
1998 {
1999 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2000
2001 if (MaxSize > PARTITION_MAXSIZE)
2002 MaxSize = PARTITION_MAXSIZE;
2003
2004 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2005 MaxSize, InputBuffer, &Quit, &Cancel);
2006
2007 if (Quit)
2008 {
2009 if (ConfirmQuit(Ir))
2010 return QUIT_PAGE;
2011
2012 break;
2013 }
2014 else if (Cancel)
2015 {
2016 return SELECT_PARTITION_PAGE;
2017 }
2018 else
2019 {
2020 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2021
2022 if (PartSize < 1)
2023 {
2024 /* Too small */
2025 continue;
2026 }
2027
2028 if (PartSize > MaxSize)
2029 {
2030 /* Too large */
2031 continue;
2032 }
2033
2034 /* Convert to bytes */
2035 if (PartSize == MaxSize)
2036 {
2037 /* Use all of the unpartitioned disk space */
2038 SectorCount = PartEntry->SectorCount.QuadPart;
2039 }
2040 else
2041 {
2042 /* Calculate the sector count from the size in MB */
2043 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2044
2045 /* But never get larger than the unpartitioned disk space */
2046 if (SectorCount > PartEntry->SectorCount.QuadPart)
2047 SectorCount = PartEntry->SectorCount.QuadPart;
2048 }
2049
2050 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2051
2052 CreatePrimaryPartition(PartitionList,
2053 SectorCount,
2054 FALSE);
2055
2056 return SELECT_PARTITION_PAGE;
2057 }
2058 }
2059
2060 return CREATE_PRIMARY_PARTITION_PAGE;
2061 }
2062
2063
2064 /*
2065 * Displays the CreateExtendedPartitionPage.
2066 *
2067 * Next pages:
2068 * SelectPartitionPage (default)
2069 * QuitPage
2070 *
2071 * RETURNS
2072 * Number of the next page.
2073 */
2074 static PAGE_NUMBER
2075 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2076 {
2077 PDISKENTRY DiskEntry;
2078 PPARTENTRY PartEntry;
2079 BOOLEAN Quit;
2080 BOOLEAN Cancel;
2081 WCHAR InputBuffer[50];
2082 ULONG MaxSize;
2083 ULONGLONG PartSize;
2084 ULONGLONG DiskSize;
2085 ULONGLONG SectorCount;
2086 PCHAR Unit;
2087
2088 if (PartitionList == NULL ||
2089 PartitionList->CurrentDisk == NULL ||
2090 PartitionList->CurrentPartition == NULL)
2091 {
2092 /* FIXME: show an error dialog */
2093 return QUIT_PAGE;
2094 }
2095
2096 DiskEntry = PartitionList->CurrentDisk;
2097 PartEntry = PartitionList->CurrentPartition;
2098
2099 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2100
2101 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2102
2103 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2104 #if 0
2105 if (DiskSize >= 10 * GB) /* 10 GB */
2106 {
2107 DiskSize = DiskSize / GB;
2108 Unit = MUIGetString(STRING_GB);
2109 }
2110 else
2111 #endif
2112 {
2113 DiskSize = DiskSize / MB;
2114 if (DiskSize == 0)
2115 DiskSize = 1;
2116
2117 Unit = MUIGetString(STRING_MB);
2118 }
2119
2120 if (DiskEntry->DriverName.Length > 0)
2121 {
2122 CONSOLE_PrintTextXY(6, 10,
2123 MUIGetString(STRING_HDINFOPARTCREATE_1),
2124 DiskSize,
2125 Unit,
2126 DiskEntry->DiskNumber,
2127 DiskEntry->Port,
2128 DiskEntry->Bus,
2129 DiskEntry->Id,
2130 &DiskEntry->DriverName,
2131 DiskEntry->NoMbr ? "GPT" : "MBR");
2132 }
2133 else
2134 {
2135 CONSOLE_PrintTextXY(6, 10,
2136 MUIGetString(STRING_HDINFOPARTCREATE_2),
2137 DiskSize,
2138 Unit,
2139 DiskEntry->DiskNumber,
2140 DiskEntry->Port,
2141 DiskEntry->Bus,
2142 DiskEntry->Id,
2143 DiskEntry->NoMbr ? "GPT" : "MBR");
2144 }
2145
2146 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2147
2148 #if 0
2149 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2150 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2151 #endif
2152
2153 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2154
2155 PartEntry = PartitionList->CurrentPartition;
2156 while (TRUE)
2157 {
2158 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2159
2160 if (MaxSize > PARTITION_MAXSIZE)
2161 MaxSize = PARTITION_MAXSIZE;
2162
2163 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2164 MaxSize, InputBuffer, &Quit, &Cancel);
2165
2166 if (Quit)
2167 {
2168 if (ConfirmQuit(Ir))
2169 return QUIT_PAGE;
2170
2171 break;
2172 }
2173 else if (Cancel)
2174 {
2175 return SELECT_PARTITION_PAGE;
2176 }
2177 else
2178 {
2179 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2180
2181 if (PartSize < 1)
2182 {
2183 /* Too small */
2184 continue;
2185 }
2186
2187 if (PartSize > MaxSize)
2188 {
2189 /* Too large */
2190 continue;
2191 }
2192
2193 /* Convert to bytes */
2194 if (PartSize == MaxSize)
2195 {
2196 /* Use all of the unpartitioned disk space */
2197 SectorCount = PartEntry->SectorCount.QuadPart;
2198 }
2199 else
2200 {
2201 /* Calculate the sector count from the size in MB */
2202 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2203
2204 /* But never get larger than the unpartitioned disk space */
2205 if (SectorCount > PartEntry->SectorCount.QuadPart)
2206 SectorCount = PartEntry->SectorCount.QuadPart;
2207 }
2208
2209 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2210
2211 CreateExtendedPartition(PartitionList,
2212 SectorCount);
2213
2214 return SELECT_PARTITION_PAGE;
2215 }
2216 }
2217
2218 return CREATE_EXTENDED_PARTITION_PAGE;
2219 }
2220
2221
2222 /*
2223 * Displays the CreateLogicalPartitionPage.
2224 *
2225 * Next pages:
2226 * SelectFileSystemPage (default)
2227 * QuitPage
2228 *
2229 * RETURNS
2230 * Number of the next page.
2231 */
2232 static PAGE_NUMBER
2233 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2234 {
2235 PDISKENTRY DiskEntry;
2236 PPARTENTRY PartEntry;
2237 BOOLEAN Quit;
2238 BOOLEAN Cancel;
2239 WCHAR InputBuffer[50];
2240 ULONG MaxSize;
2241 ULONGLONG PartSize;
2242 ULONGLONG DiskSize;
2243 ULONGLONG SectorCount;
2244 PCHAR Unit;
2245
2246 if (PartitionList == NULL ||
2247 PartitionList->CurrentDisk == NULL ||
2248 PartitionList->CurrentPartition == NULL)
2249 {
2250 /* FIXME: show an error dialog */
2251 return QUIT_PAGE;
2252 }
2253
2254 DiskEntry = PartitionList->CurrentDisk;
2255 PartEntry = PartitionList->CurrentPartition;
2256
2257 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2258
2259 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2260
2261 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2262 #if 0
2263 if (DiskSize >= 10 * GB) /* 10 GB */
2264 {
2265 DiskSize = DiskSize / GB;
2266 Unit = MUIGetString(STRING_GB);
2267 }
2268 else
2269 #endif
2270 {
2271 DiskSize = DiskSize / MB;
2272 if (DiskSize == 0)
2273 DiskSize = 1;
2274
2275 Unit = MUIGetString(STRING_MB);
2276 }
2277
2278 if (DiskEntry->DriverName.Length > 0)
2279 {
2280 CONSOLE_PrintTextXY(6, 10,
2281 MUIGetString(STRING_HDINFOPARTCREATE_1),
2282 DiskSize,
2283 Unit,
2284 DiskEntry->DiskNumber,
2285 DiskEntry->Port,
2286 DiskEntry->Bus,
2287 DiskEntry->Id,
2288 &DiskEntry->DriverName,
2289 DiskEntry->NoMbr ? "GPT" : "MBR");
2290 }
2291 else
2292 {
2293 CONSOLE_PrintTextXY(6, 10,
2294 MUIGetString(STRING_HDINFOPARTCREATE_2),
2295 DiskSize,
2296 Unit,
2297 DiskEntry->DiskNumber,
2298 DiskEntry->Port,
2299 DiskEntry->Bus,
2300 DiskEntry->Id,
2301 DiskEntry->NoMbr ? "GPT" : "MBR");
2302 }
2303
2304 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2305
2306 #if 0
2307 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2308 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2309 #endif
2310
2311 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2312
2313 PartEntry = PartitionList->CurrentPartition;
2314 while (TRUE)
2315 {
2316 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2317
2318 if (MaxSize > PARTITION_MAXSIZE)
2319 MaxSize = PARTITION_MAXSIZE;
2320
2321 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2322 MaxSize, InputBuffer, &Quit, &Cancel);
2323
2324 if (Quit)
2325 {
2326 if (ConfirmQuit(Ir))
2327 return QUIT_PAGE;
2328
2329 break;
2330 }
2331 else if (Cancel)
2332 {
2333 return SELECT_PARTITION_PAGE;
2334 }
2335 else
2336 {
2337 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2338
2339 if (PartSize < 1)
2340 {
2341 /* Too small */
2342 continue;
2343 }
2344
2345 if (PartSize > MaxSize)
2346 {
2347 /* Too large */
2348 continue;
2349 }
2350
2351 /* Convert to bytes */
2352 if (PartSize == MaxSize)
2353 {
2354 /* Use all of the unpartitioned disk space */
2355 SectorCount = PartEntry->SectorCount.QuadPart;
2356 }
2357 else
2358 {
2359 /* Calculate the sector count from the size in MB */
2360 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2361
2362 /* But never get larger than the unpartitioned disk space */
2363 if (SectorCount > PartEntry->SectorCount.QuadPart)
2364 SectorCount = PartEntry->SectorCount.QuadPart;
2365 }
2366
2367 DPRINT("Partition size: %I64u bytes\n", PartSize);
2368
2369 CreateLogicalPartition(PartitionList,
2370 SectorCount,
2371 FALSE);
2372
2373 return SELECT_PARTITION_PAGE;
2374 }
2375 }
2376
2377 return CREATE_LOGICAL_PARTITION_PAGE;
2378 }
2379
2380
2381 /*
2382 * Displays the ConfirmDeleteSystemPartitionPage.
2383 *
2384 * Next pages:
2385 * DeletePartitionPage (default)
2386 * SelectPartitionPage
2387 *
2388 * RETURNS
2389 * Number of the next page.
2390 */
2391 static PAGE_NUMBER
2392 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2393 {
2394 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2395
2396 while (TRUE)
2397 {
2398 CONSOLE_ConInKey(Ir);
2399
2400 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2401 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2402 {
2403 if (ConfirmQuit(Ir))
2404 return QUIT_PAGE;
2405
2406 break;
2407 }
2408 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2409 {
2410 return DELETE_PARTITION_PAGE;
2411 }
2412 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2413 {
2414 return SELECT_PARTITION_PAGE;
2415 }
2416 }
2417
2418 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2419 }
2420
2421
2422 /*
2423 * Displays the DeletePartitionPage.
2424 *
2425 * Next pages:
2426 * SelectPartitionPage (default)
2427 * QuitPage
2428 *
2429 * RETURNS
2430 * Number of the next page.
2431 */
2432 static PAGE_NUMBER
2433 DeletePartitionPage(PINPUT_RECORD Ir)
2434 {
2435 PDISKENTRY DiskEntry;
2436 PPARTENTRY PartEntry;
2437 ULONGLONG DiskSize;
2438 ULONGLONG PartSize;
2439 PCHAR Unit;
2440 CHAR PartTypeString[32];
2441
2442 if (PartitionList == NULL ||
2443 PartitionList->CurrentDisk == NULL ||
2444 PartitionList->CurrentPartition == NULL)
2445 {
2446 /* FIXME: show an error dialog */
2447 return QUIT_PAGE;
2448 }
2449
2450 DiskEntry = PartitionList->CurrentDisk;
2451 PartEntry = PartitionList->CurrentPartition;
2452
2453 MUIDisplayPage(DELETE_PARTITION_PAGE);
2454
2455 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2456 PartTypeString,
2457 ARRAYSIZE(PartTypeString));
2458
2459 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2460 #if 0
2461 if (PartSize >= 10 * GB) /* 10 GB */
2462 {
2463 PartSize = PartSize / GB;
2464 Unit = MUIGetString(STRING_GB);
2465 }
2466 else
2467 #endif
2468 if (PartSize >= 10 * MB) /* 10 MB */
2469 {
2470 PartSize = PartSize / MB;
2471 Unit = MUIGetString(STRING_MB);
2472 }
2473 else
2474 {
2475 PartSize = PartSize / KB;
2476 Unit = MUIGetString(STRING_KB);
2477 }
2478
2479 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2480 {
2481 CONSOLE_PrintTextXY(6, 10,
2482 MUIGetString(STRING_HDDINFOUNK2),
2483 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2484 (PartEntry->DriveLetter == 0) ? '-' : ':',
2485 PartEntry->PartitionType,
2486 PartSize,
2487 Unit);
2488 }
2489 else
2490 {
2491 CONSOLE_PrintTextXY(6, 10,
2492 " %c%c %s %I64u %s",
2493 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2494 (PartEntry->DriveLetter == 0) ? '-' : ':',
2495 PartTypeString,
2496 PartSize,
2497 Unit);
2498 }
2499
2500 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2501 #if 0
2502 if (DiskSize >= 10 * GB) /* 10 GB */
2503 {
2504 DiskSize = DiskSize / GB;
2505 Unit = MUIGetString(STRING_GB);
2506 }
2507 else
2508 #endif
2509 {
2510 DiskSize = DiskSize / MB;
2511 if (DiskSize == 0)
2512 DiskSize = 1;
2513
2514 Unit = MUIGetString(STRING_MB);
2515 }
2516
2517 if (DiskEntry->DriverName.Length > 0)
2518 {
2519 CONSOLE_PrintTextXY(6, 12,
2520 MUIGetString(STRING_HDINFOPARTDELETE_1),
2521 DiskSize,
2522 Unit,
2523 DiskEntry->DiskNumber,
2524 DiskEntry->Port,
2525 DiskEntry->Bus,
2526 DiskEntry->Id,
2527 &DiskEntry->DriverName,
2528 DiskEntry->NoMbr ? "GPT" : "MBR");
2529 }
2530 else
2531 {
2532 CONSOLE_PrintTextXY(6, 12,
2533 MUIGetString(STRING_HDINFOPARTDELETE_2),
2534 DiskSize,
2535 Unit,
2536 DiskEntry->DiskNumber,
2537 DiskEntry->Port,
2538 DiskEntry->Bus,
2539 DiskEntry->Id,
2540 DiskEntry->NoMbr ? "GPT" : "MBR");
2541 }
2542
2543 while (TRUE)
2544 {
2545 CONSOLE_ConInKey(Ir);
2546
2547 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2548 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2549 {
2550 if (ConfirmQuit(Ir))
2551 return QUIT_PAGE;
2552
2553 break;
2554 }
2555 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2556 {
2557 return SELECT_PARTITION_PAGE;
2558 }
2559 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2560 {
2561 DeleteCurrentPartition(PartitionList);
2562
2563 return SELECT_PARTITION_PAGE;
2564 }
2565 }
2566
2567 return DELETE_PARTITION_PAGE;
2568 }
2569
2570
2571 /*
2572 * Displays the SelectFileSystemPage.
2573 *
2574 * Next pages:
2575 * CheckFileSystemPage (At once if RepairUpdate is selected)
2576 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2577 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2578 * SelectPartitionPage (If the user aborts)
2579 * FormatPartitionPage (Default)
2580 * QuitPage
2581 *
2582 * SIDEEFFECTS
2583 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2584 * Calls CheckActiveSystemPartition()
2585 *
2586 * RETURNS
2587 * Number of the next page.
2588 */
2589 static PAGE_NUMBER
2590 SelectFileSystemPage(PINPUT_RECORD Ir)
2591 {
2592 PDISKENTRY DiskEntry;
2593 PPARTENTRY PartEntry;
2594 ULONGLONG DiskSize;
2595 ULONGLONG PartSize;
2596 PCHAR DiskUnit;
2597 PCHAR PartUnit;
2598 CHAR PartTypeString[32];
2599 FORMATMACHINESTATE PreviousFormatState;
2600
2601 DPRINT("SelectFileSystemPage()\n");
2602
2603 if (PartitionList == NULL ||
2604 PartitionList->CurrentDisk == NULL ||
2605 PartitionList->CurrentPartition == NULL)
2606 {
2607 /* FIXME: show an error dialog */
2608 return QUIT_PAGE;
2609 }
2610
2611 /* Find or set the active system partition */
2612 CheckActiveSystemPartition(PartitionList);
2613 if (PartitionList->SystemPartition == NULL)
2614 {
2615 /* FIXME: show an error dialog */
2616 //
2617 // Error dialog should say that we cannot find a suitable
2618 // system partition and create one on the system. At this point,
2619 // it may be nice to ask the user whether he wants to continue,
2620 // or use an external drive as the system drive/partition
2621 // (e.g. floppy, USB drive, etc...)
2622 //
2623 return QUIT_PAGE;
2624 }
2625
2626 PreviousFormatState = FormatState;
2627 switch (FormatState)
2628 {
2629 case Start:
2630 {
2631 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2632 {
2633 TempPartition = PartitionList->SystemPartition;
2634 TempPartition->NeedsCheck = TRUE;
2635
2636 FormatState = FormatSystemPartition;
2637 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2638 }
2639 else
2640 {
2641 TempPartition = PartitionList->CurrentPartition;
2642 TempPartition->NeedsCheck = TRUE;
2643
2644 FormatState = FormatInstallPartition;
2645 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2646 }
2647 break;
2648 }
2649
2650 case FormatSystemPartition:
2651 {
2652 TempPartition = PartitionList->CurrentPartition;
2653 TempPartition->NeedsCheck = TRUE;
2654
2655 FormatState = FormatInstallPartition;
2656 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2657 break;
2658 }
2659
2660 case FormatInstallPartition:
2661 {
2662 if (GetNextUnformattedPartition(PartitionList,
2663 NULL,
2664 &TempPartition))
2665 {
2666 FormatState = FormatOtherPartition;
2667 TempPartition->NeedsCheck = TRUE;
2668 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2669 }
2670 else
2671 {
2672 FormatState = FormatDone;
2673 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2674 return CHECK_FILE_SYSTEM_PAGE;
2675 }
2676 break;
2677 }
2678
2679 case FormatOtherPartition:
2680 {
2681 if (GetNextUnformattedPartition(PartitionList,
2682 NULL,
2683 &TempPartition))
2684 {
2685 FormatState = FormatOtherPartition;
2686 TempPartition->NeedsCheck = TRUE;
2687 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2688 }
2689 else
2690 {
2691 FormatState = FormatDone;
2692 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2693 return CHECK_FILE_SYSTEM_PAGE;
2694 }
2695 break;
2696 }
2697
2698 default:
2699 {
2700 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2701 /* FIXME: show an error dialog */
2702 return QUIT_PAGE;
2703 }
2704 }
2705
2706 PartEntry = TempPartition;
2707 DiskEntry = PartEntry->DiskEntry;
2708
2709 /* Adjust disk size */
2710 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2711 if (DiskSize >= 10 * GB) /* 10 GB */
2712 {
2713 DiskSize = DiskSize / GB;
2714 DiskUnit = MUIGetString(STRING_GB);
2715 }
2716 else
2717 {
2718 DiskSize = DiskSize / MB;
2719 DiskUnit = MUIGetString(STRING_MB);
2720 }
2721
2722 /* Adjust partition size */
2723 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2724 if (PartSize >= 10 * GB) /* 10 GB */
2725 {
2726 PartSize = PartSize / GB;
2727 PartUnit = MUIGetString(STRING_GB);
2728 }
2729 else
2730 {
2731 PartSize = PartSize / MB;
2732 PartUnit = MUIGetString(STRING_MB);
2733 }
2734
2735 /* Adjust partition type */
2736 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2737 PartTypeString,
2738 ARRAYSIZE(PartTypeString));
2739
2740 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2741
2742 if (PartEntry->AutoCreate)
2743 {
2744 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2745
2746 #if 0
2747 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2748 PartEntry->PartitionNumber,
2749 PartSize,
2750 PartUnit,
2751 PartTypeString);
2752 #endif
2753
2754 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
2755 DiskEntry->DiskNumber,
2756 DiskSize,
2757 DiskUnit,
2758 DiskEntry->Port,
2759 DiskEntry->Bus,
2760 DiskEntry->Id,
2761 &DiskEntry->DriverName,
2762 DiskEntry->NoMbr ? "GPT" : "MBR");
2763
2764 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2765
2766 PartEntry->AutoCreate = FALSE;
2767 }
2768 else if (PartEntry->New)
2769 {
2770 switch (FormatState)
2771 {
2772 case FormatSystemPartition:
2773 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2774 break;
2775
2776 case FormatInstallPartition:
2777 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2778 break;
2779
2780 case FormatOtherPartition:
2781 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2782 break;
2783
2784 default:
2785 break;
2786 }
2787
2788 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2789 }
2790 else
2791 {
2792 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2793
2794 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2795 {
2796 CONSOLE_PrintTextXY(8, 10,
2797 MUIGetString(STRING_HDDINFOUNK4),
2798 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2799 (PartEntry->DriveLetter == 0) ? '-' : ':',
2800 PartEntry->PartitionType,
2801 PartSize,
2802 PartUnit);
2803 }
2804 else
2805 {
2806 CONSOLE_PrintTextXY(8, 10,
2807 "%c%c %s %I64u %s",
2808 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter,
2809 (PartEntry->DriveLetter == 0) ? '-' : ':',
2810 PartTypeString,
2811 PartSize,
2812 PartUnit);
2813 }
2814
2815 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
2816 DiskEntry->DiskNumber,
2817 DiskSize,
2818 DiskUnit,
2819 DiskEntry->Port,
2820 DiskEntry->Bus,
2821 DiskEntry->Id,
2822 &DiskEntry->DriverName,
2823 DiskEntry->NoMbr ? "GPT" : "MBR");
2824 }
2825
2826 if (FileSystemList == NULL)
2827 {
2828 /* Create the file system list, and by default select the "FAT" file system */
2829 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2830 if (FileSystemList == NULL)
2831 {
2832 /* FIXME: show an error dialog */
2833 return QUIT_PAGE;
2834 }
2835 }
2836
2837 if (RepairUpdateFlag)
2838 {
2839 return CHECK_FILE_SYSTEM_PAGE;
2840 //return SELECT_PARTITION_PAGE;
2841 }
2842
2843 if (IsUnattendedSetup)
2844 {
2845 if (USetupData.FormatPartition)
2846 {
2847 /*
2848 * We use whatever currently selected file system we have
2849 * (by default, this is "FAT", as per the initialization
2850 * performed above). Note that it may be interesting to specify
2851 * which file system to use in unattended installations, in the
2852 * txtsetup.sif file.
2853 */
2854 return FORMAT_PARTITION_PAGE;
2855 }
2856
2857 return CHECK_FILE_SYSTEM_PAGE;
2858 }
2859
2860 DrawFileSystemList(FileSystemList);
2861
2862 while (TRUE)
2863 {
2864 CONSOLE_ConInKey(Ir);
2865
2866 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2867 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2868 {
2869 if (ConfirmQuit(Ir))
2870 return QUIT_PAGE;
2871
2872 break;
2873 }
2874 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2875 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2876 {
2877 FormatState = Start;
2878 return SELECT_PARTITION_PAGE;
2879 }
2880 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2881 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2882 {
2883 ScrollDownFileSystemList(FileSystemList);
2884 }
2885 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2886 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2887 {
2888 ScrollUpFileSystemList(FileSystemList);
2889 }
2890 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2891 {
2892 if (!FileSystemList->Selected->FileSystem)
2893 return SELECT_FILE_SYSTEM_PAGE;
2894 else
2895 return FORMAT_PARTITION_PAGE;
2896 }
2897 }
2898
2899 FormatState = PreviousFormatState;
2900
2901 return SELECT_FILE_SYSTEM_PAGE;
2902 }
2903
2904
2905 /*
2906 * Displays the FormatPartitionPage.
2907 *
2908 * Next pages:
2909 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2910 * SelectPartitionPage (At once)
2911 * QuitPage
2912 *
2913 * SIDEEFFECTS
2914 * Sets PartitionList->CurrentPartition->FormatState
2915 * Sets USetupData.DestinationRootPath
2916 *
2917 * RETURNS
2918 * Number of the next page.
2919 */
2920 static PAGE_NUMBER
2921 FormatPartitionPage(PINPUT_RECORD Ir)
2922 {
2923 NTSTATUS Status;
2924 PDISKENTRY DiskEntry;
2925 PPARTENTRY PartEntry;
2926 PFILE_SYSTEM_ITEM SelectedFileSystem;
2927 UNICODE_STRING PartitionRootPath;
2928 WCHAR PathBuffer[MAX_PATH];
2929 CHAR Buffer[MAX_PATH];
2930
2931 #ifndef NDEBUG
2932 ULONG Line;
2933 ULONG i;
2934 PPARTITION_INFORMATION PartitionInfo;
2935 #endif
2936
2937 DPRINT("FormatPartitionPage()\n");
2938
2939 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2940
2941 if (PartitionList == NULL || TempPartition == NULL)
2942 {
2943 /* FIXME: show an error dialog */
2944 return QUIT_PAGE;
2945 }
2946
2947 PartEntry = TempPartition;
2948 DiskEntry = PartEntry->DiskEntry;
2949
2950 SelectedFileSystem = FileSystemList->Selected;
2951
2952 while (TRUE)
2953 {
2954 if (!IsUnattendedSetup)
2955 {
2956 CONSOLE_ConInKey(Ir);
2957 }
2958
2959 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2960 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2961 {
2962 if (ConfirmQuit(Ir))
2963 return QUIT_PAGE;
2964
2965 break;
2966 }
2967 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
2968 {
2969 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2970
2971 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
2972 {
2973 /* FIXME: show an error dialog */
2974 return QUIT_PAGE;
2975 }
2976
2977 #ifndef NDEBUG
2978 CONSOLE_PrintTextXY(6, 12,
2979 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
2980 DiskEntry->Cylinders,
2981 DiskEntry->TracksPerCylinder,
2982 DiskEntry->SectorsPerTrack,
2983 DiskEntry->BytesPerSector,
2984 DiskEntry->Dirty ? '*' : ' ');
2985
2986 Line = 13;
2987
2988 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
2989 {
2990 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
2991
2992 CONSOLE_PrintTextXY(6, Line,
2993 "%2u: %2lu %c %12I64u %12I64u %02x",
2994 i,
2995 PartitionInfo->PartitionNumber,
2996 PartitionInfo->BootIndicator ? 'A' : '-',
2997 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
2998 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
2999 PartitionInfo->PartitionType);
3000 Line++;
3001 }
3002 #endif
3003
3004 /* Commit the partition changes to the disk */
3005 if (!WritePartitionsToDisk(PartitionList))
3006 {
3007 DPRINT("WritePartitionsToDisk() failed\n");
3008 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
3009 return QUIT_PAGE;
3010 }
3011
3012 /* Set PartitionRootPath */
3013 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3014 L"\\Device\\Harddisk%lu\\Partition%lu",
3015 DiskEntry->DiskNumber,
3016 PartEntry->PartitionNumber);
3017 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3018 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3019
3020 /* Format the partition */
3021 if (SelectedFileSystem->FileSystem)
3022 {
3023 Status = FormatPartition(&PartitionRootPath,
3024 SelectedFileSystem);
3025 if (Status == STATUS_NOT_SUPPORTED)
3026 {
3027 sprintf(Buffer,
3028 "Setup is currently unable to format a partition in %S.\n"
3029 "\n"
3030 " \x07 Press ENTER to continue Setup.\n"
3031 " \x07 Press F3 to quit Setup.",
3032 SelectedFileSystem->FileSystem->FileSystemName);
3033
3034 PopupError(Buffer,
3035 MUIGetString(STRING_QUITCONTINUE),
3036 NULL, POPUP_WAIT_NONE);
3037
3038 while (TRUE)
3039 {
3040 CONSOLE_ConInKey(Ir);
3041
3042 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3043 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3044 {
3045 if (ConfirmQuit(Ir))
3046 return QUIT_PAGE;
3047 else
3048 return SELECT_FILE_SYSTEM_PAGE;
3049 }
3050 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3051 {
3052 return SELECT_FILE_SYSTEM_PAGE;
3053 }
3054 }
3055 }
3056 else if (!NT_SUCCESS(Status))
3057 {
3058 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
3059 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
3060 return QUIT_PAGE;
3061 }
3062
3063 PartEntry->FormatState = Formatted;
3064 // PartEntry->FileSystem = FileSystem;
3065 PartEntry->New = FALSE;
3066 }
3067
3068 #ifndef NDEBUG
3069 CONSOLE_SetStatusText(" Done. Press any key ...");
3070 CONSOLE_ConInKey(Ir);
3071 #endif
3072
3073 return SELECT_FILE_SYSTEM_PAGE;
3074 }
3075 }
3076
3077 return FORMAT_PARTITION_PAGE;
3078 }
3079
3080
3081 /*
3082 * Displays the CheckFileSystemPage.
3083 *
3084 * Next pages:
3085 * InstallDirectoryPage (At once)
3086 * QuitPage
3087 *
3088 * SIDEEFFECTS
3089 * Inits or reloads FileSystemList
3090 *
3091 * RETURNS
3092 * Number of the next page.
3093 */
3094 static PAGE_NUMBER
3095 CheckFileSystemPage(PINPUT_RECORD Ir)
3096 {
3097 NTSTATUS Status;
3098 PDISKENTRY DiskEntry;
3099 PPARTENTRY PartEntry;
3100 PFILE_SYSTEM CurrentFileSystem;
3101 UNICODE_STRING PartitionRootPath;
3102 WCHAR PathBuffer[MAX_PATH];
3103 CHAR Buffer[MAX_PATH];
3104
3105 if (PartitionList == NULL)
3106 {
3107 /* FIXME: show an error dialog */
3108 return QUIT_PAGE;
3109 }
3110
3111 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3112 {
3113 return INSTALL_DIRECTORY_PAGE;
3114 }
3115
3116 /* Set PartitionRootPath */
3117 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3118 L"\\Device\\Harddisk%lu\\Partition%lu",
3119 DiskEntry->DiskNumber,
3120 PartEntry->PartitionNumber);
3121 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3122 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3123
3124 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3125
3126 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3127
3128 CurrentFileSystem = PartEntry->FileSystem;
3129 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3130 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3131
3132 /* HACK: Do not try to check a partition with an unknown filesystem */
3133 if (CurrentFileSystem == NULL)
3134 {
3135 PartEntry->NeedsCheck = FALSE;
3136 return CHECK_FILE_SYSTEM_PAGE;
3137 }
3138
3139 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3140 if (Status == STATUS_NOT_SUPPORTED)
3141 {
3142 sprintf(Buffer,
3143 "Setup is currently unable to check a partition formatted in %S.\n"
3144 "\n"
3145 " \x07 Press ENTER to continue Setup.\n"
3146 " \x07 Press F3 to quit Setup.",
3147 CurrentFileSystem->FileSystemName);
3148
3149 PopupError(Buffer,
3150 MUIGetString(STRING_QUITCONTINUE),
3151 NULL, POPUP_WAIT_NONE);
3152
3153 while (TRUE)
3154 {
3155 CONSOLE_ConInKey(Ir);
3156
3157 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3158 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3159 {
3160 if (ConfirmQuit(Ir))
3161 return QUIT_PAGE;
3162 else
3163 return CHECK_FILE_SYSTEM_PAGE;
3164 }
3165 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3166 {
3167 PartEntry->NeedsCheck = FALSE;
3168 return CHECK_FILE_SYSTEM_PAGE;
3169 }
3170 }
3171 }
3172 else if (!NT_SUCCESS(Status))
3173 {
3174 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3175 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3176 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3177 "(Status 0x%08lx).\n", Status);
3178 PopupError(Buffer,
3179 // MUIGetString(STRING_REBOOTCOMPUTER),
3180 MUIGetString(STRING_CONTINUE),
3181 Ir, POPUP_WAIT_ENTER);
3182
3183 // return QUIT_PAGE;
3184 }
3185
3186 PartEntry->NeedsCheck = FALSE;
3187 return CHECK_FILE_SYSTEM_PAGE;
3188 }
3189
3190
3191 static VOID
3192 BuildInstallPaths(PWSTR InstallDir,
3193 PDISKENTRY DiskEntry,
3194 PPARTENTRY PartEntry)
3195 {
3196 NTSTATUS Status;
3197
3198 Status = InitDestinationPaths(&USetupData, InstallDir, DiskEntry, PartEntry);
3199 // TODO: Check Status
3200 UNREFERENCED_PARAMETER(Status);
3201
3202 /* Initialize DestinationDriveLetter */
3203 DestinationDriveLetter = PartEntry->DriveLetter;
3204 }
3205
3206
3207 static BOOLEAN
3208 IsValidPath(
3209 IN PCWSTR InstallDir)
3210 {
3211 UINT i, Length;
3212
3213 Length = wcslen(InstallDir);
3214
3215 // TODO: Add check for 8.3 too.
3216
3217 /* Path must be at least 2 characters long */
3218 // if (Length < 2)
3219 // return FALSE;
3220
3221 /* Path must start with a backslash */
3222 // if (InstallDir[0] != L'\\')
3223 // return FALSE;
3224
3225 /* Path must not end with a backslash */
3226 if (InstallDir[Length - 1] == L'\\')
3227 return FALSE;
3228
3229 /* Path must not contain whitespace characters */
3230 for (i = 0; i < Length; i++)
3231 {
3232 if (iswspace(InstallDir[i]))
3233 return FALSE;
3234 }
3235
3236 /* Path component must not end with a dot */
3237 for (i = 0; i < Length; i++)
3238 {
3239 if (InstallDir[i] == L'\\' && i > 0)
3240 {
3241 if (InstallDir[i - 1] == L'.')
3242 return FALSE;
3243 }
3244 }
3245
3246 if (InstallDir[Length - 1] == L'.')
3247 return FALSE;
3248
3249 return TRUE;
3250 }
3251
3252
3253 /*
3254 * Displays the InstallDirectoryPage.
3255 *
3256 * Next pages:
3257 * PrepareCopyPage
3258 * QuitPage
3259 *
3260 * RETURNS
3261 * Number of the next page.
3262 */
3263 static PAGE_NUMBER
3264 InstallDirectoryPage(PINPUT_RECORD Ir)
3265 {
3266 PDISKENTRY DiskEntry;
3267 PPARTENTRY PartEntry;
3268 WCHAR InstallDir[MAX_PATH];
3269 WCHAR c;
3270 ULONG Length, Pos;
3271
3272 /* We do not need the filesystem list anymore */
3273 if (FileSystemList != NULL)
3274 {
3275 DestroyFileSystemList(FileSystemList);
3276 FileSystemList = NULL;
3277 }
3278
3279 if (PartitionList == NULL ||
3280 PartitionList->CurrentDisk == NULL ||
3281 PartitionList->CurrentPartition == NULL)
3282 {
3283 /* FIXME: show an error dialog */
3284 return QUIT_PAGE;
3285 }
3286
3287 DiskEntry = PartitionList->CurrentDisk;
3288 PartEntry = PartitionList->CurrentPartition;
3289
3290 // if (IsUnattendedSetup)
3291 if (RepairUpdateFlag)
3292 wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
3293 else if (USetupData.InstallationDirectory[0])
3294 wcscpy(InstallDir, USetupData.InstallationDirectory);
3295 else
3296 wcscpy(InstallDir, L"\\ReactOS");
3297
3298 /*
3299 * Check the validity of the predefined 'InstallDir'. If we are either
3300 * in unattended setup or in update/repair mode, and the installation path
3301 * is valid, just perform the installation. Otherwise (either in the case
3302 * of an invalid path, or we are in regular setup), display the UI and allow
3303 * the user to specify a new installation path.
3304 */
3305 if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
3306 {
3307 BuildInstallPaths(InstallDir,
3308 DiskEntry,
3309 PartEntry);
3310
3311 /*
3312 * Check whether the user attempts to install ReactOS within the
3313 * installation source directory, or in a subdirectory thereof.
3314 * If so, fail with an error.
3315 */
3316 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3317 {
3318 PopupError("You cannot install ReactOS within the installation source directory!",
3319 MUIGetString(STRING_CONTINUE),
3320 Ir, POPUP_WAIT_ENTER);
3321 return INSTALL_DIRECTORY_PAGE;
3322 }
3323
3324 return PREPARE_COPY_PAGE;
3325 }
3326
3327 Length = wcslen(InstallDir);
3328 Pos = Length;
3329
3330 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3331 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3332 CONSOLE_SetCursorXY(8 + Pos, 11);
3333 CONSOLE_SetCursorType(TRUE, TRUE);
3334
3335 while (TRUE)
3336 {
3337 CONSOLE_ConInKey(Ir);
3338
3339 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3340 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3341 {
3342 CONSOLE_SetCursorType(TRUE, FALSE);
3343
3344 if (ConfirmQuit(Ir))
3345 return QUIT_PAGE;
3346
3347 CONSOLE_SetCursorType(TRUE, TRUE);
3348 break;
3349 }
3350 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3351 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3352 {
3353 if (Pos < Length)
3354 {
3355 memmove(&InstallDir[Pos],
3356 &InstallDir[Pos + 1],
3357 (Length - Pos - 1) * sizeof(WCHAR));
3358 InstallDir[Length - 1] = UNICODE_NULL;
3359
3360 Length--;
3361 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3362 CONSOLE_SetCursorXY(8 + Pos, 11);
3363 }
3364 }
3365 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3366 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3367 {
3368 Pos = 0;
3369 CONSOLE_SetCursorXY(8 + Pos, 11);
3370 }
3371 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3372 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3373 {
3374 Pos = Length;
3375 CONSOLE_SetCursorXY(8 + Pos, 11);
3376 }
3377 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3378 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3379 {
3380 if (Pos > 0)
3381 {
3382 Pos--;
3383 CONSOLE_SetCursorXY(8 + Pos, 11);
3384 }
3385 }
3386 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3387 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3388 {
3389 if (Pos < Length)
3390 {
3391 Pos++;
3392 CONSOLE_SetCursorXY(8 + Pos, 11);
3393 }
3394 }
3395 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3396 {
3397 CONSOLE_SetCursorType(TRUE, FALSE);
3398
3399 /*
3400 * Check for the validity of the installation directory and pop up
3401 * an error if it is not the case. Then the user can fix its input.
3402 */
3403 if (!IsValidPath(InstallDir))
3404 {
3405 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3406 return INSTALL_DIRECTORY_PAGE;
3407 }
3408
3409 BuildInstallPaths(InstallDir,
3410 DiskEntry,
3411 PartEntry);
3412
3413 /*
3414 * Check whether the user attempts to install ReactOS within the
3415 * installation source directory, or in a subdirectory thereof.
3416 * If so, fail with an error.
3417 */
3418 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE))
3419 {
3420 PopupError("You cannot install ReactOS within the installation source directory!",
3421 MUIGetString(STRING_CONTINUE),
3422 Ir, POPUP_WAIT_ENTER);
3423 return INSTALL_DIRECTORY_PAGE;
3424 }
3425
3426 return PREPARE_COPY_PAGE;
3427 }
3428 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3429 {
3430 if (Pos > 0)
3431 {
3432 if (Pos < Length)
3433 memmove(&InstallDir[Pos - 1],
3434 &InstallDir[Pos],
3435 (Length - Pos) * sizeof(WCHAR));
3436 InstallDir[Length - 1] = UNICODE_NULL;
3437
3438 Pos--;
3439 Length--;
3440 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3441 CONSOLE_SetCursorXY(8 + Pos, 11);
3442 }
3443 }
3444 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3445 {
3446 if (Length < 50)
3447 {
3448 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
3449 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3450 {
3451 if (Pos < Length)
3452 memmove(&InstallDir[Pos + 1],
3453 &InstallDir[Pos],
3454 (Length - Pos) * sizeof(WCHAR));
3455 InstallDir[Length + 1] = UNICODE_NULL;
3456 InstallDir[Pos] = c;
3457
3458 Pos++;
3459 Length++;
3460 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3461 CONSOLE_SetCursorXY(8 + Pos, 11);
3462 }
3463 }
3464 }
3465 }
3466
3467 return INSTALL_DIRECTORY_PAGE;
3468 }
3469
3470
3471 // PSETUP_ERROR_ROUTINE
3472 static VOID
3473 __cdecl
3474 USetupErrorRoutine(
3475 IN PUSETUP_DATA pSetupData,
3476 ...)
3477 {
3478 INPUT_RECORD Ir;
3479 va_list arg_ptr;
3480
3481 va_start(arg_ptr, pSetupData);
3482
3483 if (pSetupData->LastErrorNumber >= ERROR_SUCCESS &&
3484 pSetupData->LastErrorNumber < ERROR_LAST_ERROR_CODE)
3485 {
3486 // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
3487 MUIDisplayErrorV(pSetupData->LastErrorNumber, &Ir, POPUP_WAIT_ENTER, arg_ptr);
3488 }
3489
3490 va_end(arg_ptr);
3491 }
3492
3493 /*
3494 * Displays the PrepareCopyPage.
3495 *
3496 * Next pages:
3497 * FileCopyPage(At once)
3498 * QuitPage
3499 *
3500 * SIDEEFFECTS
3501 * Calls PrepareFileCopy
3502 *
3503 * RETURNS
3504 * Number of the next page.
3505 */
3506 static PAGE_NUMBER
3507 PrepareCopyPage(PINPUT_RECORD Ir)
3508 {
3509 // ERROR_NUMBER ErrorNumber;
3510 BOOLEAN Success;
3511
3512 MUIDisplayPage(PREPARE_COPY_PAGE);
3513
3514 /* ErrorNumber = */ Success = PrepareFileCopy(&USetupData, NULL);
3515 if (/*ErrorNumber != ERROR_SUCCESS*/ !Success)
3516 {
3517 // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER);
3518 return QUIT_PAGE;
3519 }
3520
3521 return FILE_COPY_PAGE;
3522 }
3523
3524 typedef struct _COPYCONTEXT
3525 {
3526 ULONG TotalOperations;
3527 ULONG CompletedOperations;
3528 PPROGRESSBAR ProgressBar;
3529 PPROGRESSBAR MemoryBars[4];
3530 } COPYCONTEXT, *PCOPYCONTEXT;
3531
3532 static VOID
3533 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3534 IN BOOLEAN First)
3535 {
3536 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3537
3538 /* Get the memory information from the system */
3539 NtQuerySystemInformation(SystemPerformanceInformation,
3540 &PerfInfo,
3541 sizeof(PerfInfo),
3542 NULL);
3543
3544 /* Check if this is initial setup */
3545 if (First)
3546 {
3547 /* Set maximum limits to be total RAM pages */
3548 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
3549 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
3550 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
3551 }
3552
3553 /* Set current values */
3554 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
3555 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
3556 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
3557 }
3558
3559 static UINT
3560 CALLBACK
3561 FileCopyCallback(PVOID Context,
3562 UINT Notification,
3563 UINT_PTR Param1,
3564 UINT_PTR Param2)
3565 {
3566 PCOPYCONTEXT CopyContext = (PCOPYCONTEXT)Context;
3567 PFILEPATHS_W FilePathInfo;
3568 PCWSTR SrcFileName, DstFileName;
3569
3570 switch (Notification)
3571 {
3572 case SPFILENOTIFY_STARTSUBQUEUE:
3573 {
3574 CopyContext->TotalOperations = (ULONG)Param2;
3575 CopyContext->CompletedOperations = 0;
3576 ProgressSetStepCount(CopyContext->ProgressBar,
3577 CopyContext->TotalOperations);
3578 SetupUpdateMemoryInfo(CopyContext, TRUE);
3579 break;
3580 }
3581
3582 case SPFILENOTIFY_STARTDELETE:
3583 case SPFILENOTIFY_STARTRENAME:
3584 case SPFILENOTIFY_STARTCOPY:
3585 {
3586 FilePathInfo = (PFILEPATHS_W)Param1;
3587
3588 if (Notification == SPFILENOTIFY_STARTDELETE)
3589 {
3590 /* Display delete message */
3591 ASSERT(Param2 == FILEOP_DELETE);
3592
3593 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3594 if (DstFileName) ++DstFileName;
3595 else DstFileName = FilePathInfo->Target;
3596
3597 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING),
3598 DstFileName);
3599 }
3600 else if (Notification == SPFILENOTIFY_STARTRENAME)
3601 {
3602 /* Display move/rename message */
3603 ASSERT(Param2 == FILEOP_RENAME);
3604
3605 SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
3606 if (SrcFileName) ++SrcFileName;
3607 else SrcFileName = FilePathInfo->Source;
3608
3609 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3610 if (DstFileName) ++DstFileName;
3611 else DstFileName = FilePathInfo->Target;
3612
3613 if (!wcsicmp(SrcFileName, DstFileName))
3614 Param2 = STRING_MOVING;
3615 else
3616 Param2 = STRING_RENAMING;
3617
3618 CONSOLE_SetStatusText(MUIGetString(Param2),
3619 SrcFileName, DstFileName);
3620 }
3621 else if (Notification == SPFILENOTIFY_STARTCOPY)
3622 {
3623 /* Display copy message */
3624 ASSERT(Param2 == FILEOP_COPY);
3625
3626 /* NOTE: When extracting from CABs the Source is the CAB name */
3627 DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
3628 if (DstFileName) ++DstFileName;
3629 else DstFileName = FilePathInfo->Target;
3630
3631 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING),
3632 DstFileName);
3633 }
3634
3635 SetupUpdateMemoryInfo(CopyContext, FALSE);
3636 break;
3637 }
3638
3639 case SPFILENOTIFY_COPYERROR:
3640 {
3641 FilePathInfo = (PFILEPATHS_W)Param1;
3642
3643 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
3644 FilePathInfo->Target, FilePathInfo->Win32Error);
3645 return FILEOP_SKIP;
3646 }
3647
3648 case SPFILENOTIFY_ENDDELETE:
3649 case SPFILENOTIFY_ENDRENAME:
3650 case SPFILENOTIFY_ENDCOPY:
3651 {
3652 CopyContext->CompletedOperations++;
3653
3654 /* SYSREG checkpoint */
3655 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations)
3656 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3657
3658 ProgressNextStep(CopyContext->ProgressBar);
3659 SetupUpdateMemoryInfo(CopyContext, FALSE);
3660 break;
3661 }
3662 }
3663
3664 return FILEOP_DOIT;
3665 }
3666
3667
3668 /*
3669 * Displays the FileCopyPage.
3670 *
3671 * Next pages:
3672 * RegistryPage(At once)
3673 *
3674 * SIDEEFFECTS
3675 * Calls DoFileCopy
3676 *
3677 * RETURNS
3678 * Number of the next page.
3679 */
3680 static PAGE_NUMBER
3681 FileCopyPage(PINPUT_RECORD Ir)
3682 {
3683 COPYCONTEXT CopyContext;
3684 UINT MemBarWidth;
3685
3686 MUIDisplayPage(FILE_COPY_PAGE);
3687
3688 /* Create context for the copy process */
3689 CopyContext.TotalOperations = 0;
3690 CopyContext.CompletedOperations = 0;
3691
3692 /* Create the progress bar as well */
3693 CopyContext.ProgressBar = CreateProgressBar(13,
3694 26,
3695 xScreen - 13,
3696 yScreen - 20,
3697 10,
3698 24,
3699 TRUE,
3700 MUIGetString(STRING_SETUPCOPYINGFILES));
3701
3702 // fit memory bars to screen width, distribute them uniform
3703 MemBarWidth = (xScreen - 26) / 5;
3704 MemBarWidth -= MemBarWidth % 2; // make even
3705 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3706 /* Create the paged pool progress bar */
3707 CopyContext.MemoryBars[0] = CreateProgressBar(13,
3708 40,
3709 13 + MemBarWidth,
3710 43,
3711 13,
3712 44,
3713 FALSE,
3714 "Kernel Pool");
3715
3716 /* Create the non paged pool progress bar */
3717 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (MemBarWidth / 2),
3718 40,
3719 (xScreen / 2) + (MemBarWidth / 2),
3720 43,
3721 (xScreen / 2)- (MemBarWidth / 2),
3722 44,
3723 FALSE,
3724 "Kernel Cache");
3725
3726 /* Create the global memory progress bar */
3727 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - MemBarWidth,
3728 40,
3729 xScreen - 13,
3730 43,
3731 xScreen - 13 - MemBarWidth,
3732 44,
3733 FALSE,
3734 "Free Memory");
3735
3736 /* Do the file copying */
3737 DoFileCopy(&USetupData, FileCopyCallback, &CopyContext);
3738
3739 /* If we get here, we're done, so cleanup the progress bar */
3740 DestroyProgressBar(CopyContext.ProgressBar);
3741 DestroyProgressBar(CopyContext.MemoryBars[0]);
3742 DestroyProgressBar(CopyContext.MemoryBars[1]);
3743 DestroyProgressBar(CopyContext.MemoryBars[2]);
3744
3745 /* Create the $winnt$.inf file */
3746 InstallSetupInfFile(&USetupData);
3747
3748 /* Go display the next page */
3749 return REGISTRY_PAGE;
3750 }
3751
3752
3753 static VOID
3754 __cdecl
3755 RegistryStatus(IN REGISTRY_STATUS RegStatus, ...)
3756 {
3757 /* WARNING: Please keep this lookup table in sync with the resources! */
3758 static const UINT StringIDs[] =
3759 {
3760 STRING_DONE, /* Success */
3761 STRING_REGHIVEUPDATE, /* RegHiveUpdate */
3762 STRING_IMPORTFILE, /* ImportRegHive */
3763 STRING_DISPLAYSETTINGSUPDATE, /* DisplaySettingsUpdate */
3764 STRING_LOCALESETTINGSUPDATE, /* LocaleSettingsUpdate */
3765 STRING_ADDKBLAYOUTS, /* KeybLayouts */
3766 STRING_KEYBOARDSETTINGSUPDATE, /* KeybSettingsUpdate */
3767 STRING_CODEPAGEINFOUPDATE, /* CodePageInfoUpdate */
3768 };
3769
3770 va_list args;
3771
3772 if (RegStatus < ARRAYSIZE(StringIDs))
3773 {
3774 va_start(args, RegStatus);
3775 CONSOLE_SetStatusTextV(MUIGetString(StringIDs[RegStatus]), args);
3776 va_end(args);
3777 }
3778 else
3779 {
3780 CONSOLE_SetStatusText("Unknown status %d", RegStatus);
3781 }
3782 }
3783
3784 /*
3785 * Displays the RegistryPage.
3786 *
3787 * Next pages:
3788 * SuccessPage (if RepairUpdate)
3789 * BootLoaderPage (default)
3790 * QuitPage
3791 *
3792 * SIDEEFFECTS
3793 * Calls UpdateRegistry
3794 *
3795 * RETURNS
3796 * Number of the next page.
3797 */
3798 static PAGE_NUMBER
3799 RegistryPage(PINPUT_RECORD Ir)
3800 {
3801 ULONG Error;
3802
3803 MUIDisplayPage(REGISTRY_PAGE);
3804
3805 Error = UpdateRegistry(&USetupData,
3806 RepairUpdateFlag,
3807 PartitionList,
3808 DestinationDriveLetter,
3809 SelectedLanguageId,
3810 RegistryStatus);
3811 if (Error != ERROR_SUCCESS)
3812 {
3813 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER);
3814 return QUIT_PAGE;
3815 }
3816 else
3817 {
3818 CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
3819 return BOOT_LOADER_PAGE;
3820 }
3821 }
3822
3823
3824 /*
3825 * Displays the BootLoaderPage.
3826 *
3827 * Next pages:
3828 * SuccessPage (if RepairUpdate)
3829 * BootLoaderHarddiskMbrPage
3830 * BootLoaderHarddiskVbrPage
3831 * BootLoaderFloppyPage
3832 * SuccessPage
3833 * QuitPage
3834 *
3835 * SIDEEFFECTS
3836 * Calls RegInitializeRegistry
3837 * Calls ImportRegistryFile
3838 * Calls SetDefaultPagefile
3839 * Calls SetMountedDeviceValues
3840 *
3841 * RETURNS
3842 * Number of the next page.
3843 */
3844 static PAGE_NUMBER
3845 BootLoaderPage(PINPUT_RECORD Ir)
3846 {
3847 UCHAR PartitionType;
3848 BOOLEAN InstallOnFloppy;
3849 USHORT Line = 12;
3850 WCHAR PathBuffer[MAX_PATH];
3851
3852 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3853
3854 RtlFreeUnicodeString(&USetupData.SystemRootPath);
3855 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3856 L"\\Device\\Harddisk%lu\\Partition%lu\\",
3857 PartitionList->SystemPartition->DiskEntry->DiskNumber,
3858 PartitionList->SystemPartition->PartitionNumber);
3859 RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer);
3860 DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath);
3861
3862 PartitionType = PartitionList->SystemPartition->PartitionType;
3863
3864 /* For unattended setup, skip MBR installation or install on floppy if needed */
3865 if (IsUnattendedSetup)
3866 {
3867 if ((USetupData.MBRInstallType == 0) ||
3868 (USetupData.MBRInstallType == 1))
3869 {
3870 goto Quit;
3871 }
3872 }
3873
3874 /*
3875 * We may install an MBR or VBR, but before that, check whether
3876 * we need to actually install the VBR on floppy.
3877 */
3878 if (PartitionType == PARTITION_ENTRY_UNUSED)
3879 {
3880 DPRINT("Error: system partition invalid (unused)\n");
3881 InstallOnFloppy = TRUE;
3882 }
3883 else if (PartitionType == PARTITION_OS2BOOTMGR)
3884 {
3885 /* OS/2 boot manager partition */
3886 DPRINT("Found OS/2 boot manager partition\n");
3887 InstallOnFloppy = TRUE;
3888 }
3889 else if (PartitionType == PARTITION_LINUX)
3890 {
3891 /* Linux partition */
3892 DPRINT("Found Linux native partition (ext2/ext3/ReiserFS/BTRFS/etc)\n");
3893 InstallOnFloppy = FALSE;
3894 }
3895 else if (PartitionType == PARTITION_IFS)
3896 {
3897 /* NTFS partition */
3898 DPRINT("Found NTFS partition\n");
3899
3900 // FIXME: Make it FALSE when we'll support NTFS installation!
3901 InstallOnFloppy = TRUE;
3902 }
3903 else if ((PartitionType == PARTITION_FAT_12) ||
3904 (PartitionType == PARTITION_FAT_16) ||
3905 (PartitionType == PARTITION_HUGE) ||
3906 (PartitionType == PARTITION_XINT13) ||
3907 (PartitionType == PARTITION_FAT32) ||
3908 (PartitionType == PARTITION_FAT32_XINT13))
3909 {
3910 DPRINT("Found FAT partition\n");
3911 InstallOnFloppy = FALSE;
3912 }
3913 else
3914 {
3915 /* Unknown partition */
3916 DPRINT("Unknown partition found\n");
3917 InstallOnFloppy = TRUE;
3918 }
3919
3920 /* We should install on floppy */
3921 if (InstallOnFloppy)
3922 {
3923 USetupData.MBRInstallType = 1;
3924 goto Quit;
3925 }
3926
3927 /* Is it an unattended install on hdd? */
3928 if (IsUnattendedSetup)
3929 {
3930 if ((USetupData.MBRInstallType == 2) ||
3931 (USetupData.MBRInstallType == 3))
3932 {
3933 goto Quit;
3934 }
3935 }
3936
3937 MUIDisplayPage(BOOT_LOADER_PAGE);
3938 CONSOLE_InvertTextXY(8, Line, 60, 1);
3939
3940 while (TRUE)
3941 {
3942 CONSOLE_ConInKey(Ir);
3943
3944 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3945 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
3946 {
3947 CONSOLE_NormalTextXY(8, Line, 60, 1);
3948
3949 Line++;
3950 if (Line < 12)
3951 Line = 15;
3952
3953 if (Line > 15)
3954 Line = 12;
3955
3956 CONSOLE_InvertTextXY(8, Line, 60, 1);
3957 }
3958 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3959 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
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_F3)) /* F3 */
3974 {
3975 if (ConfirmQuit(Ir))
3976 return QUIT_PAGE;
3977
3978 break;
3979 }
3980 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3981 {
3982 if (Line == 12)
3983 {
3984 /* Install on both MBR and VBR */
3985 USetupData.MBRInstallType =