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