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