[USETUP][SETUPLIB] Code refactoring.
[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 if (PartitionList->CurrentPartition->IsPartitioned == FALSE)
1666 {
1667 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY);
1668 return SELECT_PARTITION_PAGE;
1669 }
1670
1671 if (PartitionList->CurrentPartition->BootIndicator ||
1672 PartitionList->CurrentPartition == PartitionList->SystemPartition)
1673 {
1674 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
1675 }
1676
1677 return DELETE_PARTITION_PAGE;
1678 }
1679 }
1680
1681 return SELECT_PARTITION_PAGE;
1682 }
1683
1684
1685 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9
1686 /* Restriction for MaxSize: pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1 */
1687 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1)
1688
1689 static VOID
1690 ShowPartitionSizeInputBox(SHORT Left,
1691 SHORT Top,
1692 SHORT Right,
1693 SHORT Bottom,
1694 ULONG MaxSize,
1695 PWSTR InputBuffer,
1696 PBOOLEAN Quit,
1697 PBOOLEAN Cancel)
1698 {
1699 INPUT_RECORD Ir;
1700 COORD coPos;
1701 DWORD Written;
1702 CHAR Buffer[128];
1703 INT Length, Pos;
1704 WCHAR ch;
1705 SHORT iLeft;
1706 SHORT iTop;
1707
1708 if (Quit != NULL)
1709 *Quit = FALSE;
1710
1711 if (Cancel != NULL)
1712 *Cancel = FALSE;
1713
1714 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1);
1715
1716 /* Print message */
1717 coPos.X = Left + 2;
1718 coPos.Y = Top + 2;
1719 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE));
1720 iLeft = coPos.X + strlen(Buffer) + 1;
1721 iTop = coPos.Y;
1722
1723 WriteConsoleOutputCharacterA(StdOutput,
1724 Buffer,
1725 strlen(Buffer),
1726 coPos,
1727 &Written);
1728
1729 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize);
1730 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1;
1731 coPos.Y = iTop;
1732 WriteConsoleOutputCharacterA(StdOutput,
1733 Buffer,
1734 strlen(Buffer),
1735 coPos,
1736 &Written);
1737
1738 swprintf(InputBuffer, L"%lu", MaxSize);
1739 Length = wcslen(InputBuffer);
1740 Pos = Length;
1741 CONSOLE_SetInputTextXY(iLeft,
1742 iTop,
1743 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1744 InputBuffer);
1745 CONSOLE_SetCursorXY(iLeft + Length, iTop);
1746 CONSOLE_SetCursorType(TRUE, TRUE);
1747
1748 while (TRUE)
1749 {
1750 CONSOLE_ConInKey(&Ir);
1751
1752 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1753 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
1754 {
1755 if (Quit != NULL)
1756 *Quit = TRUE;
1757
1758 InputBuffer[0] = UNICODE_NULL;
1759 CONSOLE_SetCursorType(TRUE, FALSE);
1760 break;
1761 }
1762 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
1763 {
1764 CONSOLE_SetCursorType(TRUE, FALSE);
1765 break;
1766 }
1767 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */
1768 {
1769 if (Cancel != NULL)
1770 *Cancel = TRUE;
1771
1772 InputBuffer[0] = UNICODE_NULL;
1773 CONSOLE_SetCursorType(TRUE, FALSE);
1774 break;
1775 }
1776 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1777 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
1778 {
1779 Pos = 0;
1780 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1781 }
1782 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1783 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
1784 {
1785 Pos = Length;
1786 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1787 }
1788 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1789 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
1790 {
1791 if (Pos > 0)
1792 {
1793 Pos--;
1794 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1795 }
1796 }
1797 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1798 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
1799 {
1800 if (Pos < Length)
1801 {
1802 Pos++;
1803 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1804 }
1805 }
1806 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) &&
1807 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
1808 {
1809 if (Pos < Length)
1810 {
1811 memmove(&InputBuffer[Pos],
1812 &InputBuffer[Pos + 1],
1813 (Length - Pos - 1) * sizeof(WCHAR));
1814 InputBuffer[Length - 1] = UNICODE_NULL;
1815
1816 Length--;
1817 CONSOLE_SetInputTextXY(iLeft,
1818 iTop,
1819 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1820 InputBuffer);
1821 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1822 }
1823 }
1824 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */
1825 {
1826 if (Pos > 0)
1827 {
1828 if (Pos < Length)
1829 memmove(&InputBuffer[Pos - 1],
1830 &InputBuffer[Pos],
1831 (Length - Pos) * sizeof(WCHAR));
1832 InputBuffer[Length - 1] = UNICODE_NULL;
1833
1834 Pos--;
1835 Length--;
1836 CONSOLE_SetInputTextXY(iLeft,
1837 iTop,
1838 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1839 InputBuffer);
1840 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1841 }
1842 }
1843 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00)
1844 {
1845 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)
1846 {
1847 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar;
1848
1849 if ((ch >= L'0') && (ch <= L'9'))
1850 {
1851 if (Pos < Length)
1852 memmove(&InputBuffer[Pos + 1],
1853 &InputBuffer[Pos],
1854 (Length - Pos) * sizeof(WCHAR));
1855 InputBuffer[Length + 1] = UNICODE_NULL;
1856 InputBuffer[Pos] = ch;
1857
1858 Pos++;
1859 Length++;
1860 CONSOLE_SetInputTextXY(iLeft,
1861 iTop,
1862 PARTITION_SIZE_INPUT_FIELD_LENGTH,
1863 InputBuffer);
1864 CONSOLE_SetCursorXY(iLeft + Pos, iTop);
1865 }
1866 }
1867 }
1868 }
1869 }
1870
1871
1872 /*
1873 * Displays the CreatePrimaryPartitionPage.
1874 *
1875 * Next pages:
1876 * SelectPartitionPage
1877 * SelectFileSystemPage (default)
1878 * QuitPage
1879 *
1880 * RETURNS
1881 * Number of the next page.
1882 */
1883 static PAGE_NUMBER
1884 CreatePrimaryPartitionPage(PINPUT_RECORD Ir)
1885 {
1886 PDISKENTRY DiskEntry;
1887 PPARTENTRY PartEntry;
1888 BOOLEAN Quit;
1889 BOOLEAN Cancel;
1890 WCHAR InputBuffer[50];
1891 ULONG MaxSize;
1892 ULONGLONG PartSize;
1893 ULONGLONG DiskSize;
1894 ULONGLONG SectorCount;
1895 PCHAR Unit;
1896
1897 if (PartitionList == NULL ||
1898 PartitionList->CurrentDisk == NULL ||
1899 PartitionList->CurrentPartition == NULL)
1900 {
1901 /* FIXME: show an error dialog */
1902 return QUIT_PAGE;
1903 }
1904
1905 DiskEntry = PartitionList->CurrentDisk;
1906 PartEntry = PartitionList->CurrentPartition;
1907
1908 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
1909
1910 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION));
1911
1912 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
1913 #if 0
1914 if (DiskSize >= 10 * GB) /* 10 GB */
1915 {
1916 DiskSize = DiskSize / GB;
1917 Unit = MUIGetString(STRING_GB);
1918 }
1919 else
1920 #endif
1921 {
1922 DiskSize = DiskSize / MB;
1923 if (DiskSize == 0)
1924 DiskSize = 1;
1925
1926 Unit = MUIGetString(STRING_MB);
1927 }
1928
1929 if (DiskEntry->DriverName.Length > 0)
1930 {
1931 CONSOLE_PrintTextXY(6, 10,
1932 MUIGetString(STRING_HDINFOPARTCREATE_1),
1933 DiskSize,
1934 Unit,
1935 DiskEntry->DiskNumber,
1936 DiskEntry->Port,
1937 DiskEntry->Bus,
1938 DiskEntry->Id,
1939 &DiskEntry->DriverName,
1940 DiskEntry->NoMbr ? "GPT" : "MBR");
1941 }
1942 else
1943 {
1944 CONSOLE_PrintTextXY(6, 10,
1945 MUIGetString(STRING_HDINFOPARTCREATE_2),
1946 DiskSize,
1947 Unit,
1948 DiskEntry->DiskNumber,
1949 DiskEntry->Port,
1950 DiskEntry->Bus,
1951 DiskEntry->Id,
1952 DiskEntry->NoMbr ? "GPT" : "MBR");
1953 }
1954
1955 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
1956
1957 #if 0
1958 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
1959 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
1960 #endif
1961
1962 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
1963
1964 PartEntry = PartitionList->CurrentPartition;
1965 while (TRUE)
1966 {
1967 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
1968
1969 if (MaxSize > PARTITION_MAXSIZE)
1970 MaxSize = PARTITION_MAXSIZE;
1971
1972 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
1973 MaxSize, InputBuffer, &Quit, &Cancel);
1974
1975 if (Quit)
1976 {
1977 if (ConfirmQuit(Ir))
1978 return QUIT_PAGE;
1979
1980 break;
1981 }
1982 else if (Cancel)
1983 {
1984 return SELECT_PARTITION_PAGE;
1985 }
1986 else
1987 {
1988 PartSize = _wcstoui64(InputBuffer, NULL, 10);
1989
1990 if (PartSize < 1)
1991 {
1992 /* Too small */
1993 continue;
1994 }
1995
1996 if (PartSize > MaxSize)
1997 {
1998 /* Too large */
1999 continue;
2000 }
2001
2002 /* Convert to bytes */
2003 if (PartSize == MaxSize)
2004 {
2005 /* Use all of the unpartitioned disk space */
2006 SectorCount = PartEntry->SectorCount.QuadPart;
2007 }
2008 else
2009 {
2010 /* Calculate the sector count from the size in MB */
2011 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2012
2013 /* But never get larger than the unpartitioned disk space */
2014 if (SectorCount > PartEntry->SectorCount.QuadPart)
2015 SectorCount = PartEntry->SectorCount.QuadPart;
2016 }
2017
2018 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2019
2020 CreatePrimaryPartition(PartitionList,
2021 SectorCount,
2022 FALSE);
2023
2024 return SELECT_PARTITION_PAGE;
2025 }
2026 }
2027
2028 return CREATE_PRIMARY_PARTITION_PAGE;
2029 }
2030
2031
2032 /*
2033 * Displays the CreateExtendedPartitionPage.
2034 *
2035 * Next pages:
2036 * SelectPartitionPage (default)
2037 * QuitPage
2038 *
2039 * RETURNS
2040 * Number of the next page.
2041 */
2042 static PAGE_NUMBER
2043 CreateExtendedPartitionPage(PINPUT_RECORD Ir)
2044 {
2045 PDISKENTRY DiskEntry;
2046 PPARTENTRY PartEntry;
2047 BOOLEAN Quit;
2048 BOOLEAN Cancel;
2049 WCHAR InputBuffer[50];
2050 ULONG MaxSize;
2051 ULONGLONG PartSize;
2052 ULONGLONG DiskSize;
2053 ULONGLONG SectorCount;
2054 PCHAR Unit;
2055
2056 if (PartitionList == NULL ||
2057 PartitionList->CurrentDisk == NULL ||
2058 PartitionList->CurrentPartition == NULL)
2059 {
2060 /* FIXME: show an error dialog */
2061 return QUIT_PAGE;
2062 }
2063
2064 DiskEntry = PartitionList->CurrentDisk;
2065 PartEntry = PartitionList->CurrentPartition;
2066
2067 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2068
2069 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION));
2070
2071 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2072 #if 0
2073 if (DiskSize >= 10 * GB) /* 10 GB */
2074 {
2075 DiskSize = DiskSize / GB;
2076 Unit = MUIGetString(STRING_GB);
2077 }
2078 else
2079 #endif
2080 {
2081 DiskSize = DiskSize / MB;
2082 if (DiskSize == 0)
2083 DiskSize = 1;
2084
2085 Unit = MUIGetString(STRING_MB);
2086 }
2087
2088 if (DiskEntry->DriverName.Length > 0)
2089 {
2090 CONSOLE_PrintTextXY(6, 10,
2091 MUIGetString(STRING_HDINFOPARTCREATE_1),
2092 DiskSize,
2093 Unit,
2094 DiskEntry->DiskNumber,
2095 DiskEntry->Port,
2096 DiskEntry->Bus,
2097 DiskEntry->Id,
2098 &DiskEntry->DriverName,
2099 DiskEntry->NoMbr ? "GPT" : "MBR");
2100 }
2101 else
2102 {
2103 CONSOLE_PrintTextXY(6, 10,
2104 MUIGetString(STRING_HDINFOPARTCREATE_2),
2105 DiskSize,
2106 Unit,
2107 DiskEntry->DiskNumber,
2108 DiskEntry->Port,
2109 DiskEntry->Bus,
2110 DiskEntry->Id,
2111 DiskEntry->NoMbr ? "GPT" : "MBR");
2112 }
2113
2114 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2115
2116 #if 0
2117 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2118 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2119 #endif
2120
2121 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2122
2123 PartEntry = PartitionList->CurrentPartition;
2124 while (TRUE)
2125 {
2126 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2127
2128 if (MaxSize > PARTITION_MAXSIZE)
2129 MaxSize = PARTITION_MAXSIZE;
2130
2131 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2132 MaxSize, InputBuffer, &Quit, &Cancel);
2133
2134 if (Quit)
2135 {
2136 if (ConfirmQuit(Ir))
2137 return QUIT_PAGE;
2138
2139 break;
2140 }
2141 else if (Cancel)
2142 {
2143 return SELECT_PARTITION_PAGE;
2144 }
2145 else
2146 {
2147 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2148
2149 if (PartSize < 1)
2150 {
2151 /* Too small */
2152 continue;
2153 }
2154
2155 if (PartSize > MaxSize)
2156 {
2157 /* Too large */
2158 continue;
2159 }
2160
2161 /* Convert to bytes */
2162 if (PartSize == MaxSize)
2163 {
2164 /* Use all of the unpartitioned disk space */
2165 SectorCount = PartEntry->SectorCount.QuadPart;
2166 }
2167 else
2168 {
2169 /* Calculate the sector count from the size in MB */
2170 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2171
2172 /* But never get larger than the unpartitioned disk space */
2173 if (SectorCount > PartEntry->SectorCount.QuadPart)
2174 SectorCount = PartEntry->SectorCount.QuadPart;
2175 }
2176
2177 DPRINT ("Partition size: %I64u bytes\n", PartSize);
2178
2179 CreateExtendedPartition(PartitionList,
2180 SectorCount);
2181
2182 return SELECT_PARTITION_PAGE;
2183 }
2184 }
2185
2186 return CREATE_EXTENDED_PARTITION_PAGE;
2187 }
2188
2189
2190 /*
2191 * Displays the CreateLogicalPartitionPage.
2192 *
2193 * Next pages:
2194 * SelectFileSystemPage (default)
2195 * QuitPage
2196 *
2197 * RETURNS
2198 * Number of the next page.
2199 */
2200 static PAGE_NUMBER
2201 CreateLogicalPartitionPage(PINPUT_RECORD Ir)
2202 {
2203 PDISKENTRY DiskEntry;
2204 PPARTENTRY PartEntry;
2205 BOOLEAN Quit;
2206 BOOLEAN Cancel;
2207 WCHAR InputBuffer[50];
2208 ULONG MaxSize;
2209 ULONGLONG PartSize;
2210 ULONGLONG DiskSize;
2211 ULONGLONG SectorCount;
2212 PCHAR Unit;
2213
2214 if (PartitionList == NULL ||
2215 PartitionList->CurrentDisk == NULL ||
2216 PartitionList->CurrentPartition == NULL)
2217 {
2218 /* FIXME: show an error dialog */
2219 return QUIT_PAGE;
2220 }
2221
2222 DiskEntry = PartitionList->CurrentDisk;
2223 PartEntry = PartitionList->CurrentPartition;
2224
2225 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2226
2227 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION));
2228
2229 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2230 #if 0
2231 if (DiskSize >= 10 * GB) /* 10 GB */
2232 {
2233 DiskSize = DiskSize / GB;
2234 Unit = MUIGetString(STRING_GB);
2235 }
2236 else
2237 #endif
2238 {
2239 DiskSize = DiskSize / MB;
2240 if (DiskSize == 0)
2241 DiskSize = 1;
2242
2243 Unit = MUIGetString(STRING_MB);
2244 }
2245
2246 if (DiskEntry->DriverName.Length > 0)
2247 {
2248 CONSOLE_PrintTextXY(6, 10,
2249 MUIGetString(STRING_HDINFOPARTCREATE_1),
2250 DiskSize,
2251 Unit,
2252 DiskEntry->DiskNumber,
2253 DiskEntry->Port,
2254 DiskEntry->Bus,
2255 DiskEntry->Id,
2256 &DiskEntry->DriverName,
2257 DiskEntry->NoMbr ? "GPT" : "MBR");
2258 }
2259 else
2260 {
2261 CONSOLE_PrintTextXY(6, 10,
2262 MUIGetString(STRING_HDINFOPARTCREATE_2),
2263 DiskSize,
2264 Unit,
2265 DiskEntry->DiskNumber,
2266 DiskEntry->Port,
2267 DiskEntry->Bus,
2268 DiskEntry->Id,
2269 DiskEntry->NoMbr ? "GPT" : "MBR");
2270 }
2271
2272 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE));
2273
2274 #if 0
2275 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB",
2276 PartitionList->CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB);
2277 #endif
2278
2279 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION));
2280
2281 PartEntry = PartitionList->CurrentPartition;
2282 while (TRUE)
2283 {
2284 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */
2285
2286 if (MaxSize > PARTITION_MAXSIZE)
2287 MaxSize = PARTITION_MAXSIZE;
2288
2289 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */
2290 MaxSize, InputBuffer, &Quit, &Cancel);
2291
2292 if (Quit)
2293 {
2294 if (ConfirmQuit(Ir))
2295 return QUIT_PAGE;
2296
2297 break;
2298 }
2299 else if (Cancel)
2300 {
2301 return SELECT_PARTITION_PAGE;
2302 }
2303 else
2304 {
2305 PartSize = _wcstoui64(InputBuffer, NULL, 10);
2306
2307 if (PartSize < 1)
2308 {
2309 /* Too small */
2310 continue;
2311 }
2312
2313 if (PartSize > MaxSize)
2314 {
2315 /* Too large */
2316 continue;
2317 }
2318
2319 /* Convert to bytes */
2320 if (PartSize == MaxSize)
2321 {
2322 /* Use all of the unpartitioned disk space */
2323 SectorCount = PartEntry->SectorCount.QuadPart;
2324 }
2325 else
2326 {
2327 /* Calculate the sector count from the size in MB */
2328 SectorCount = PartSize * MB / DiskEntry->BytesPerSector;
2329
2330 /* But never get larger than the unpartitioned disk space */
2331 if (SectorCount > PartEntry->SectorCount.QuadPart)
2332 SectorCount = PartEntry->SectorCount.QuadPart;
2333 }
2334
2335 DPRINT("Partition size: %I64u bytes\n", PartSize);
2336
2337 CreateLogicalPartition(PartitionList,
2338 SectorCount,
2339 FALSE);
2340
2341 return SELECT_PARTITION_PAGE;
2342 }
2343 }
2344
2345 return CREATE_LOGICAL_PARTITION_PAGE;
2346 }
2347
2348
2349 /*
2350 * Displays the ConfirmDeleteSystemPartitionPage.
2351 *
2352 * Next pages:
2353 * DeletePartitionPage (default)
2354 * SelectPartitionPage
2355 *
2356 * RETURNS
2357 * Number of the next page.
2358 */
2359 static PAGE_NUMBER
2360 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir)
2361 {
2362 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE);
2363
2364 while (TRUE)
2365 {
2366 CONSOLE_ConInKey(Ir);
2367
2368 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2369 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2370 {
2371 if (ConfirmQuit(Ir))
2372 return QUIT_PAGE;
2373
2374 break;
2375 }
2376 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2377 {
2378 return DELETE_PARTITION_PAGE;
2379 }
2380 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2381 {
2382 return SELECT_PARTITION_PAGE;
2383 }
2384 }
2385
2386 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE;
2387 }
2388
2389
2390 /*
2391 * Displays the DeletePartitionPage.
2392 *
2393 * Next pages:
2394 * SelectPartitionPage (default)
2395 * QuitPage
2396 *
2397 * RETURNS
2398 * Number of the next page.
2399 */
2400 static PAGE_NUMBER
2401 DeletePartitionPage(PINPUT_RECORD Ir)
2402 {
2403 PDISKENTRY DiskEntry;
2404 PPARTENTRY PartEntry;
2405 ULONGLONG DiskSize;
2406 ULONGLONG PartSize;
2407 PCHAR Unit;
2408 CHAR PartTypeString[32];
2409
2410 if (PartitionList == NULL ||
2411 PartitionList->CurrentDisk == NULL ||
2412 PartitionList->CurrentPartition == NULL)
2413 {
2414 /* FIXME: show an error dialog */
2415 return QUIT_PAGE;
2416 }
2417
2418 DiskEntry = PartitionList->CurrentDisk;
2419 PartEntry = PartitionList->CurrentPartition;
2420
2421 MUIDisplayPage(DELETE_PARTITION_PAGE);
2422
2423 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2424 PartTypeString,
2425 ARRAYSIZE(PartTypeString));
2426
2427 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2428 #if 0
2429 if (PartSize >= 10 * GB) /* 10 GB */
2430 {
2431 PartSize = PartSize / GB;
2432 Unit = MUIGetString(STRING_GB);
2433 }
2434 else
2435 #endif
2436 if (PartSize >= 10 * MB) /* 10 MB */
2437 {
2438 PartSize = PartSize / MB;
2439 Unit = MUIGetString(STRING_MB);
2440 }
2441 else
2442 {
2443 PartSize = PartSize / KB;
2444 Unit = MUIGetString(STRING_KB);
2445 }
2446
2447 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2448 {
2449 CONSOLE_PrintTextXY(6, 10,
2450 MUIGetString(STRING_HDDINFOUNK2),
2451 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2452 (PartEntry->DriveLetter == 0) ? '-' : ':',
2453 PartEntry->PartitionType,
2454 PartSize,
2455 Unit);
2456 }
2457 else
2458 {
2459 CONSOLE_PrintTextXY(6, 10,
2460 " %c%c %s %I64u %s",
2461 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2462 (PartEntry->DriveLetter == 0) ? '-' : ':',
2463 PartTypeString,
2464 PartSize,
2465 Unit);
2466 }
2467
2468 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2469 #if 0
2470 if (DiskSize >= 10 * GB) /* 10 GB */
2471 {
2472 DiskSize = DiskSize / GB;
2473 Unit = MUIGetString(STRING_GB);
2474 }
2475 else
2476 #endif
2477 {
2478 DiskSize = DiskSize / MB;
2479 if (DiskSize == 0)
2480 DiskSize = 1;
2481
2482 Unit = MUIGetString(STRING_MB);
2483 }
2484
2485 if (DiskEntry->DriverName.Length > 0)
2486 {
2487 CONSOLE_PrintTextXY(6, 12,
2488 MUIGetString(STRING_HDINFOPARTDELETE_1),
2489 DiskSize,
2490 Unit,
2491 DiskEntry->DiskNumber,
2492 DiskEntry->Port,
2493 DiskEntry->Bus,
2494 DiskEntry->Id,
2495 &DiskEntry->DriverName,
2496 DiskEntry->NoMbr ? "GPT" : "MBR");
2497 }
2498 else
2499 {
2500 CONSOLE_PrintTextXY(6, 12,
2501 MUIGetString(STRING_HDINFOPARTDELETE_2),
2502 DiskSize,
2503 Unit,
2504 DiskEntry->DiskNumber,
2505 DiskEntry->Port,
2506 DiskEntry->Bus,
2507 DiskEntry->Id,
2508 DiskEntry->NoMbr ? "GPT" : "MBR");
2509 }
2510
2511 while (TRUE)
2512 {
2513 CONSOLE_ConInKey(Ir);
2514
2515 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2516 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2517 {
2518 if (ConfirmQuit(Ir))
2519 return QUIT_PAGE;
2520
2521 break;
2522 }
2523 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */
2524 {
2525 return SELECT_PARTITION_PAGE;
2526 }
2527 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */
2528 {
2529 DeleteCurrentPartition(PartitionList);
2530
2531 return SELECT_PARTITION_PAGE;
2532 }
2533 }
2534
2535 return DELETE_PARTITION_PAGE;
2536 }
2537
2538
2539 /*
2540 * Displays the SelectFileSystemPage.
2541 *
2542 * Next pages:
2543 * CheckFileSystemPage (At once if RepairUpdate is selected)
2544 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition)
2545 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition)
2546 * SelectPartitionPage (If the user aborts)
2547 * FormatPartitionPage (Default)
2548 * QuitPage
2549 *
2550 * SIDEEFFECTS
2551 * Sets PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType (via UpdatePartitionType)
2552 * Calls CheckActiveSystemPartition()
2553 *
2554 * RETURNS
2555 * Number of the next page.
2556 */
2557 static PAGE_NUMBER
2558 SelectFileSystemPage(PINPUT_RECORD Ir)
2559 {
2560 PDISKENTRY DiskEntry;
2561 PPARTENTRY PartEntry;
2562 ULONGLONG DiskSize;
2563 ULONGLONG PartSize;
2564 PCHAR DiskUnit;
2565 PCHAR PartUnit;
2566 CHAR PartTypeString[32];
2567 FORMATMACHINESTATE PreviousFormatState;
2568
2569 DPRINT("SelectFileSystemPage()\n");
2570
2571 if (PartitionList == NULL ||
2572 PartitionList->CurrentDisk == NULL ||
2573 PartitionList->CurrentPartition == NULL)
2574 {
2575 /* FIXME: show an error dialog */
2576 return QUIT_PAGE;
2577 }
2578
2579 /* Find or set the active system partition */
2580 CheckActiveSystemPartition(PartitionList);
2581 if (PartitionList->SystemPartition == NULL)
2582 {
2583 /* FIXME: show an error dialog */
2584 //
2585 // Error dialog should say that we cannot find a suitable
2586 // system partition and create one on the system. At this point,
2587 // it may be nice to ask the user whether he wants to continue,
2588 // or use an external drive as the system drive/partition
2589 // (e.g. floppy, USB drive, etc...)
2590 //
2591 return QUIT_PAGE;
2592 }
2593
2594 PreviousFormatState = FormatState;
2595 switch (FormatState)
2596 {
2597 case Start:
2598 {
2599 if (PartitionList->CurrentPartition != PartitionList->SystemPartition)
2600 {
2601 TempPartition = PartitionList->SystemPartition;
2602 TempPartition->NeedsCheck = TRUE;
2603
2604 FormatState = FormatSystemPartition;
2605 DPRINT1("FormatState: Start --> FormatSystemPartition\n");
2606 }
2607 else
2608 {
2609 TempPartition = PartitionList->CurrentPartition;
2610 TempPartition->NeedsCheck = TRUE;
2611
2612 FormatState = FormatInstallPartition;
2613 DPRINT1("FormatState: Start --> FormatInstallPartition\n");
2614 }
2615 break;
2616 }
2617
2618 case FormatSystemPartition:
2619 {
2620 TempPartition = PartitionList->CurrentPartition;
2621 TempPartition->NeedsCheck = TRUE;
2622
2623 FormatState = FormatInstallPartition;
2624 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n");
2625 break;
2626 }
2627
2628 case FormatInstallPartition:
2629 {
2630 if (GetNextUnformattedPartition(PartitionList,
2631 NULL,
2632 &TempPartition))
2633 {
2634 FormatState = FormatOtherPartition;
2635 TempPartition->NeedsCheck = TRUE;
2636 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n");
2637 }
2638 else
2639 {
2640 FormatState = FormatDone;
2641 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n");
2642 return CHECK_FILE_SYSTEM_PAGE;
2643 }
2644 break;
2645 }
2646
2647 case FormatOtherPartition:
2648 {
2649 if (GetNextUnformattedPartition(PartitionList,
2650 NULL,
2651 &TempPartition))
2652 {
2653 FormatState = FormatOtherPartition;
2654 TempPartition->NeedsCheck = TRUE;
2655 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n");
2656 }
2657 else
2658 {
2659 FormatState = FormatDone;
2660 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n");
2661 return CHECK_FILE_SYSTEM_PAGE;
2662 }
2663 break;
2664 }
2665
2666 default:
2667 {
2668 DPRINT1("FormatState: Invalid value %ld\n", FormatState);
2669 /* FIXME: show an error dialog */
2670 return QUIT_PAGE;
2671 }
2672 }
2673
2674 PartEntry = TempPartition;
2675 DiskEntry = PartEntry->DiskEntry;
2676
2677 /* Adjust disk size */
2678 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2679 if (DiskSize >= 10 * GB) /* 10 GB */
2680 {
2681 DiskSize = DiskSize / GB;
2682 DiskUnit = MUIGetString(STRING_GB);
2683 }
2684 else
2685 {
2686 DiskSize = DiskSize / MB;
2687 DiskUnit = MUIGetString(STRING_MB);
2688 }
2689
2690 /* Adjust partition size */
2691 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2692 if (PartSize >= 10 * GB) /* 10 GB */
2693 {
2694 PartSize = PartSize / GB;
2695 PartUnit = MUIGetString(STRING_GB);
2696 }
2697 else
2698 {
2699 PartSize = PartSize / MB;
2700 PartUnit = MUIGetString(STRING_MB);
2701 }
2702
2703 /* Adjust partition type */
2704 GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
2705 PartTypeString,
2706 ARRAYSIZE(PartTypeString));
2707
2708 if (PartEntry->AutoCreate)
2709 {
2710 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION));
2711
2712 #if 0
2713 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of",
2714 PartEntry->PartitionNumber,
2715 PartSize,
2716 PartUnit,
2717 PartTypeString);
2718 #endif
2719
2720 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1),
2721 DiskEntry->DiskNumber,
2722 DiskSize,
2723 DiskUnit,
2724 DiskEntry->Port,
2725 DiskEntry->Bus,
2726 DiskEntry->Id,
2727 &DiskEntry->DriverName,
2728 DiskEntry->NoMbr ? "GPT" : "MBR");
2729
2730 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT));
2731
2732 PartEntry->AutoCreate = FALSE;
2733 }
2734 else if (PartEntry->New)
2735 {
2736 switch (FormatState)
2737 {
2738 case FormatSystemPartition:
2739 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART));
2740 break;
2741
2742 case FormatInstallPartition:
2743 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART));
2744 break;
2745
2746 case FormatOtherPartition:
2747 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART));
2748 break;
2749
2750 default:
2751 break;
2752 }
2753
2754 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT));
2755 }
2756 else
2757 {
2758 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART));
2759
2760 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ??
2761 {
2762 CONSOLE_PrintTextXY(8, 10,
2763 MUIGetString(STRING_HDDINFOUNK4),
2764 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2765 (PartEntry->DriveLetter == 0) ? '-' : ':',
2766 PartEntry->PartitionType,
2767 PartSize,
2768 PartUnit);
2769 }
2770 else
2771 {
2772 CONSOLE_PrintTextXY(8, 10,
2773 "%c%c %s %I64u %s",
2774 (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
2775 (PartEntry->DriveLetter == 0) ? '-' : ':',
2776 PartTypeString,
2777 PartSize,
2778 PartUnit);
2779 }
2780
2781 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1),
2782 DiskEntry->DiskNumber,
2783 DiskSize,
2784 DiskUnit,
2785 DiskEntry->Port,
2786 DiskEntry->Bus,
2787 DiskEntry->Id,
2788 &DiskEntry->DriverName,
2789 DiskEntry->NoMbr ? "GPT" : "MBR");
2790 }
2791
2792 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE);
2793
2794 if (FileSystemList == NULL)
2795 {
2796 /* Create the file system list, and by default select the "FAT" file system */
2797 FileSystemList = CreateFileSystemList(6, 26, PartEntry->New, L"FAT");
2798 if (FileSystemList == NULL)
2799 {
2800 /* FIXME: show an error dialog */
2801 return QUIT_PAGE;
2802 }
2803 }
2804
2805 if (RepairUpdateFlag)
2806 {
2807 return CHECK_FILE_SYSTEM_PAGE;
2808 //return SELECT_PARTITION_PAGE;
2809 }
2810
2811 if (IsUnattendedSetup)
2812 {
2813 if (USetupData.FormatPartition)
2814 {
2815 /*
2816 * We use whatever currently selected file system we have
2817 * (by default, this is "FAT", as per the initialization
2818 * performed above). Note that it may be interesting to specify
2819 * which file system to use in unattended installations, in the
2820 * txtsetup.sif file.
2821 */
2822 return FORMAT_PARTITION_PAGE;
2823 }
2824
2825 return CHECK_FILE_SYSTEM_PAGE;
2826 }
2827
2828 DrawFileSystemList(FileSystemList);
2829
2830 while (TRUE)
2831 {
2832 CONSOLE_ConInKey(Ir);
2833
2834 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2835 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2836 {
2837 if (ConfirmQuit(Ir))
2838 return QUIT_PAGE;
2839
2840 break;
2841 }
2842 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2843 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */
2844 {
2845 FormatState = Start;
2846 return SELECT_PARTITION_PAGE;
2847 }
2848 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2849 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
2850 {
2851 ScrollDownFileSystemList(FileSystemList);
2852 }
2853 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2854 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
2855 {
2856 ScrollUpFileSystemList(FileSystemList);
2857 }
2858 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */
2859 {
2860 if (!FileSystemList->Selected->FileSystem)
2861 return SELECT_FILE_SYSTEM_PAGE;
2862 else
2863 return FORMAT_PARTITION_PAGE;
2864 }
2865 }
2866
2867 FormatState = PreviousFormatState;
2868
2869 return SELECT_FILE_SYSTEM_PAGE;
2870 }
2871
2872
2873 /*
2874 * Displays the FormatPartitionPage.
2875 *
2876 * Next pages:
2877 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut)
2878 * SelectPartitionPage (At once)
2879 * QuitPage
2880 *
2881 * SIDEEFFECTS
2882 * Sets PartitionList->CurrentPartition->FormatState
2883 * Sets USetupData.DestinationRootPath
2884 *
2885 * RETURNS
2886 * Number of the next page.
2887 */
2888 static PAGE_NUMBER
2889 FormatPartitionPage(PINPUT_RECORD Ir)
2890 {
2891 UNICODE_STRING PartitionRootPath;
2892 WCHAR PathBuffer[MAX_PATH];
2893 PDISKENTRY DiskEntry;
2894 PPARTENTRY PartEntry;
2895 PFILE_SYSTEM_ITEM SelectedFileSystem;
2896 NTSTATUS Status;
2897
2898 #ifndef NDEBUG
2899 ULONG Line;
2900 ULONG i;
2901 PPARTITION_INFORMATION PartitionInfo;
2902 #endif
2903
2904 DPRINT("FormatPartitionPage()\n");
2905
2906 MUIDisplayPage(FORMAT_PARTITION_PAGE);
2907
2908 if (PartitionList == NULL || TempPartition == NULL)
2909 {
2910 /* FIXME: show an error dialog */
2911 return QUIT_PAGE;
2912 }
2913
2914 PartEntry = TempPartition;
2915 DiskEntry = PartEntry->DiskEntry;
2916
2917 SelectedFileSystem = FileSystemList->Selected;
2918
2919 while (TRUE)
2920 {
2921 if (!IsUnattendedSetup)
2922 {
2923 CONSOLE_ConInKey(Ir);
2924 }
2925
2926 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
2927 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
2928 {
2929 if (ConfirmQuit(Ir))
2930 return QUIT_PAGE;
2931
2932 break;
2933 }
2934 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */
2935 {
2936 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
2937
2938 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem))
2939 {
2940 /* FIXME: show an error dialog */
2941 return QUIT_PAGE;
2942 }
2943
2944 #ifndef NDEBUG
2945 CONSOLE_PrintTextXY(6, 12,
2946 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c",
2947 DiskEntry->Cylinders,
2948 DiskEntry->TracksPerCylinder,
2949 DiskEntry->SectorsPerTrack,
2950 DiskEntry->BytesPerSector,
2951 DiskEntry->Dirty ? '*' : ' ');
2952
2953 Line = 13;
2954
2955 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
2956 {
2957 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
2958
2959 CONSOLE_PrintTextXY(6, Line,
2960 "%2u: %2lu %c %12I64u %12I64u %02x",
2961 i,
2962 PartitionInfo->PartitionNumber,
2963 PartitionInfo->BootIndicator ? 'A' : '-',
2964 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
2965 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
2966 PartitionInfo->PartitionType);
2967 Line++;
2968 }
2969 #endif
2970
2971 /* Commit the partition changes to the disk */
2972 if (!WritePartitionsToDisk(PartitionList))
2973 {
2974 DPRINT("WritePartitionsToDisk() failed\n");
2975 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER);
2976 return QUIT_PAGE;
2977 }
2978
2979 /* Set PartitionRootPath */
2980 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
2981 L"\\Device\\Harddisk%lu\\Partition%lu",
2982 DiskEntry->DiskNumber,
2983 PartEntry->PartitionNumber);
2984 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
2985 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
2986
2987 /* Format the partition */
2988 if (SelectedFileSystem->FileSystem)
2989 {
2990 Status = FormatPartition(&PartitionRootPath,
2991 SelectedFileSystem);
2992 if (!NT_SUCCESS(Status))
2993 {
2994 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status);
2995 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer);
2996 return QUIT_PAGE;
2997 }
2998
2999 PartEntry->FormatState = Formatted;
3000 // PartEntry->FileSystem = FileSystem;
3001 PartEntry->New = FALSE;
3002 }
3003
3004 #ifndef NDEBUG
3005 CONSOLE_SetStatusText(" Done. Press any key ...");
3006 CONSOLE_ConInKey(Ir);
3007 #endif
3008
3009 return SELECT_FILE_SYSTEM_PAGE;
3010 }
3011 }
3012
3013 return FORMAT_PARTITION_PAGE;
3014 }
3015
3016
3017 /*
3018 * Displays the CheckFileSystemPage.
3019 *
3020 * Next pages:
3021 * InstallDirectoryPage (At once)
3022 * QuitPage
3023 *
3024 * SIDEEFFECTS
3025 * Inits or reloads FileSystemList
3026 *
3027 * RETURNS
3028 * Number of the next page.
3029 */
3030 static PAGE_NUMBER
3031 CheckFileSystemPage(PINPUT_RECORD Ir)
3032 {
3033 PFILE_SYSTEM CurrentFileSystem;
3034 UNICODE_STRING PartitionRootPath;
3035 WCHAR PathBuffer[MAX_PATH];
3036 CHAR Buffer[MAX_PATH];
3037 PDISKENTRY DiskEntry;
3038 PPARTENTRY PartEntry;
3039 NTSTATUS Status;
3040
3041 if (PartitionList == NULL)
3042 {
3043 /* FIXME: show an error dialog */
3044 return QUIT_PAGE;
3045 }
3046
3047 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry))
3048 {
3049 return INSTALL_DIRECTORY_PAGE;
3050 }
3051
3052 /* Set PartitionRootPath */
3053 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3054 L"\\Device\\Harddisk%lu\\Partition%lu",
3055 DiskEntry->DiskNumber,
3056 PartEntry->PartitionNumber);
3057 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
3058 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
3059
3060 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART));
3061
3062 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
3063
3064 CurrentFileSystem = PartEntry->FileSystem;
3065 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystemName: %S\n",
3066 PartEntry->PartitionType, (CurrentFileSystem ? CurrentFileSystem->FileSystemName : L"n/a"));
3067
3068 /* HACK: Do not try to check a partition with an unknown filesystem */
3069 if (CurrentFileSystem == NULL)
3070 {
3071 PartEntry->NeedsCheck = FALSE;
3072 return CHECK_FILE_SYSTEM_PAGE;
3073 }
3074
3075 if (CurrentFileSystem->ChkdskFunc == NULL)
3076 {
3077 sprintf(Buffer,
3078 "Setup is currently unable to check a partition formatted in %S.\n"
3079 "\n"
3080 " \x07 Press ENTER to continue Setup.\n"
3081 " \x07 Press F3 to quit Setup.",
3082 CurrentFileSystem->FileSystemName);
3083
3084 PopupError(Buffer,
3085 MUIGetString(STRING_QUITCONTINUE),
3086 NULL, POPUP_WAIT_NONE);
3087
3088 while (TRUE)
3089 {
3090 CONSOLE_ConInKey(Ir);
3091
3092 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 &&
3093 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */
3094 {
3095 if (ConfirmQuit(Ir))
3096 return QUIT_PAGE;
3097 else
3098 return CHECK_FILE_SYSTEM_PAGE;
3099 }
3100 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */
3101 {
3102 PartEntry->NeedsCheck = FALSE;
3103 return CHECK_FILE_SYSTEM_PAGE;
3104 }
3105 }
3106 }
3107 else
3108 {
3109 Status = ChkdskPartition(&PartitionRootPath, CurrentFileSystem);
3110 if (!NT_SUCCESS(Status))
3111 {
3112 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status);
3113 // sprintf(Buffer, "Setup failed to verify the selected partition.\n"
3114 sprintf(Buffer, "ChkDsk detected some disk errors.\n"
3115 "(Status 0x%08lx).\n", Status);
3116 PopupError(Buffer,
3117 // MUIGetString(STRING_REBOOTCOMPUTER),
3118 MUIGetString(STRING_CONTINUE),
3119 Ir, POPUP_WAIT_ENTER);
3120
3121 // return QUIT_PAGE;
3122 }
3123
3124 PartEntry->NeedsCheck = FALSE;
3125 return CHECK_FILE_SYSTEM_PAGE;
3126 }
3127 }
3128
3129
3130 static VOID
3131 BuildInstallPaths(PWSTR InstallDir,
3132 PDISKENTRY DiskEntry,
3133 PPARTENTRY PartEntry)
3134 {
3135 WCHAR PathBuffer[MAX_PATH];
3136
3137 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/
3138 /* Create 'InstallPath' string */
3139 RtlFreeUnicodeString(&InstallPath);
3140 RtlCreateUnicodeString(&InstallPath, InstallDir);
3141
3142 /* Create 'USetupData.DestinationRootPath' string */
3143 RtlFreeUnicodeString(&USetupData.DestinationRootPath);
3144 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3145 L"\\Device\\Harddisk%lu\\Partition%lu\\",
3146 DiskEntry->DiskNumber,
3147 PartEntry->PartitionNumber);
3148 RtlCreateUnicodeString(&USetupData.DestinationRootPath, PathBuffer);
3149 DPRINT("DestinationRootPath: %wZ\n", &USetupData.DestinationRootPath);
3150
3151 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/
3152 /* Create 'USetupData.DestinationPath' string */
3153 RtlFreeUnicodeString(&USetupData.DestinationPath);
3154 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3155 USetupData.DestinationRootPath.Buffer, InstallDir);
3156 RtlCreateUnicodeString(&USetupData.DestinationPath, PathBuffer);
3157
3158 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/
3159 /* Create 'USetupData.DestinationArcPath' */
3160 RtlFreeUnicodeString(&USetupData.DestinationArcPath);
3161 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
3162 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\",
3163 DiskEntry->BiosDiskNumber,
3164 PartEntry->PartitionNumber);
3165 ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallDir);
3166 RtlCreateUnicodeString(&USetupData.DestinationArcPath, PathBuffer);
3167
3168 /* Initialize DestinationDriveLetter */
3169 DestinationDriveLetter = (WCHAR)PartEntry->DriveLetter;
3170 }
3171
3172
3173 /*
3174 * Displays the InstallDirectoryPage.
3175 *
3176 * Next pages:
3177 * PrepareCopyPage
3178 * QuitPage
3179 *
3180 * RETURNS
3181 * Number of the next page.
3182 */
3183 static PAGE_NUMBER
3184 InstallDirectoryPage(PINPUT_RECORD Ir)
3185 {
3186 PDISKENTRY DiskEntry;
3187 PPARTENTRY PartEntry;
3188 WCHAR InstallDir[MAX_PATH];
3189 WCHAR c;
3190 ULONG Length, Pos;
3191
3192 /* We do not need the filesystem list anymore */
3193 if (FileSystemList != NULL)
3194 {
3195 DestroyFileSystemList(FileSystemList);
3196 FileSystemList = NULL;
3197 }
3198
3199 if (PartitionList == NULL ||
3200 PartitionList->CurrentDisk == NULL ||
3201 PartitionList->CurrentPartition == NULL)
3202 {
3203 /* FIXME: show an error dialog */
3204 return QUIT_PAGE;
3205 }
3206
3207 DiskEntry = PartitionList->CurrentDisk;
3208 PartEntry = PartitionList->CurrentPartition;
3209
3210 // if (IsUnattendedSetup)
3211 if (RepairUpdateFlag)
3212 wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath
3213 else if (USetupData.InstallationDirectory[0])
3214 wcscpy(InstallDir, USetupData.InstallationDirectory);
3215 else
3216 wcscpy(InstallDir, L"\\ReactOS");
3217
3218 /*
3219 * Check the validity of the predefined 'InstallDir'. If we are either
3220 * in unattended setup or in update/repair mode, and the installation path
3221 * is valid, just perform the installation. Otherwise (either in the case
3222 * of an invalid path, or we are in regular setup), display the UI and allow
3223 * the user to specify a new installation path.
3224 */
3225 if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir))
3226 {
3227 BuildInstallPaths(InstallDir,
3228 DiskEntry,
3229 PartEntry);
3230
3231 return PREPARE_COPY_PAGE;
3232 }
3233
3234 Length = wcslen(InstallDir);
3235 Pos = Length;
3236
3237 MUIDisplayPage(INSTALL_DIRECTORY_PAGE);
3238 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3239 CONSOLE_SetCursorXY(8 + Pos, 11);
3240 CONSOLE_SetCursorType(TRUE, TRUE);
3241
3242 while (TRUE)
3243 {
3244 CONSOLE_ConInKey(Ir);
3245
3246 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3247 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
3248 {
3249 CONSOLE_SetCursorType(TRUE, FALSE);
3250
3251 if (ConfirmQuit(Ir))
3252 return QUIT_PAGE;
3253
3254 CONSOLE_SetCursorType(TRUE, TRUE);
3255 break;
3256 }
3257 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3258 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */
3259 {
3260 if (Pos < Length)
3261 {
3262 memmove(&InstallDir[Pos],
3263 &InstallDir[Pos + 1],
3264 (Length - Pos - 1) * sizeof(WCHAR));
3265 InstallDir[Length - 1] = UNICODE_NULL;
3266
3267 Length--;
3268 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3269 CONSOLE_SetCursorXY(8 + Pos, 11);
3270 }
3271 }
3272 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3273 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */
3274 {
3275 Pos = 0;
3276 CONSOLE_SetCursorXY(8 + Pos, 11);
3277 }
3278 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3279 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */
3280 {
3281 Pos = Length;
3282 CONSOLE_SetCursorXY(8 + Pos, 11);
3283 }
3284 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3285 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */
3286 {
3287 if (Pos > 0)
3288 {
3289 Pos--;
3290 CONSOLE_SetCursorXY(8 + Pos, 11);
3291 }
3292 }
3293 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
3294 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */
3295 {
3296 if (Pos < Length)
3297 {
3298 Pos++;
3299 CONSOLE_SetCursorXY(8 + Pos, 11);
3300 }
3301 }
3302 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
3303 {
3304 CONSOLE_SetCursorType(TRUE, FALSE);
3305
3306 /*
3307 * Check for the validity of the installation directory and pop up
3308 * an error if it is not the case. Then the user can fix its input.
3309 */
3310 if (!IsValidPath(InstallDir))
3311 {
3312 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER);
3313 return INSTALL_DIRECTORY_PAGE;
3314 }
3315
3316 BuildInstallPaths(InstallDir,
3317 DiskEntry,
3318 PartEntry);
3319
3320 return PREPARE_COPY_PAGE;
3321 }
3322 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */
3323 {
3324 if (Pos > 0)
3325 {
3326 if (Pos < Length)
3327 memmove(&InstallDir[Pos - 1],
3328 &InstallDir[Pos],
3329 (Length - Pos) * sizeof(WCHAR));
3330 InstallDir[Length - 1] = UNICODE_NULL;
3331
3332 Pos--;
3333 Length--;
3334 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3335 CONSOLE_SetCursorXY(8 + Pos, 11);
3336 }
3337 }
3338 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar))
3339 {
3340 if (Length < 50)
3341 {
3342 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar;
3343 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_')
3344 {
3345 if (Pos < Length)
3346 memmove(&InstallDir[Pos + 1],
3347 &InstallDir[Pos],
3348 (Length - Pos) * sizeof(WCHAR));
3349 InstallDir[Length + 1] = UNICODE_NULL;
3350 InstallDir[Pos] = c;
3351
3352 Pos++;
3353 Length++;
3354 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir);
3355 CONSOLE_SetCursorXY(8 + Pos, 11);
3356 }
3357 }
3358 }
3359 }
3360
3361 return INSTALL_DIRECTORY_PAGE;
3362 }
3363
3364
3365 static BOOLEAN
3366 AddSectionToCopyQueueCab(HINF InfFile,
3367 PWCHAR SectionName,
3368 PWCHAR SourceCabinet,
3369 PCUNICODE_STRING DestinationPath,
3370 PINPUT_RECORD Ir)
3371 {
3372 INFCONTEXT FilesContext;
3373 INFCONTEXT DirContext;
3374 PWCHAR FileKeyName;
3375 PWCHAR FileKeyValue;
3376 PWCHAR DirKeyValue;
3377 PWCHAR TargetFileName;
3378
3379 /*
3380 * This code enumerates the list of files in reactos.dff / reactos.inf
3381 * that need to be extracted from reactos.cab and be installed in their
3382 * respective directories.
3383 */
3384
3385 /* Search for the SectionName section */
3386 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3387 {
3388 CHAR Buffer[128];
3389 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
3390 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
3391 return FALSE;
3392 }
3393
3394 /*
3395 * Enumerate the files in the section and add them to the file queue.
3396 */
3397 do
3398 {
3399 /* Get source file name and target directory id */
3400 if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
3401 {
3402 /* FIXME: Handle error! */
3403 DPRINT1("INF_GetData() failed\n");
3404 break;
3405 }
3406
3407 /* Get optional target file name */
3408 if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
3409 TargetFileName = NULL;
3410
3411 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3412
3413 /* Lookup target directory */
3414 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3415 {
3416 /* FIXME: Handle error! */
3417 DPRINT1("SetupFindFirstLine() failed\n");
3418 INF_FreeData(FileKeyName);
3419 INF_FreeData(FileKeyValue);
3420 INF_FreeData(TargetFileName);
3421 break;
3422 }
3423
3424 INF_FreeData(FileKeyValue);
3425
3426 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3427 {
3428 /* FIXME: Handle error! */
3429 DPRINT1("INF_GetData() failed\n");
3430 INF_FreeData(FileKeyName);
3431 INF_FreeData(TargetFileName);
3432 break;
3433 }
3434
3435 if (!SetupQueueCopy(SetupFileQueue,
3436 SourceCabinet,
3437 USetupData.SourceRootPath.Buffer,
3438 USetupData.SourceRootDir.Buffer,
3439 FileKeyName,
3440 DirKeyValue,
3441 TargetFileName))
3442 {
3443 /* FIXME: Handle error! */
3444 DPRINT1("SetupQueueCopy() failed\n");
3445 }
3446
3447 INF_FreeData(FileKeyName);
3448 INF_FreeData(TargetFileName);
3449 INF_FreeData(DirKeyValue);
3450 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3451
3452 return TRUE;
3453 }
3454
3455
3456 static BOOLEAN
3457 AddSectionToCopyQueue(HINF InfFile,
3458 PWCHAR SectionName,
3459 PWCHAR SourceCabinet,
3460 PCUNICODE_STRING DestinationPath,
3461 PINPUT_RECORD Ir)
3462 {
3463 INFCONTEXT FilesContext;
3464 INFCONTEXT DirContext;
3465 PWCHAR FileKeyName;
3466 PWCHAR FileKeyValue;
3467 PWCHAR DirKeyValue;
3468 PWCHAR TargetFileName;
3469 WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
3470
3471 if (SourceCabinet)
3472 return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
3473
3474 /*
3475 * This code enumerates the list of files in txtsetup.sif
3476 * that need to be installed in their respective directories.
3477 */
3478
3479 /* Search for the SectionName section */
3480 if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
3481 {
3482 CHAR Buffer[128];
3483 sprintf(Buffer, MUIGetString(STRING_TXTSETUPFAILED), SectionName);
3484 PopupError(Buffer, MUIGetString(STRING_REBOOTCOMPUTER), Ir, POPUP_WAIT_ENTER);
3485 return FALSE;
3486 }
3487
3488 /*
3489 * Enumerate the files in the section and add them to the file queue.
3490 */
3491 do
3492 {
3493 /* Get source file name */
3494 if (!INF_GetDataField(&FilesContext, 0, &FileKeyName))
3495 {
3496 /* FIXME: Handle error! */
3497 DPRINT1("INF_GetData() failed\n");
3498 break;
3499 }
3500
3501 /* Get target directory id */
3502 if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
3503 {
3504 /* FIXME: Handle error! */
3505 DPRINT1("INF_GetData() failed\n");
3506 INF_FreeData(FileKeyName);
3507 break;
3508 }
3509
3510 /* Get optional target file name */
3511 if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
3512 TargetFileName = NULL;
3513 else if (!*TargetFileName)
3514 TargetFileName = NULL;
3515
3516 DPRINT("FileKeyName: '%S' FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
3517
3518 /* Lookup target directory */
3519 if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
3520 {
3521 /* FIXME: Handle error! */
3522 DPRINT1("SetupFindFirstLine() failed\n");
3523 INF_FreeData(FileKeyName);
3524 INF_FreeData(FileKeyValue);
3525 INF_FreeData(TargetFileName);
3526 break;
3527 }
3528
3529 INF_FreeData(FileKeyValue);
3530
3531 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3532 {
3533 /* FIXME: Handle error! */
3534 DPRINT1("INF_GetData() failed\n");
3535 INF_FreeData(FileKeyName);
3536 INF_FreeData(TargetFileName);
3537 break;
3538 }
3539
3540 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
3541 {
3542 /* Installation path */
3543 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3544
3545 StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
3546 USetupData.SourceRootDir.Buffer);
3547
3548 DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
3549 }
3550 else if (DirKeyValue[0] == L'\\')
3551 {
3552 /* Absolute path */
3553 DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
3554
3555 StringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
3556 DirKeyValue);
3557
3558 DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName);
3559 }
3560 else // if (DirKeyValue[0] != L'\\')
3561 {
3562 /* Path relative to the installation path */
3563 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3564
3565 CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
3566 USetupData.SourceRootDir.Buffer, DirKeyValue);
3567
3568 DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
3569 }
3570
3571 if (!SetupQueueCopy(SetupFileQueue,
3572 SourceCabinet,
3573 USetupData.SourceRootPath.Buffer,
3574 CompleteOrigDirName,
3575 FileKeyName,
3576 DirKeyValue,
3577 TargetFileName))
3578 {
3579 /* FIXME: Handle error! */
3580 DPRINT1("SetupQueueCopy() failed\n");
3581 }
3582
3583 INF_FreeData(FileKeyName);
3584 INF_FreeData(TargetFileName);
3585 INF_FreeData(DirKeyValue);
3586 } while (SetupFindNextLine(&FilesContext, &FilesContext));
3587
3588 return TRUE;
3589 }
3590
3591
3592 static BOOLEAN
3593 PrepareCopyPageInfFile(HINF InfFile,
3594 PWCHAR SourceCabinet,
3595 PINPUT_RECORD Ir)
3596 {
3597 NTSTATUS Status;
3598 INFCONTEXT DirContext;
3599 PWCHAR AdditionalSectionName = NULL;
3600 PWCHAR DirKeyValue;
3601 WCHAR PathBuffer[MAX_PATH];
3602
3603 /* Add common files */
3604 if (!AddSectionToCopyQueue(InfFile, L"SourceDisksFiles", SourceCabinet, &USetupData.DestinationPath, Ir))
3605 return FALSE;
3606
3607 /* Add specific files depending of computer type */
3608 if (SourceCabinet == NULL)
3609 {
3610 if (!ProcessComputerFiles(InfFile, ComputerList, &AdditionalSectionName))
3611 return FALSE;
3612
3613 if (AdditionalSectionName)
3614 {
3615 if (!AddSectionToCopyQueue(InfFile, AdditionalSectionName, SourceCabinet, &USetupData.DestinationPath, Ir))
3616 return FALSE;
3617 }
3618 }
3619
3620 /* Create directories */
3621
3622 /*
3623 * FIXME:
3624 * Copying files to USetupData.DestinationRootPath should be done from within
3625 * the SystemPartitionFiles section.
3626 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
3627 * For installing to USetupData.DestinationPath specify just '\' .
3628 */
3629
3630 /* Get destination path */
3631 StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), USetupData.DestinationPath.Buffer);
3632
3633 DPRINT("FullPath(1): '%S'\n", PathBuffer);
3634
3635 /* Create the install directory */
3636 Status = SetupCreateDirectory(PathBuffer);
3637 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3638 {
3639 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
3640 MUIDisplayError(ERROR_CREATE_INSTALL_DIR, Ir, POPUP_WAIT_ENTER);
3641 return FALSE;
3642 }
3643
3644 /* Search for the 'Directories' section */
3645 if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
3646 {
3647 if (SourceCabinet)
3648 {
3649 MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER);
3650 }
3651 else
3652 {
3653 MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER);
3654 }
3655
3656 return FALSE;
3657 }
3658
3659 /* Enumerate the directory values and create the subdirectories */
3660 do
3661 {
3662 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
3663 {
3664 DPRINT1("break\n");
3665 break;
3666 }
3667
3668 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
3669 {
3670 /* Installation path */
3671 DPRINT("InstallationPath: '%S'\n", DirKeyValue);
3672
3673 StringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
3674 USetupData.DestinationPath.Buffer);
3675
3676 DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
3677 }
3678 else if (DirKeyValue[0] == L'\\')
3679 {
3680 /* Absolute path */
3681 DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
3682
3683 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3684 USetupData.DestinationRootPath.Buffer, DirKeyValue);
3685
3686 DPRINT("AbsolutePath(2): '%S'\n", PathBuffer);
3687
3688 Status = SetupCreateDirectory(PathBuffer);
3689 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3690 {
3691 INF_FreeData(DirKeyValue);
3692 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3693 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3694 return FALSE;
3695 }
3696 }
3697 else // if (DirKeyValue[0] != L'\\')
3698 {
3699 /* Path relative to the installation path */
3700 DPRINT("RelativePath: '%S'\n", DirKeyValue);
3701
3702 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3703 USetupData.DestinationPath.Buffer, DirKeyValue);
3704
3705 DPRINT("RelativePath(2): '%S'\n", PathBuffer);
3706
3707 Status = SetupCreateDirectory(PathBuffer);
3708 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
3709 {
3710 INF_FreeData(DirKeyValue);
3711 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
3712 MUIDisplayError(ERROR_CREATE_DIR, Ir, POPUP_WAIT_ENTER);
3713 return FALSE;
3714 }
3715 }
3716
3717 INF_FreeData(DirKeyValue);
3718 } while (SetupFindNextLine(&DirContext, &DirContext));
3719
3720 return TRUE;
3721 }
3722
3723
3724 /*
3725 * Displays the PrepareCopyPage.
3726 *
3727 * Next pages:
3728 * FileCopyPage(At once)
3729 * QuitPage
3730 *
3731 * SIDEEFFECTS
3732 * Inits SetupFileQueue
3733 * Calls PrepareCopyPageInfFile
3734 *
3735 * RETURNS
3736 * Number of the next page.
3737 */
3738 static PAGE_NUMBER
3739 PrepareCopyPage(PINPUT_RECORD Ir)
3740 {
3741 HINF InfHandle;
3742 WCHAR PathBuffer[MAX_PATH];
3743 INFCONTEXT CabinetsContext;
3744 ULONG InfFileSize;
3745 PWCHAR KeyValue;
3746 UINT ErrorLine;
3747 PVOID InfFileData;
3748
3749 MUIDisplayPage(PREPARE_COPY_PAGE);
3750
3751 /* Create the file queue */
3752 SetupFileQueue = SetupOpenFileQueue();
3753 if (SetupFileQueue == NULL)
3754 {
3755 MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
3756 return QUIT_PAGE;
3757 }
3758
3759 if (!PrepareCopyPageInfFile(SetupInf, NULL, Ir))
3760 {
3761 /* FIXME: show an error dialog */
3762 return QUIT_PAGE;
3763 }
3764
3765 /* Search for the 'Cabinets' section */
3766 if (!SetupFindFirstLineW(SetupInf, L"Cabinets", NULL, &CabinetsContext))
3767 {
3768 return FILE_COPY_PAGE;
3769 }
3770
3771 /*
3772 * Enumerate the directory values in the 'Cabinets'
3773 * section and parse their inf files.
3774 */
3775 do
3776 {
3777 if (!INF_GetData(&CabinetsContext, NULL, &KeyValue))
3778 break;
3779
3780 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
3781 USetupData.SourcePath.Buffer, KeyValue);
3782
3783 CabinetInitialize();
3784 CabinetSetEventHandlers(NULL, NULL, NULL);
3785 CabinetSetCabinetName(PathBuffer);
3786
3787 if (CabinetOpen() == CAB_STATUS_SUCCESS)
3788 {
3789 DPRINT("Cabinet %S\n", CabinetGetCabinetName());
3790
3791 InfFileData = CabinetGetCabinetReservedArea(&InfFileSize);
3792 if (InfFileData == NULL)
3793 {
3794 MUIDisplayError(ERROR_CABINET_SCRIPT, Ir, POPUP_WAIT_ENTER);
3795 return QUIT_PAGE;
3796 }
3797 }
3798 else
3799 {
3800 DPRINT("Cannot open cabinet: %S.\n", CabinetGetCabinetName());
3801 MUIDisplayError(ERROR_CABINET_MISSING, Ir, POPUP_WAIT_ENTER);
3802 return QUIT_PAGE;
3803 }
3804
3805 InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData,
3806 InfFileSize,
3807 NULL,
3808 INF_STYLE_WIN4,
3809 USetupData.LanguageId,
3810 &ErrorLine);
3811
3812 if (InfHandle == INVALID_HANDLE_VALUE)
3813 {
3814 MUIDisplayError(ERROR_INVALID_CABINET_INF, Ir, POPUP_WAIT_ENTER);
3815 return QUIT_PAGE;
3816 }
3817
3818 CabinetCleanup();
3819
3820 if (!PrepareCopyPageInfFile(InfHandle, KeyValue, Ir))
3821 {
3822 /* FIXME: show an error dialog */
3823 return QUIT_PAGE;
3824 }
3825 } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
3826
3827 return FILE_COPY_PAGE;
3828 }
3829
3830
3831 VOID
3832 NTAPI
3833 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
3834 IN BOOLEAN First)
3835 {
3836 SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
3837
3838 /* Get the memory information from the system */
3839 NtQuerySystemInformation(SystemPerformanceInformation,
3840 &PerfInfo,
3841 sizeof(PerfInfo),
3842 NULL);
3843
3844 /* Check if this is initial setup */
3845 if (First)
3846 {
3847 /* Set maximum limits to be total RAM pages */
3848 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit);
3849 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit);
3850 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit);
3851 }
3852
3853 /* Set current values */
3854 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages);
3855 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage);
3856 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
3857 }
3858
3859
3860 static UINT
3861 CALLBACK
3862 FileCopyCallback(PVOID Context,
3863 UINT Notification,
3864 UINT_PTR Param1,
3865 UINT_PTR Param2)
3866 {
3867 PCOPYCONTEXT CopyContext;
3868
3869 CopyContext = (PCOPYCONTEXT)Context;
3870
3871 switch (Notification)
3872 {
3873 case SPFILENOTIFY_STARTSUBQUEUE:
3874 CopyContext->TotalOperations = (ULONG)Param2;
3875 ProgressSetStepCount(CopyContext->ProgressBar,
3876 CopyContext->TotalOperations);
3877 SetupUpdateMemoryInfo(CopyContext, TRUE);
3878 break;
3879
3880 case SPFILENOTIFY_STARTCOPY:
3881 /* Display copy message */
3882 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING), (PWSTR)Param1);
3883 SetupUpdateMemoryInfo(CopyContext, FALSE);
3884 break;
3885
3886 case SPFILENOTIFY_ENDCOPY:
3887 CopyContext->CompletedOperations++;
3888
3889 /* SYSREG checkpoint */
3890 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations)
3891 DPRINT1("CHECKPOINT:HALF_COPIED\n");
3892
3893 ProgressNextStep(CopyContext->ProgressBar);
3894 SetupUpdateMemoryInfo(CopyContext, FALSE);
3895 break;
3896 }
3897
3898 return 0;
3899 }
3900
3901
3902 /*
3903 * Displays the FileCopyPage.
3904 *
3905 * Next pages:
3906 * RegistryPage(At once)
3907 *
3908 * SIDEEFFECTS
3909 * Calls SetupCommitFileQueueW
3910 * Calls SetupCloseFileQueue
3911 *
3912 * RETURNS
3913 * Number of the next page.
3914 */
3915 static PAGE_NUMBER
3916 FileCopyPage(PINPUT_RECORD Ir)
3917 {
3918 COPYCONTEXT CopyContext;
3919 unsigned int mem_bar_width;
3920
3921 MUIDisplayPage(FILE_COPY_PAGE);
3922
3923 /* Create context for the copy process */
3924 CopyContext.DestinationRootPath = USetupData.DestinationRootPath.Buffer;
3925 CopyContext.InstallPath = InstallPath.Buffer;
3926 CopyContext.TotalOperations = 0;
3927 CopyContext.CompletedOperations = 0;
3928
3929 /* Create the progress bar as well */
3930 CopyContext.ProgressBar = CreateProgressBar(13,
3931 26,
3932 xScreen - 13,
3933 yScreen - 20,
3934 10,
3935 24,
3936 TRUE,
3937 MUIGetString(STRING_SETUPCOPYINGFILES));
3938
3939 // fit memory bars to screen width, distribute them uniform
3940 mem_bar_width = (xScreen - 26) / 5;
3941 mem_bar_width -= mem_bar_width % 2; // make even
3942 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
3943 /* Create the paged pool progress bar */
3944 CopyContext.MemoryBars[0] = CreateProgressBar(13,
3945 40,
3946 13 + mem_bar_width,
3947 43,
3948 13,
3949 44,
3950 FALSE,
3951 "Kernel Pool");
3952
3953 /* Create the non paged pool progress bar */
3954 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (mem_bar_width / 2),
3955 40,
3956 (xScreen / 2) + (mem_bar_width / 2),
3957 43,
3958 (xScreen / 2)- (mem_bar_width / 2),
3959 44,
3960 FALSE,
3961 "Kernel Cache");
3962
3963 /* Create the global memory progress bar */
3964 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - mem_bar_width,
3965 40,
3966 xScreen - 13,
3967 43,
3968 xScreen - 13 - mem_bar_width,
3969 44,
3970 FALSE,
3971 "Free Memory");
3972
3973 /* Do the file copying */
3974 SetupCommitFileQueueW(NULL,
3975 SetupFileQueue,
3976 FileCopyCallback,
3977 &CopyContext);
3978
3979 /* If we get here, we're done, so cleanup the queue and progress bar */
3980 SetupCloseFileQueue(SetupFileQueue);
3981 DestroyProgressBar(CopyContext.ProgressBar);
3982 DestroyProgressBar(CopyContext.MemoryBars[0]);
3983 DestroyProgressBar(CopyContext.MemoryBars[1]);
3984 DestroyProgressBar(CopyContext.MemoryBars[2]);
3985
3986 /* Create the $winnt$.inf file */
3987 InstallSetupInfFile(&USetupData);
3988
3989 /* Go display the next page */
3990 return REGISTRY_PAGE;
3991 }
3992
3993
3994 /*
3995 * Displays the RegistryPage.
3996 *
3997 * Next pages:
3998 * SuccessPage (if RepairUpdate)
3999 * BootLoaderPage (default)
4000 * QuitPage
4001 *
4002 * SIDEEFFECTS
4003 * Calls RegInitializeRegistry
4004 * Calls ImportRegistryFile
4005 * Calls SetDefaultPagefile
4006 * Calls SetMountedDeviceValues
4007 *
4008 * RETURNS
4009 * Number of the next page.
4010 */
4011 static PAGE_NUMBER
4012 RegistryPage(PINPUT_RECORD Ir)
4013 {
4014 NTSTATUS Status;
4015 INFCONTEXT InfContext;
4016 PWSTR Action;
4017 PWSTR File;
4018 PWSTR Section;
4019 BOOLEAN Success;
4020 BOOLEAN ShouldRepairRegistry = FALSE;
4021 BOOLEAN Delete;
4022
4023 MUIDisplayPage(REGISTRY_PAGE);
4024
4025 if (RepairUpdateFlag)
4026 {
4027 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n");
4028
4029 /* Verify the registry hives and check whether we need to update or repair any of them */
4030 Status = VerifyRegistryHives(&USetupData.DestinationPath, &ShouldRepairRegistry);
4031 if (!NT_SUCCESS(Status))
4032 {
4033 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status);
4034 ShouldRepairRegistry = FALSE;
4035 }
4036 if (!ShouldRepairRegistry)
4037 DPRINT1("No need to repair the registry\n");
4038 }
4039
4040 DoUpdate:
4041 /* Update the registry */
4042 CONSOLE_SetStatusText(MUIGetString(STRING_REGHIVEUPDATE));
4043
4044 /* Initialize the registry and setup the registry hives */
4045 Status = RegInitializeRegistry(&USetupData.DestinationPath);
4046 if (!NT_SUCCESS(Status))
4047 {
4048 DPRINT1("RegInitializeRegistry() failed\n");
4049 /********** HACK!!!!!!!!!!! **********/
4050 if (Status == STATUS_NOT_IMPLEMENTED)
4051 {
4052 /* The hack was called, display its corresponding error */
4053 MUIDisplayError(ERROR_INITIALIZE_REGISTRY, Ir, POPUP_WAIT_ENTER);
4054 }
4055 else
4056 /*************************************/
4057 {
4058 /* Something else failed */
4059 MUIDisplayError(ERROR_CREATE_HIVE, Ir, POPUP_WAIT_ENTER);
4060 }
4061 return QUIT_PAGE;
4062 }
4063
4064 if (!RepairUpdateFlag || ShouldRepairRegistry)
4065 {
4066 /*
4067 * We fully setup the hives, in case we are doing a fresh installation
4068 * (RepairUpdateFlag == FALSE), or in case we are doing an update
4069 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to
4070 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE).
4071 */
4072
4073 Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Fresh", NULL, &InfContext); // Windows-compatible
4074 if (!Success)
4075 Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Install", NULL, &InfContext); // ReactOS-specific
4076
4077 if (!Success)
4078 {
4079 DPRINT1("SetupFindFirstLine() failed\n");
4080 MUIDisplayError(ERROR_FIND_REGISTRY, Ir, POPUP_WAIT_ENTER);
4081 goto Cleanup;
4082 }
4083 }
4084 else // if (RepairUpdateFlag && !ShouldRepairRegistry)
4085 {
4086 /*
4087 * In case we are doing an update (RepairUpdateFlag == TRUE) and
4088 * NO registry hives need a repair (ShouldRepairRegistry == FALSE),
4089 * we only update the hives.
4090 */
4091
4092 Success = SetupFindFirstLineW(SetupInf, L"HiveInfs.Upgrade", NULL, &InfContext);
4093 if (!Success)
4094 {
4095 /* Nothing to do for update! */
4096 DPRINT1("No update needed for the registry!\n");
4097 goto Cleanup;
4098 }
4099 }
4100
4101 do
4102 {
4103 INF_GetDataField(&InfContext, 0, &Action);
4104 INF_GetDataField(&InfContext, 1, &File);
4105 INF_GetDataField(&InfContext, 2, &Section);
4106
4107 DPRINT("Action: %S File: %S Section %S\n", Action, File, Section);
4108
4109 if (Action == NULL)
4110 {
4111 INF_FreeData(Action);
4112 INF_FreeData(File);
4113 INF_FreeData(Section);
4114 break; // Hackfix
4115 }
4116
4117 if (!_wcsicmp(Action, L"AddReg"))
4118 Delete = FALSE;
4119 else if (!_wcsicmp(Action, L"DelReg"))
4120 Delete = TRUE;
4121 else
4122 {
4123 DPRINT1("Unrecognized registry INF action '%S'\n", Action);
4124 INF_FreeData(Action);
4125 INF_FreeData(File);
4126 INF_FreeData(Section);
4127 continue;
4128 }
4129
4130 INF_FreeData(Action);
4131
4132 CONSOLE_SetStatusText(MUIGetString(STRING_IMPORTFILE), File);
4133
4134 if (!ImportRegistryFile(USetupData.SourcePath.Buffer, File, Section, USetupData.LanguageId, Delete))
4135 {
4136 DPRINT1("Importing %S failed\n", File);
4137 INF_FreeData(File);
4138 INF_FreeData(Section);
4139 MUIDisplayError(ERROR_IMPORT_HIVE, Ir, POPUP_WAIT_ENTER);
4140 goto Cleanup;
4141 }
4142 } while (SetupFindNextLine(&InfContext, &InfContext));
4143
4144 if (!RepairUpdateFlag || ShouldRepairRegistry)
4145 {
4146 /* See the explanation for this test above */
4147
4148 /* Update display registry settings */
4149 CONSOLE_SetStatusText(MUIGetString(STRING_DISPLAYETTINGSUPDATE));
4150 if (!ProcessDisplayRegistry(SetupInf, DisplayList))
4151 {
4152 MUIDisplayError(ERROR_UPDATE_DISPLAY_SETTINGS, Ir, POPUP_WAIT_ENTER);
4153 goto Cleanup;
4154 }
4155
4156 /* Set the locale */
4157 CONSOLE_SetStatusText(MUIGetString(STRING_LOCALESETTINGSUPDATE));
4158 if (!ProcessLocaleRegistry(LanguageList))
4159 {
4160 MUIDisplayError(ERROR_UPDATE_LOCALESETTINGS, Ir, POPUP_WAIT_ENTER);
4161 goto Cleanup;
4162 }
4163
4164 /* Add keyboard layouts */
4165 CONSOLE_SetStatusText(MUIGetString(STRING_ADDKBLAYOUTS));
4166 if (!AddKeyboardLayouts())
4167 {
4168 MUIDisplayError(ERROR_ADDING_KBLAYOUTS, Ir, POPUP_WAIT_ENTER);
4169 goto Cleanup;
4170 }
4171
4172 /* Set GeoID */
4173 if (!SetGeoID(MUIGetGeoID()))
4174 {
4175 MUIDisplayError(ERROR_UPDATE_GEOID, Ir, POPUP_WAIT_ENTER);
4176 goto Cleanup;
4177 }
4178
4179 if (!IsUnattendedSetup)
4180 {
4181 /* Update keyboard layout settings */
4182 CONSOLE_SetStatusText(MUIGetString(STRING_KEYBOARDSETTINGSUPDATE));
4183 if (!ProcessKeyboardLayoutRegistry(LayoutList))
4184 {
4185 MUIDisplayError(ERROR_UPDATE_KBSETTINGS, Ir, POPUP_WAIT_ENTER);
4186 goto Cleanup;
4187 }
4188 }
4189
4190 /* Add codepage information to registry */
4191 CONSOLE_SetStatusText(MUIGetString(STRING_CODEPAGEINFOUPDATE));
4192 if (!AddCodePage())
4193 {
4194 MUIDisplayError(ERROR_ADDING_CODEPAGE, Ir, POPUP_WAIT_ENTER);
4195 goto Cleanup;
4196 }
4197
4198 /* Set the default pagefile entry */
4199 SetDefaultPagefile(DestinationDriveLetter);
4200
4201 /* Update the mounted devices list */
4202 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
4203 SetMountedDeviceValues(PartitionList);
4204 }
4205
4206 Cleanup:
4207 //
4208 // TODO: Unload all the registry stuff, perform cleanup,
4209 // and copy the created hive files into .sav files.
4210 //
4211 RegCleanupRegistry(&USetupData.DestinationPath);
4212
4213 /*
4214 * Check whether we were in update/repair mode but we were actually
4215 * repairing the registry hives. If so, we have finished repairing them,
4216 * and we now reset the flag and run the proper registry update.
4217 * Otherwise we have finished the registry update!
4218 */
4219 if (RepairUpdateFlag && ShouldRepairRegistry)
4220 {
4221 ShouldRepairRegistry = FALSE;
4222 goto DoUpdate;
4223 }
4224
4225 if (NT_SUCCESS(Status))
4226 {
4227 CONSOLE_SetStatusText(MUIGetString(STRING_DONE));
4228 return BOOT_LOADER_PAGE;
4229 }
4230 else
4231 {
4232 return QUIT_PAGE;
4233 }
4234 }
4235
4236
4237 /*
4238 * Displays the BootLoaderPage.
4239 *
4240 * Next pages:
4241 * SuccessPage (if RepairUpdate)
4242 * BootLoaderHarddiskMbrPage
4243 * BootLoaderHarddiskVbrPage
4244 * BootLoaderFloppyPage
4245 * SuccessPage
4246 * QuitPage
4247 *
4248 * SIDEEFFECTS
4249 * Calls RegInitializeRegistry
4250 * Calls ImportRegistryFile
4251 * Calls SetDefaultPagefile
4252 * Calls SetMountedDeviceValues
4253 *
4254 * RETURNS
4255 * Number of the next page.
4256 */
4257 static PAGE_NUMBER
4258 BootLoaderPage(PINPUT_RECORD Ir)
4259 {
4260 UCHAR PartitionType;
4261 BOOLEAN InstallOnFloppy;
4262 USHORT Line = 12;
4263 WCHAR PathBuffer[MAX_PATH];
4264
4265 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4266
4267 RtlFreeUnicodeString(&USetupData.SystemRootPath);
4268 StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
4269 L"\\Device\\Harddisk%lu\\Partition%lu\\",
4270 PartitionList->SystemPartition->DiskEntry->DiskNumber,
4271 PartitionList->SystemPartition->PartitionNumber);
4272 RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer);
4273 DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath);
4274
4275 PartitionType = PartitionList->SystemPartition->PartitionType;
4276
4277 /* For unattended setup, skip MBR installation or install on floppy if needed */
4278 if (IsUnattendedSetup)
4279 {
4280 if ((USetupData.MBRInstallType == 0) ||
4281 (USetupData.MBRInstallType == 1))
4282 {
4283 goto Quit;
4284 }
4285 }
4286
4287 /*
4288 * We may install an MBR or VBR, but before that, check whether
4289 * we need to actually install the VBR on floppy.
4290 */
4291 if (PartitionType == PARTITION_ENTRY_UNUSED)
4292 {
4293 DPRINT("Error: system partition invalid (unused)\n");
4294 InstallOnFloppy = TRUE;
4295 }
4296 else if (PartitionType == PARTITION_OS2BOOTMGR)
4297 {
4298 /* OS/2 boot manager partition */
4299 DPRINT("Found OS/2 boot manager partition\n");
4300 InstallOnFloppy = TRUE;
4301 }
4302 else if (PartitionType == PARTITION_EXT2)
4303 {
4304 /* Linux EXT2 partition */
4305 DPRINT("Found Linux EXT2 partition\n");
4306 InstallOnFloppy = FALSE;
4307 }
4308 else if (PartitionType == PARTITION_IFS)
4309 {
4310 /* NTFS partition */
4311 DPRINT("Found NTFS partition\n");
4312
4313 // FIXME: Make it FALSE when we'll support NTFS installation!
4314 InstallOnFloppy = TRUE;
4315 }
4316 else if ((PartitionType == PARTITION_FAT_12) ||
4317 (PartitionType == PARTITION_FAT_16) ||
4318 (PartitionType == PARTITION_HUGE) ||
4319 (PartitionType == PARTITION_XINT13) ||
4320 (PartitionType == PARTITION_FAT32) ||
4321 (PartitionType == PARTITION_FAT32_XINT13))
4322 {
4323 DPRINT("Found FAT partition\n");
4324 InstallOnFloppy = FALSE;
4325 }
4326 else
4327 {
4328 /* Unknown partition */
4329 DPRINT("Unknown partition found\n");
4330 InstallOnFloppy = TRUE;
4331 }
4332
4333 /* We should install on floppy */
4334 if (InstallOnFloppy)
4335 {
4336 USetupData.MBRInstallType = 1;
4337 goto Quit;
4338 }
4339
4340 /* Is it an unattended install on hdd? */
4341 if (IsUnattendedSetup)
4342 {
4343 if ((USetupData.MBRInstallType == 2) ||
4344 (USetupData.MBRInstallType == 3))
4345 {
4346 goto Quit;
4347 }
4348 }
4349
4350 MUIDisplayPage(BOOT_LOADER_PAGE);
4351 CONSOLE_InvertTextXY(8, Line, 60, 1);
4352
4353 while (TRUE)
4354 {
4355 CONSOLE_ConInKey(Ir);
4356
4357 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4358 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */
4359 {
4360 CONSOLE_NormalTextXY(8, Line, 60, 1);
4361
4362 Line++;
4363 if (Line < 12)
4364 Line = 15;
4365
4366 if (Line > 15)
4367 Line = 12;
4368
4369 CONSOLE_InvertTextXY(8, Line, 60, 1);
4370 }
4371 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4372 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */
4373 {
4374 CONSOLE_NormalTextXY(8, Line, 60, 1);
4375
4376 Line--;
4377 if (Line < 12)
4378 Line = 15;
4379
4380 if (Line > 15)
4381 Line = 12;
4382
4383 CONSOLE_InvertTextXY(8, Line, 60, 1);
4384 }
4385 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4386 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4387 {
4388 if (ConfirmQuit(Ir))
4389 return QUIT_PAGE;
4390
4391 break;
4392 }
4393 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4394 {
4395 if (Line == 12)
4396 {
4397 /* Install on both MBR and VBR */
4398 USetupData.MBRInstallType = 2;
4399 break;
4400 }
4401 else if (Line == 13)
4402 {
4403 /* Install on VBR only */
4404 USetupData.MBRInstallType = 3;
4405 break;
4406 }
4407 else if (Line == 14)
4408 {
4409 /* Install on floppy */
4410 USetupData.MBRInstallType = 1;
4411 break;
4412 }
4413 else if (Line == 15)
4414 {
4415 /* Skip MBR installation */
4416 USetupData.MBRInstallType = 0;
4417 break;
4418 }
4419
4420 return BOOT_LOADER_PAGE;
4421 }
4422 }
4423
4424 Quit:
4425 switch (USetupData.MBRInstallType)
4426 {
4427 /* Skip MBR installation */
4428 case 0:
4429 return SUCCESS_PAGE;
4430
4431 /* Install on floppy */
4432 case 1:
4433 return BOOT_LOADER_FLOPPY_PAGE;
4434
4435 /* Install on both MBR and VBR */
4436 case 2:
4437 return BOOT_LOADER_HARDDISK_MBR_PAGE;
4438
4439 /* Install on VBR only */
4440 case 3:
4441 return BOOT_LOADER_HARDDISK_VBR_PAGE;
4442 }
4443
4444 return BOOT_LOADER_PAGE;
4445 }
4446
4447
4448 /*
4449 * Displays the BootLoaderFloppyPage.
4450 *
4451 * Next pages:
4452 * SuccessPage (At once)
4453 * QuitPage
4454 *
4455 * SIDEEFFECTS
4456 * Calls InstallFatBootcodeToFloppy()
4457 *
4458 * RETURNS
4459 * Number of the next page.
4460 */
4461 static PAGE_NUMBER
4462 BootLoaderFloppyPage(PINPUT_RECORD Ir)
4463 {
4464 NTSTATUS Status;
4465
4466 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE);
4467
4468 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT));
4469
4470 while (TRUE)
4471 {
4472 CONSOLE_ConInKey(Ir);
4473
4474 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
4475 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */
4476 {
4477 if (ConfirmQuit(Ir))
4478 return QUIT_PAGE;
4479
4480 break;
4481 }
4482 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4483 {
4484 if (DoesPathExist(NULL, L"\\Device\\Floppy0\\") == FALSE)
4485 {
4486 MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER);
4487 return BOOT_LOADER_FLOPPY_PAGE;
4488 }
4489
4490 Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath, &USetupData.DestinationArcPath);
4491 if (!NT_SUCCESS(Status))
4492 {
4493 /* Print error message */
4494 return BOOT_LOADER_FLOPPY_PAGE;
4495 }
4496
4497 return SUCCESS_PAGE;
4498 }
4499 }
4500
4501 return BOOT_LOADER_FLOPPY_PAGE;
4502 }
4503
4504
4505 /*
4506 * Displays the BootLoaderHarddiskVbrPage.
4507 *
4508 * Next pages:
4509 * SuccessPage (At once)
4510 * QuitPage
4511 *
4512 * SIDEEFFECTS
4513 * Calls InstallVBRToPartition()
4514 *
4515 * RETURNS
4516 * Number of the next page.
4517 */
4518 static PAGE_NUMBER
4519 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir)
4520 {
4521 NTSTATUS Status;
4522
4523 Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4524 &USetupData.SourceRootPath,
4525 &USetupData.DestinationArcPath,
4526 PartitionList->SystemPartition->PartitionType);
4527 if (!NT_SUCCESS(Status))
4528 {
4529 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
4530 return QUIT_PAGE;
4531 }
4532
4533 return SUCCESS_PAGE;
4534 }
4535
4536
4537 /*
4538 * Displays the BootLoaderHarddiskMbrPage.
4539 *
4540 * Next pages:
4541 * SuccessPage (At once)
4542 * QuitPage
4543 *
4544 * SIDEEFFECTS
4545 * Calls InstallVBRToPartition()
4546 * Calls InstallMbrBootCodeToDisk()
4547 *
4548 * RETURNS
4549 * Number of the next page.
4550 */
4551 static PAGE_NUMBER
4552 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir)
4553 {
4554 NTSTATUS Status;
4555 WCHAR DestinationDevicePathBuffer[MAX_PATH];
4556 WCHAR SourceMbrPathBuffer[MAX_PATH];
4557 WCHAR DstPath[MAX_PATH];
4558
4559 /* Step 1: Write the VBR */
4560 Status = InstallVBRToPartition(&USetupData.SystemRootPath,
4561 &USetupData.SourceRootPath,
4562 &USetupData.DestinationArcPath,
4563 PartitionList->SystemPartition->PartitionType);
4564 if (!NT_SUCCESS(Status))
4565 {
4566 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER);
4567 return QUIT_PAGE;
4568 }
4569
4570 /* Step 2: Write the MBR */
4571 StringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer),
4572 L"\\Device\\Harddisk%d\\Partition0",
4573 PartitionList->SystemPartition->DiskEntry->DiskNumber);
4574
4575 CombinePaths(SourceMbrPathBuffer, ARRAYSIZE(SourceMbrPathBuffer), 2, USetupData.SourceRootPath.Buffer, L"\\loader\\dosmbr.bin");
4576
4577 if (IsThereAValidBootSector(DestinationDevicePathBuffer))
4578 {
4579 /* Save current MBR */
4580 CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, USetupData.SystemRootPath.Buffer, L"mbr.old");
4581
4582 DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath);
4583 Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR));
4584 if (!NT_SUCCESS(Status))
4585 {
4586 DPRINT1("SaveBootSector() failed (Status %lx)\n", Status);
4587 // Don't care if we succeeded or not saving the old MBR, just go ahead.
4588 }
4589 }
4590
4591 DPRINT1("Install MBR bootcode: %S ==> %S\n",
4592 SourceMbrPathBuffer, DestinationDevicePathBuffer);
4593 Status = InstallMbrBootCodeToDisk(SourceMbrPathBuffer,
4594 DestinationDevicePathBuffer);
4595 if (!NT_SUCCESS(Status))
4596 {
4597 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
4598 Status);
4599 MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER);
4600 return QUIT_PAGE;
4601 }
4602
4603 return SUCCESS_PAGE;
4604 }
4605
4606
4607 /**
4608 * @name ProgressTimeOutStringHandler
4609 *
4610 * Handles the generation (displaying) of the timeout
4611 * countdown to the screen dynamically.
4612 *
4613 * @param Bar
4614 * A pointer to a progress bar.
4615 *
4616 * @param AlwaysUpdate
4617 * Constantly update the progress bar (boolean type).
4618 *
4619 * @param Buffer
4620 * A pointer to a string buffer.
4621 *
4622 * @param cchBufferSize
4623 * The buffer's size in number of characters.
4624 *
4625 * @return
4626 * TRUE or FALSE on function termination.
4627 *
4628 */
4629 static
4630 BOOLEAN NTAPI
4631 ProgressTimeOutStringHandler(
4632 IN PPROGRESSBAR Bar,
4633 IN BOOLEAN AlwaysUpdate,
4634 OUT PSTR Buffer,
4635 IN SIZE_T cchBufferSize)
4636 {
4637 ULONG OldProgress = Bar->Progress;
4638
4639 if (Bar->StepCount == 0)
4640 {
4641 Bar->Progress = 0;
4642 }
4643 else
4644 {
4645 Bar->Progress = Bar->StepCount - Bar->CurrentStep;
4646 }
4647
4648 /* Build the progress string if it has changed */
4649 if (Bar->ProgressFormatText &&
4650 (AlwaysUpdate || (Bar->Progress != OldProgress)))
4651 {
4652 RtlStringCchPrintfA(Buffer, cchBufferSize,
4653 Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1);
4654
4655 return TRUE;
4656 }
4657
4658 return FALSE;
4659 }
4660
4661 /**
4662 * @name ProgressCountdown
4663 *
4664 * Displays and draws a red-coloured progress bar with a countdown.
4665 * When the timeout is reached, the flush page is displayed for reboot.
4666 *
4667 * @param Ir
4668 * A pointer to an input keyboard record.
4669 *
4670 * @param TimeOut
4671 * Initial countdown value in seconds.
4672 *
4673 * @return
4674 * Nothing.
4675 *
4676 */
4677 static VOID
4678 ProgressCountdown(
4679 IN PINPUT_RECORD Ir,
4680 IN LONG TimeOut)
4681 {
4682 NTSTATUS Status;
4683 ULONG StartTime, BarWidth, TimerDiv;
4684 LONG TimeElapsed;
4685 LONG TimerValue, OldTimerValue;
4686 LARGE_INTEGER Timeout;
4687 PPROGRESSBAR ProgressBar;
4688 BOOLEAN RefreshProgress = TRUE;
4689
4690 /* Bail out if the timeout is already zero */
4691 if (TimeOut <= 0)
4692 return;
4693
4694 /* Create the timeout progress bar and set it up */
4695 ProgressBar = CreateProgressBarEx(13,
4696 26,
4697 xScreen - 13,
4698 yScreen - 20,
4699 10,
4700 24,
4701 TRUE,
4702 FOREGROUND_RED | BACKGROUND_BLUE,
4703 0,
4704 NULL,
4705 MUIGetString(STRING_REBOOTPROGRESSBAR),
4706 ProgressTimeOutStringHandler);
4707
4708 BarWidth = max(1, ProgressBar->Width);
4709 TimerValue = TimeOut * BarWidth;
4710 ProgressSetStepCount(ProgressBar, TimerValue);
4711
4712 StartTime = NtGetTickCount();
4713 CONSOLE_Flush();
4714
4715 TimerDiv = 1000 / BarWidth;
4716 TimerDiv = max(1, TimerDiv);
4717 OldTimerValue = TimerValue;
4718 while (TRUE)
4719 {
4720 /* Decrease the timer */
4721
4722 /*
4723 * Compute how much time the previous operations took.
4724 * This allows us in particular to take account for any time
4725 * elapsed if something slowed down.
4726 */
4727 TimeElapsed = NtGetTickCount() - StartTime;
4728 if (TimeElapsed >= TimerDiv)
4729 {
4730 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */
4731 TimeElapsed /= TimerDiv;
4732 StartTime += (TimerDiv * TimeElapsed);
4733
4734 if (TimeElapsed <= TimerValue)
4735 TimerValue -= TimeElapsed;
4736 else
4737 TimerValue = 0;
4738
4739 RefreshProgress = TRUE;
4740 }
4741
4742 if (RefreshProgress)
4743 {
4744 ProgressSetStep(ProgressBar, OldTimerValue - TimerValue);
4745 RefreshProgress = FALSE;
4746 }
4747
4748 /* Stop when the timer reaches zero */
4749 if (TimerValue <= 0)
4750 break;
4751
4752 /* Check for user key presses */
4753
4754 /*
4755 * If the timer is used, use a passive wait of maximum 1 second
4756 * while monitoring for incoming console input events, so that
4757 * we are still able to display the timing count.
4758 */
4759
4760 /* Wait a maximum of 1 second for input events */
4761 TimeElapsed = NtGetTickCount() - StartTime;
4762 if (TimeElapsed < TimerDiv)
4763 {
4764 /* Convert the time to NT Format */
4765 Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL;
4766 Status = NtWaitForSingleObject(StdInput, FALSE, &Timeout);
4767 }
4768 else
4769 {
4770 Status = STATUS_TIMEOUT;
4771 }
4772
4773 /* Check whether the input event has been signaled, or a timeout happened */
4774 if (Status == STATUS_TIMEOUT)
4775 {
4776 continue;
4777 }
4778 if (Status != STATUS_WAIT_0)
4779 {
4780 /* An error happened, bail out */
4781 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status);
4782 break;
4783 }
4784
4785 /* Check for an ENTER key press */
4786 while (CONSOLE_ConInKeyPeek(Ir))
4787 {
4788 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */
4789 {
4790 /* Found it, stop waiting */
4791 goto Exit;
4792 }
4793 }
4794 }
4795
4796 Exit:
4797 /* Destroy the progress bar and quit */
4798 DestroyProgressBar(ProgressBar);
4799 }
4800
4801
4802 /*
4803 * Displays the QuitPage.
4804 *
4805 * Next pages:
4806 * FlushPage (At once)
4807 *
4808 * SIDEEFFECTS
4809 * Destroy the Lists
4810 *
4811 * RETURNS
4812 * Number of the next page.
4813 */
4814 static PAGE_NUMBER
4815 QuitPage(PINPUT_RECORD Ir)
4816 {
4817 MUIDisplayPage(QUIT_PAGE);
4818
4819 /* Destroy the NTOS installations list */
4820 if (NtOsInstallsList != NULL)
4821 {
4822 DestroyGenericList(NtOsInstallsList, TRUE);
4823 NtOsInstallsList = NULL;
4824 }
4825
4826 /* Destroy the partition list */
4827 if (PartitionList != NULL)
4828 {
4829 DestroyPartitionList(PartitionList);
4830 PartitionList = NULL;
4831 }
4832 TempPartition = NULL;
4833 FormatState = Start;
4834
4835 /* Destroy the filesystem list */
4836 if (FileSystemList != NULL)
4837 {
4838 DestroyFileSystemList(FileSystemList);
4839 FileSystemList = NULL;
4840 }
4841
4842 /* Destroy the computer settings list */
4843 if (ComputerList != NULL)
4844 {
4845 DestroyGenericList(ComputerList, TRUE);
4846 ComputerList = NULL;
4847 }
4848
4849 /* Destroy the display settings list */
4850 if (DisplayList != NULL)
4851 {
4852 DestroyGenericList(DisplayList, TRUE);
4853 DisplayList = NULL;
4854 }
4855
4856 /* Destroy the keyboard settings list */
4857 if (KeyboardList != NULL)
4858 {
4859 DestroyGenericList(KeyboardList, TRUE);
4860 KeyboardList = NULL;
4861 }
4862
4863 /* Destroy the keyboard layout list */
4864 if (LayoutList != NULL)
4865 {
4866 DestroyGenericList(LayoutList, TRUE);
4867 LayoutList = NULL;
4868 }
4869
4870 /* Destroy the languages list */
4871 if (LanguageList != NULL)
4872 {
4873 DestroyGenericList(LanguageList, FALSE);
4874 LanguageList = NULL;
4875 }
4876
4877 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2));
4878
4879 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4880 ProgressCountdown(Ir, 15);
4881 return FLUSH_PAGE;
4882 }
4883
4884
4885 /*
4886 * Displays the SuccessPage.
4887 *
4888 * Next pages:
4889 * FlushPage (At once)
4890 *
4891 * SIDEEFFECTS
4892 * Destroy the Lists
4893 *
4894 * RETURNS
4895 * Number of the next page.
4896 */
4897 static PAGE_NUMBER
4898 SuccessPage(PINPUT_RECORD Ir)
4899 {
4900 MUIDisplayPage(SUCCESS_PAGE);
4901
4902 if (IsUnattendedSetup)
4903 return FLUSH_PAGE;
4904
4905 /* Wait for maximum 15 seconds or an ENTER key before quitting */
4906 ProgressCountdown(Ir, 15);
4907 return FLUSH_PAGE;
4908 }
4909
4910
4911 /*
4912 * Displays the FlushPage.
4913 *
4914 * Next pages:
4915 * RebootPage (At once)
4916 *
4917 * RETURNS
4918 * Number of the next page.
4919 */
4920 static PAGE_NUMBER
4921 FlushPage(PINPUT_RECORD Ir)
4922 {
4923 MUIDisplayPage(FLUSH_PAGE);
4924 return REBOOT_PAGE;
4925 }
4926
4927
4928 DWORD WINAPI
4929 PnpEventThread(IN LPVOID lpParameter);
4930
4931
4932 /*
4933 * The start routine and page management
4934 */
4935 NTSTATUS
4936 RunUSetup(VOID)
4937 {
4938 NTSTATUS Status;
4939 INPUT_RECORD Ir;
4940 PAGE_NUMBER Page;
4941 BOOLEAN Old;
4942
4943 InfSetHeap(ProcessHeap);
4944
4945 /* Tell the Cm this is a setup boot, and it has to behave accordingly */
4946 Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP);
4947 if (!NT_SUCCESS(Status))
4948 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status);
4949
4950 /* Create the PnP thread in suspended state */
4951 Status = RtlCreateUserThread(NtCurrentProcess(),
4952 NULL,
4953 TRUE,
4954 0,
4955 0,
4956 0,
4957 PnpEventThread,
4958 &SetupInf,
4959 &hPnpThread,
4960 NULL);
4961 if (!NT_SUCCESS(Status))
4962 hPnpThread = NULL;
4963
4964 if (!CONSOLE_Init())
4965 {
4966 PrintString(MUIGetString(STRING_CONSOLEFAIL1));
4967 PrintString(MUIGetString(STRING_CONSOLEFAIL2));
4968 PrintString(MUIGetString(STRING_CONSOLEFAIL3));
4969
4970 /* We failed to initialize the video, just quit the installer */
4971 return STATUS_APP_INIT_FAILURE;
4972 }
4973
4974 /* Initialize global unicode strings */
4975 RtlInitUnicodeString(&USetupData.SourcePath, NULL);
4976 RtlInitUnicodeString(&USetupData.SourceRootPath, NULL);
4977 RtlInitUnicodeString(&USetupData.SourceRootDir, NULL);
4978 RtlInitUnicodeString(&InstallPath, NULL);
4979 RtlInitUnicodeString(&USetupData.DestinationPath, NULL);
4980 RtlInitUnicodeString(&USetupData.DestinationArcPath, NULL);
4981 RtlInitUnicodeString(&USetupData.DestinationRootPath, NULL);
4982 RtlInitUnicodeString(&USetupData.SystemRootPath, NULL);
4983
4984 /* Hide the cursor */
4985 CONSOLE_SetCursorType(TRUE, FALSE);
4986
4987 /* Global Initialization page */
4988 CONSOLE_ClearScreen();
4989 CONSOLE_Flush();
4990 Page = SetupStartPage(&Ir);
4991
4992 while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE)
4993 {
4994 CONSOLE_ClearScreen();
4995 CONSOLE_Flush();
4996
4997 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup ");
4998 // CONSOLE_Flush();
4999
5000 switch (Page)
5001 {
5002 /* Language page */
5003 case LANGUAGE_PAGE:
5004 Page = LanguagePage(&Ir);
5005 break;
5006
5007 /* Welcome page */
5008 case WELCOME_PAGE:
5009 Page = WelcomePage(&Ir);
5010 break;
5011
5012 /* License page */
5013 case LICENSE_PAGE:
5014 Page = LicensePage(&Ir);
5015 break;
5016
5017 /* Install pages */
5018 case INSTALL_INTRO_PAGE:
5019 Page = InstallIntroPage(&Ir);
5020 break;
5021
5022 #if 0
5023 case SCSI_CONTROLLER_PAGE:
5024 Page = ScsiControllerPage(&Ir);
5025 break;
5026
5027 case OEM_DRIVER_PAGE:
5028 Page = OemDriverPage(&Ir);
5029 break;
5030 #endif
5031
5032 case DEVICE_SETTINGS_PAGE:
5033 Page = DeviceSettingsPage(&Ir);
5034 break;
5035
5036 case COMPUTER_SETTINGS_PAGE:
5037 Page = ComputerSettingsPage(&Ir);
5038 break;
5039
5040 case DISPLAY_SETTINGS_PAGE:
5041 Page = DisplaySettingsPage(&Ir);
5042 break;
5043
5044 case KEYBOARD_SETTINGS_PAGE:
5045 Page = KeyboardSettingsPage(&Ir);
5046 break;
5047
5048 case LAYOUT_SETTINGS_PAGE:
5049 Page = LayoutSettingsPage(&Ir);
5050 break;
5051
5052 case SELECT_PARTITION_PAGE:
5053 Page = SelectPartitionPage(&Ir);
5054 break;
5055
5056 case CREATE_PRIMARY_PARTITION_PAGE:
5057 Page = CreatePrimaryPartitionPage(&Ir);
5058 break;
5059
5060 case CREATE_EXTENDED_PARTITION_PAGE:
5061 Page = CreateExtendedPartitionPage(&Ir);
5062 break;
5063
5064 case CREATE_LOGICAL_PARTITION_PAGE:
5065 Page = CreateLogicalPartitionPage(&Ir);
5066 break;
5067
5068 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE:
5069 Page = ConfirmDeleteSystemPartitionPage(&Ir);
5070 break;
5071
5072 case DELETE_PARTITION_PAGE:
5073 Page = DeletePartitionPage(&Ir);
5074 break;
5075
5076 case SELECT_FILE_SYSTEM_PAGE:
5077 Page = SelectFileSystemPage(&Ir);
5078 break;
5079
5080 case FORMAT_PARTITION_PAGE:
5081 Page = FormatPartitionPage(&Ir);
5082 break;
5083
5084 case CHECK_FILE_SYSTEM_PAGE:
5085 Page = CheckFileSystemPage(&Ir);
5086 break;
5087
5088 case INSTALL_DIRECTORY_PAGE:
5089 Page = InstallDirectoryPage(&Ir);
5090 break;
5091
5092 case PREPARE_COPY_PAGE:
5093 Page = PrepareCopyPage(&Ir);
5094 break;
5095
5096 case FILE_COPY_PAGE:
5097 Page = FileCopyPage(&Ir);
5098 break;
5099
5100 case REGISTRY_PAGE:
5101 Page = RegistryPage(&Ir);
5102 break;
5103
5104 case BOOT_LOADER_PAGE:
5105 Page = BootLoaderPage(&Ir);
5106 break;
5107
5108 case BOOT_LOADER_FLOPPY_PAGE:
5109 Page = BootLoaderFloppyPage(&Ir);
5110 break;
5111
5112 case BOOT_LOADER_HARDDISK_MBR_PAGE:
5113 Page = BootLoaderHarddiskMbrPage(&Ir);
5114 break;
5115
5116 case BOOT_LOADER_HARDDISK_VBR_PAGE:
5117 Page = BootLoaderHarddiskVbrPage(&Ir);
5118 break;
5119
5120 /* Repair pages */
5121 case REPAIR_INTRO_PAGE:
5122 Page = RepairIntroPage(&Ir);
5123 break;
5124
5125 case UPGRADE_REPAIR_PAGE:
5126 Page = UpgradeRepairPage(&Ir);
5127 break;
5128
5129 case SUCCESS_PAGE:
5130 Page = SuccessPage(&Ir);
5131 break;
5132
5133 case FLUSH_PAGE:
5134 Page = FlushPage(&Ir);
5135 break;
5136
5137 case QUIT_PAGE:
5138 Page = QuitPage(&Ir);
5139 break;
5140
5141 case RECOVERY_PAGE:
5142 case REBOOT_PAGE:
5143 break;
5144 }
5145 }
5146
5147 SetupCloseInfFile(SetupInf);
5148
5149 if (Page == RECOVERY_PAGE)
5150 RecoveryConsole();
5151
5152 FreeConsole();
5153
5154 /* Reboot */
5155 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old);
5156 NtShutdownSystem(ShutdownReboot);
5157 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old);
5158
5159 return STATUS_SUCCESS;
5160 }
5161
5162
5163 VOID NTAPI
5164 NtProcessStartup(PPEB Peb)
5165 {
5166 NTSTATUS Status;
5167 LARGE_INTEGER Time;
5168
5169 RtlNormalizeProcessParams(Peb->ProcessParameters);
5170
5171 ProcessHeap = Peb->ProcessHeap;
5172
5173 NtQuerySystemTime(&Time);
5174
5175 Status = RunUSetup();
5176
5177 if (NT_SUCCESS(Status))
5178 {
5179 /*
5180 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing
5181 * a protective waiting.
5182 * This wait is needed because, since we are started as SMSS.EXE,
5183 * the NT kernel explicitly waits 5 seconds for the initial process
5184 * SMSS.EXE to initialize (as a protective measure), and otherwise
5185 * bugchecks with the code SESSION5_INITIALIZATION_FAILED.
5186 */
5187 Time.QuadPart += 50000000;
5188 NtDelayExecution(FALSE, &Time);
5189 }
5190 else
5191 {
5192 /* The installer failed to start: raise a hard error (crash the system/BSOD) */
5193 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED,
5194 0, 0, NULL, 0, NULL);
5195 }
5196
5197 NtTerminateProcess(NtCurrentProcess(), Status);
5198 }
5199
5200 /* EOF */