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