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