1 /* 2 * ReactOS kernel 3 * Copyright (C) 2002, 2003, 2004 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 /* 20 * COPYRIGHT: See COPYING in the top level directory 21 * PROJECT: ReactOS text-mode setup 22 * FILE: base/setup/usetup/usetup.c 23 * PURPOSE: Text-mode setup 24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 25 * Hervé Poussineau (hpoussin@reactos.org) 26 */ 27 28 #include <usetup.h> 29 #include <math.h> 30 #include <ntstrsafe.h> 31 32 #include "bootsup.h" 33 #include "chkdsk.h" 34 #include "cmdcons.h" 35 #include "devinst.h" 36 #include "format.h" 37 38 #define NDEBUG 39 #include <debug.h> 40 41 42 /* GLOBALS & LOCALS *********************************************************/ 43 44 HANDLE ProcessHeap; 45 BOOLEAN IsUnattendedSetup = FALSE; 46 47 static USETUP_DATA USetupData; 48 49 /* Partition where to perform the installation */ 50 static PPARTENTRY InstallPartition = NULL; 51 // static PPARTENTRY SystemPartition = NULL; // The system partition we will actually use (can be different from PartitionList->SystemPartition in case we install on removable disk) 52 53 // FIXME: Is it really useful?? Just used for SetDefaultPagefile... 54 static WCHAR DestinationDriveLetter; 55 56 57 /* OTHER Stuff *****/ 58 59 PCWSTR SelectedLanguageId; 60 static WCHAR DefaultLanguage[20]; // Copy of string inside LanguageList 61 static WCHAR DefaultKBLayout[20]; // Copy of string inside KeyboardList 62 63 static BOOLEAN RepairUpdateFlag = FALSE; 64 65 /* Global partition list on the system */ 66 static PPARTLIST PartitionList = NULL; 67 68 /* Currently selected partition entry in the list */ 69 static PPARTENTRY CurrentPartition = NULL; 70 71 /* List of supported file systems for the partition to be formatted */ 72 static PFILE_SYSTEM_LIST FileSystemList = NULL; 73 74 /* Machine state for the formatter */ 75 static PPARTENTRY TempPartition = NULL; 76 static FORMATMACHINESTATE FormatState = Start; 77 78 /*****************************************************/ 79 80 static PNTOS_INSTALLATION CurrentInstallation = NULL; 81 static PGENERIC_LIST NtOsInstallsList = NULL; 82 83 84 /* FUNCTIONS ****************************************************************/ 85 86 static VOID 87 PrintString(char* fmt,...) 88 { 89 char buffer[512]; 90 va_list ap; 91 UNICODE_STRING UnicodeString; 92 ANSI_STRING AnsiString; 93 94 va_start(ap, fmt); 95 vsprintf(buffer, fmt, ap); 96 va_end(ap); 97 98 RtlInitAnsiString(&AnsiString, buffer); 99 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE); 100 NtDisplayString(&UnicodeString); 101 RtlFreeUnicodeString(&UnicodeString); 102 } 103 104 105 static VOID 106 DrawBox(IN SHORT xLeft, 107 IN SHORT yTop, 108 IN SHORT Width, 109 IN SHORT Height) 110 { 111 COORD coPos; 112 DWORD Written; 113 114 /* Draw upper left corner */ 115 coPos.X = xLeft; 116 coPos.Y = yTop; 117 FillConsoleOutputCharacterA(StdOutput, 118 0xDA, // '+', 119 1, 120 coPos, 121 &Written); 122 123 /* Draw upper edge */ 124 coPos.X = xLeft + 1; 125 coPos.Y = yTop; 126 FillConsoleOutputCharacterA(StdOutput, 127 0xC4, // '-', 128 Width - 2, 129 coPos, 130 &Written); 131 132 /* Draw upper right corner */ 133 coPos.X = xLeft + Width - 1; 134 coPos.Y = yTop; 135 FillConsoleOutputCharacterA(StdOutput, 136 0xBF, // '+', 137 1, 138 coPos, 139 &Written); 140 141 /* Draw right edge, inner space and left edge */ 142 for (coPos.Y = yTop + 1; coPos.Y < yTop + Height - 1; coPos.Y++) 143 { 144 coPos.X = xLeft; 145 FillConsoleOutputCharacterA(StdOutput, 146 0xB3, // '|', 147 1, 148 coPos, 149 &Written); 150 151 coPos.X = xLeft + 1; 152 FillConsoleOutputCharacterA(StdOutput, 153 ' ', 154 Width - 2, 155 coPos, 156 &Written); 157 158 coPos.X = xLeft + Width - 1; 159 FillConsoleOutputCharacterA(StdOutput, 160 0xB3, // '|', 161 1, 162 coPos, 163 &Written); 164 } 165 166 /* Draw lower left corner */ 167 coPos.X = xLeft; 168 coPos.Y = yTop + Height - 1; 169 FillConsoleOutputCharacterA(StdOutput, 170 0xC0, // '+', 171 1, 172 coPos, 173 &Written); 174 175 /* Draw lower edge */ 176 coPos.X = xLeft + 1; 177 coPos.Y = yTop + Height - 1; 178 FillConsoleOutputCharacterA(StdOutput, 179 0xC4, // '-', 180 Width - 2, 181 coPos, 182 &Written); 183 184 /* Draw lower right corner */ 185 coPos.X = xLeft + Width - 1; 186 coPos.Y = yTop + Height - 1; 187 FillConsoleOutputCharacterA(StdOutput, 188 0xD9, // '+', 189 1, 190 coPos, 191 &Written); 192 } 193 194 195 VOID 196 PopupError(PCCH Text, 197 PCCH Status, 198 PINPUT_RECORD Ir, 199 ULONG WaitEvent) 200 { 201 SHORT yTop; 202 SHORT xLeft; 203 COORD coPos; 204 DWORD Written; 205 ULONG Length; 206 ULONG MaxLength; 207 ULONG Lines; 208 PCHAR p; 209 PCCH pnext; 210 BOOLEAN LastLine; 211 SHORT Width; 212 SHORT Height; 213 214 /* Count text lines and longest line */ 215 MaxLength = 0; 216 Lines = 0; 217 pnext = Text; 218 219 while (TRUE) 220 { 221 p = strchr(pnext, '\n'); 222 223 if (p == NULL) 224 { 225 Length = strlen(pnext); 226 LastLine = TRUE; 227 } 228 else 229 { 230 Length = (ULONG)(p - pnext); 231 LastLine = FALSE; 232 } 233 234 Lines++; 235 236 if (Length > MaxLength) 237 MaxLength = Length; 238 239 if (LastLine) 240 break; 241 242 pnext = p + 1; 243 } 244 245 /* Check length of status line */ 246 if (Status != NULL) 247 { 248 Length = strlen(Status); 249 250 if (Length > MaxLength) 251 MaxLength = Length; 252 } 253 254 Width = MaxLength + 4; 255 Height = Lines + 2; 256 257 if (Status != NULL) 258 Height += 2; 259 260 yTop = (yScreen - Height) / 2; 261 xLeft = (xScreen - Width) / 2; 262 263 264 /* Set screen attributes */ 265 coPos.X = xLeft; 266 for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++) 267 { 268 FillConsoleOutputAttribute(StdOutput, 269 FOREGROUND_RED | BACKGROUND_WHITE, 270 Width, 271 coPos, 272 &Written); 273 } 274 275 DrawBox(xLeft, yTop, Width, Height); 276 277 /* Print message text */ 278 coPos.Y = yTop + 1; 279 pnext = Text; 280 while (TRUE) 281 { 282 p = strchr(pnext, '\n'); 283 284 if (p == NULL) 285 { 286 Length = strlen(pnext); 287 LastLine = TRUE; 288 } 289 else 290 { 291 Length = (ULONG)(p - pnext); 292 LastLine = FALSE; 293 } 294 295 if (Length != 0) 296 { 297 coPos.X = xLeft + 2; 298 WriteConsoleOutputCharacterA(StdOutput, 299 pnext, 300 Length, 301 coPos, 302 &Written); 303 } 304 305 if (LastLine) 306 break; 307 308 coPos.Y++; 309 pnext = p + 1; 310 } 311 312 /* Print separator line and status text */ 313 if (Status != NULL) 314 { 315 coPos.Y = yTop + Height - 3; 316 coPos.X = xLeft; 317 FillConsoleOutputCharacterA(StdOutput, 318 0xC3, // '+', 319 1, 320 coPos, 321 &Written); 322 323 coPos.X = xLeft + 1; 324 FillConsoleOutputCharacterA(StdOutput, 325 0xC4, // '-', 326 Width - 2, 327 coPos, 328 &Written); 329 330 coPos.X = xLeft + Width - 1; 331 FillConsoleOutputCharacterA(StdOutput, 332 0xB4, // '+', 333 1, 334 coPos, 335 &Written); 336 337 coPos.Y++; 338 coPos.X = xLeft + 2; 339 WriteConsoleOutputCharacterA(StdOutput, 340 Status, 341 min(strlen(Status), (SIZE_T)Width - 4), 342 coPos, 343 &Written); 344 } 345 346 if (WaitEvent == POPUP_WAIT_NONE) 347 return; 348 349 while (TRUE) 350 { 351 CONSOLE_ConInKey(Ir); 352 353 if (WaitEvent == POPUP_WAIT_ANY_KEY || 354 Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) 355 { 356 return; 357 } 358 } 359 } 360 361 362 /* 363 * Confirm quit setup 364 * RETURNS 365 * TRUE: Quit setup. 366 * FALSE: Don't quit setup. 367 */ 368 static BOOL 369 ConfirmQuit(PINPUT_RECORD Ir) 370 { 371 BOOL Result = FALSE; 372 MUIDisplayError(ERROR_NOT_INSTALLED, NULL, POPUP_WAIT_NONE); 373 374 while (TRUE) 375 { 376 CONSOLE_ConInKey(Ir); 377 378 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 379 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 380 { 381 Result = TRUE; 382 break; 383 } 384 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 385 { 386 Result = FALSE; 387 break; 388 } 389 } 390 391 return Result; 392 } 393 394 395 static VOID 396 UpdateKBLayout(VOID) 397 { 398 PGENERIC_LIST_ENTRY ListEntry; 399 PCWSTR pszNewLayout; 400 401 pszNewLayout = MUIDefaultKeyboardLayout(SelectedLanguageId); 402 403 if (USetupData.LayoutList == NULL) 404 { 405 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout); 406 if (USetupData.LayoutList == NULL) 407 { 408 /* FIXME: Handle error! */ 409 return; 410 } 411 } 412 413 /* Search for default layout (if provided) */ 414 if (pszNewLayout != NULL) 415 { 416 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry; 417 ListEntry = GetNextListEntry(ListEntry)) 418 { 419 if (!wcscmp(pszNewLayout, ((PGENENTRY)GetListEntryData(ListEntry))->Id)) 420 { 421 SetCurrentListEntry(USetupData.LayoutList, ListEntry); 422 break; 423 } 424 } 425 } 426 } 427 428 429 static NTSTATUS 430 NTAPI 431 GetSettingDescription( 432 IN PGENERIC_LIST_ENTRY Entry, 433 OUT PSTR Buffer, 434 IN SIZE_T cchBufferSize) 435 { 436 return RtlStringCchPrintfA(Buffer, cchBufferSize, "%S", 437 ((PGENENTRY)GetListEntryData(Entry))->Value); 438 } 439 440 static NTSTATUS 441 NTAPI 442 GetNTOSInstallationName( 443 IN PGENERIC_LIST_ENTRY Entry, 444 OUT PSTR Buffer, 445 IN SIZE_T cchBufferSize) 446 { 447 PNTOS_INSTALLATION NtOsInstall = (PNTOS_INSTALLATION)GetListEntryData(Entry); 448 PPARTENTRY PartEntry = NtOsInstall->PartEntry; 449 450 if (PartEntry && PartEntry->DriveLetter) 451 { 452 /* We have retrieved a partition that is mounted */ 453 return RtlStringCchPrintfA(Buffer, cchBufferSize, 454 "%C:%S \"%S\"", 455 PartEntry->DriveLetter, 456 NtOsInstall->PathComponent, 457 NtOsInstall->InstallationName); 458 } 459 else 460 { 461 /* We failed somewhere, just show the NT path */ 462 return RtlStringCchPrintfA(Buffer, cchBufferSize, 463 "%wZ \"%S\"", 464 &NtOsInstall->SystemNtPath, 465 NtOsInstall->InstallationName); 466 } 467 } 468 469 470 /* 471 * Displays the LanguagePage. 472 * 473 * Next pages: WelcomePage, QuitPage 474 * 475 * SIDEEFFECTS 476 * Init SelectedLanguageId 477 * Init USetupData.LanguageId 478 * 479 * RETURNS 480 * Number of the next page. 481 */ 482 static PAGE_NUMBER 483 LanguagePage(PINPUT_RECORD Ir) 484 { 485 GENERIC_LIST_UI ListUi; 486 PCWSTR NewLanguageId; 487 BOOL RefreshPage = FALSE; 488 489 /* Initialize the computer settings list */ 490 if (USetupData.LanguageList == NULL) 491 { 492 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage); 493 if (USetupData.LanguageList == NULL) 494 { 495 PopupError("Setup failed to initialize available translations", NULL, NULL, POPUP_WAIT_NONE); 496 return WELCOME_PAGE; 497 } 498 } 499 500 SelectedLanguageId = DefaultLanguage; 501 USetupData.LanguageId = 0; 502 503 /* Load the font */ 504 SetConsoleCodePage(); 505 UpdateKBLayout(); 506 507 /* 508 * If there is no language or just a single one in the list, 509 * skip the language selection process altogether. 510 */ 511 if (GetNumberOfListEntries(USetupData.LanguageList) <= 1) 512 { 513 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF); 514 return WELCOME_PAGE; 515 } 516 517 InitGenericListUi(&ListUi, USetupData.LanguageList, GetSettingDescription); 518 DrawGenericList(&ListUi, 519 2, 18, 520 xScreen - 3, 521 yScreen - 3); 522 523 ScrollToPositionGenericList(&ListUi, GetDefaultLanguageIndex()); 524 525 MUIDisplayPage(LANGUAGE_PAGE); 526 527 while (TRUE) 528 { 529 CONSOLE_ConInKey(Ir); 530 531 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 532 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 533 { 534 ScrollDownGenericList(&ListUi); 535 RefreshPage = TRUE; 536 } 537 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 538 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 539 { 540 ScrollUpGenericList(&ListUi); 541 RefreshPage = TRUE; 542 } 543 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 544 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */ 545 { 546 ScrollPageDownGenericList(&ListUi); 547 RefreshPage = TRUE; 548 } 549 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 550 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */ 551 { 552 ScrollPageUpGenericList(&ListUi); 553 RefreshPage = TRUE; 554 } 555 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 556 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 557 { 558 if (ConfirmQuit(Ir)) 559 return QUIT_PAGE; 560 else 561 RedrawGenericList(&ListUi); 562 } 563 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 564 { 565 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1); 566 567 SelectedLanguageId = 568 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id; 569 570 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF); 571 572 if (wcscmp(SelectedLanguageId, DefaultLanguage)) 573 { 574 UpdateKBLayout(); 575 } 576 577 /* Load the font */ 578 SetConsoleCodePage(); 579 580 return WELCOME_PAGE; 581 } 582 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) 583 { 584 /* a-z */ 585 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar); 586 RefreshPage = TRUE; 587 } 588 589 if (RefreshPage) 590 { 591 ASSERT(GetNumberOfListEntries(USetupData.LanguageList) >= 1); 592 593 NewLanguageId = 594 ((PGENENTRY)GetListEntryData(GetCurrentListEntry(USetupData.LanguageList)))->Id; 595 596 if (wcscmp(SelectedLanguageId, NewLanguageId)) 597 { 598 /* Clear the language page */ 599 MUIClearPage(LANGUAGE_PAGE); 600 601 SelectedLanguageId = NewLanguageId; 602 603 /* Load the font */ 604 SetConsoleCodePage(); 605 606 /* Redraw language selection page in native language */ 607 MUIDisplayPage(LANGUAGE_PAGE); 608 } 609 610 RefreshPage = FALSE; 611 } 612 } 613 614 return WELCOME_PAGE; 615 } 616 617 618 /* 619 * Start page 620 * 621 * Next pages: 622 * LanguagePage (at once, default) 623 * InstallIntroPage (at once, if unattended) 624 * QuitPage 625 * 626 * SIDEEFFECTS 627 * Init Sdi 628 * Init USetupData.SourcePath 629 * Init USetupData.SourceRootPath 630 * Init USetupData.SourceRootDir 631 * Init USetupData.SetupInf 632 * Init USetupData.RequiredPartitionDiskSpace 633 * Init IsUnattendedSetup 634 * If unattended, init *List and sets the Codepage 635 * If unattended, init SelectedLanguageId 636 * If unattended, init USetupData.LanguageId 637 * 638 * RETURNS 639 * Number of the next page. 640 */ 641 static PAGE_NUMBER 642 SetupStartPage(PINPUT_RECORD Ir) 643 { 644 ULONG Error; 645 PGENERIC_LIST_ENTRY ListEntry; 646 PCWSTR LocaleId; 647 648 MUIDisplayPage(SETUP_INIT_PAGE); 649 650 /* Initialize Setup, phase 1 */ 651 Error = InitializeSetup(&USetupData, 1); 652 if (Error != ERROR_SUCCESS) 653 { 654 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER); 655 return QUIT_PAGE; 656 } 657 658 /* Initialize the user-mode PnP manager */ 659 if (!EnableUserModePnpManager()) 660 DPRINT1("The user-mode PnP manager could not initialize, expect unavailable devices!\n"); 661 662 /* Wait for any immediate pending installations to finish */ 663 if (WaitNoPendingInstallEvents(NULL) != STATUS_WAIT_0) 664 DPRINT1("WaitNoPendingInstallEvents() failed to wait!\n"); 665 666 CheckUnattendedSetup(&USetupData); 667 668 if (IsUnattendedSetup) 669 { 670 // TODO: Read options from inf 671 /* Load the hardware, language and keyboard layout lists */ 672 673 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf); 674 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf); 675 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf); 676 677 USetupData.LanguageList = CreateLanguageList(USetupData.SetupInf, DefaultLanguage); 678 679 /* new part */ 680 SelectedLanguageId = DefaultLanguage; 681 wcscpy(DefaultLanguage, USetupData.LocaleID); 682 USetupData.LanguageId = (LANGID)(wcstol(SelectedLanguageId, NULL, 16) & 0xFFFF); 683 684 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout); 685 686 /* first we hack LanguageList */ 687 for (ListEntry = GetFirstListEntry(USetupData.LanguageList); ListEntry; 688 ListEntry = GetNextListEntry(ListEntry)) 689 { 690 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id; 691 if (!wcsicmp(USetupData.LocaleID, LocaleId)) 692 { 693 DPRINT("found %S in LanguageList\n", LocaleId); 694 SetCurrentListEntry(USetupData.LanguageList, ListEntry); 695 break; 696 } 697 } 698 699 /* now LayoutList */ 700 for (ListEntry = GetFirstListEntry(USetupData.LayoutList); ListEntry; 701 ListEntry = GetNextListEntry(ListEntry)) 702 { 703 LocaleId = ((PGENENTRY)GetListEntryData(ListEntry))->Id; 704 if (!wcsicmp(USetupData.LocaleID, LocaleId)) 705 { 706 DPRINT("found %S in LayoutList\n", LocaleId); 707 SetCurrentListEntry(USetupData.LayoutList, ListEntry); 708 break; 709 } 710 } 711 712 SetConsoleCodePage(); 713 714 return INSTALL_INTRO_PAGE; 715 } 716 717 return LANGUAGE_PAGE; 718 } 719 720 721 /* 722 * Displays the WelcomePage. 723 * 724 * Next pages: 725 * InstallIntroPage (default) 726 * RepairIntroPage 727 * RecoveryPage 728 * LicensePage 729 * QuitPage 730 * 731 * RETURNS 732 * Number of the next page. 733 */ 734 static PAGE_NUMBER 735 WelcomePage(PINPUT_RECORD Ir) 736 { 737 MUIDisplayPage(WELCOME_PAGE); 738 739 while (TRUE) 740 { 741 CONSOLE_ConInKey(Ir); 742 743 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 744 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 745 { 746 if (ConfirmQuit(Ir)) 747 return QUIT_PAGE; 748 749 break; 750 } 751 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 752 { 753 return INSTALL_INTRO_PAGE; 754 } 755 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */ 756 { 757 return RECOVERY_PAGE; // REPAIR_INTRO_PAGE; 758 } 759 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'L') /* L */ 760 { 761 return LICENSE_PAGE; 762 } 763 } 764 765 return WELCOME_PAGE; 766 } 767 768 769 /* 770 * Displays the License page. 771 * 772 * Next page: 773 * WelcomePage (default) 774 * 775 * RETURNS 776 * Number of the next page. 777 */ 778 static PAGE_NUMBER 779 LicensePage(PINPUT_RECORD Ir) 780 { 781 MUIDisplayPage(LICENSE_PAGE); 782 783 while (TRUE) 784 { 785 CONSOLE_ConInKey(Ir); 786 787 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 788 { 789 return WELCOME_PAGE; 790 } 791 } 792 793 return LICENSE_PAGE; 794 } 795 796 797 /* 798 * Displays the RepairIntroPage. 799 * 800 * Next pages: 801 * RebootPage (default) 802 * InstallIntroPage 803 * RecoveryPage 804 * IntroPage 805 * 806 * RETURNS 807 * Number of the next page. 808 */ 809 static PAGE_NUMBER 810 RepairIntroPage(PINPUT_RECORD Ir) 811 { 812 MUIDisplayPage(REPAIR_INTRO_PAGE); 813 814 while (TRUE) 815 { 816 CONSOLE_ConInKey(Ir); 817 818 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 819 { 820 return REBOOT_PAGE; 821 } 822 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */ 823 { 824 RepairUpdateFlag = TRUE; 825 return INSTALL_INTRO_PAGE; 826 } 827 else if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'R') /* R */ 828 { 829 return RECOVERY_PAGE; 830 } 831 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 832 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */ 833 { 834 return WELCOME_PAGE; 835 } 836 } 837 838 return REPAIR_INTRO_PAGE; 839 } 840 841 /* 842 * Displays the UpgradeRepairPage. 843 * 844 * Next pages: 845 * RebootPage (default) 846 * InstallIntroPage 847 * RecoveryPage 848 * WelcomePage 849 * 850 * RETURNS 851 * Number of the next page. 852 */ 853 static PAGE_NUMBER 854 UpgradeRepairPage(PINPUT_RECORD Ir) 855 { 856 GENERIC_LIST_UI ListUi; 857 858 /*** HACK!! ***/ 859 if (PartitionList == NULL) 860 { 861 PartitionList = CreatePartitionList(); 862 if (PartitionList == NULL) 863 { 864 /* FIXME: show an error dialog */ 865 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER); 866 return QUIT_PAGE; 867 } 868 else if (IsListEmpty(&PartitionList->DiskListHead)) 869 { 870 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER); 871 return QUIT_PAGE; 872 } 873 874 /* Reset the formatter machine state */ 875 TempPartition = NULL; 876 FormatState = Start; 877 } 878 /**************/ 879 880 NtOsInstallsList = CreateNTOSInstallationsList(PartitionList); 881 if (!NtOsInstallsList) 882 DPRINT1("Failed to get a list of NTOS installations; continue installation...\n"); 883 884 /* 885 * If there is no available installation (or just a single one??) that can 886 * be updated in the list, just continue with the regular installation. 887 */ 888 if (!NtOsInstallsList || GetNumberOfListEntries(NtOsInstallsList) == 0) 889 { 890 RepairUpdateFlag = FALSE; 891 892 // return INSTALL_INTRO_PAGE; 893 return DEVICE_SETTINGS_PAGE; 894 // return SCSI_CONTROLLER_PAGE; 895 } 896 897 MUIDisplayPage(UPGRADE_REPAIR_PAGE); 898 899 InitGenericListUi(&ListUi, NtOsInstallsList, GetNTOSInstallationName); 900 DrawGenericList(&ListUi, 901 2, 23, 902 xScreen - 3, 903 yScreen - 3); 904 905 // return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 906 while (TRUE) 907 { 908 CONSOLE_ConInKey(Ir); 909 910 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) 911 { 912 switch (Ir->Event.KeyEvent.wVirtualKeyCode) 913 { 914 case VK_DOWN: /* DOWN */ 915 ScrollDownGenericList(&ListUi); 916 break; 917 case VK_UP: /* UP */ 918 ScrollUpGenericList(&ListUi); 919 break; 920 case VK_NEXT: /* PAGE DOWN */ 921 ScrollPageDownGenericList(&ListUi); 922 break; 923 case VK_PRIOR: /* PAGE UP */ 924 ScrollPageUpGenericList(&ListUi); 925 break; 926 case VK_F3: /* F3 */ 927 { 928 if (ConfirmQuit(Ir)) 929 return QUIT_PAGE; 930 else 931 RedrawGenericList(&ListUi); 932 break; 933 } 934 case VK_ESCAPE: /* ESC */ 935 { 936 RestoreGenericListUiState(&ListUi); 937 // return nextPage; // prevPage; 938 939 // return INSTALL_INTRO_PAGE; 940 return DEVICE_SETTINGS_PAGE; 941 // return SCSI_CONTROLLER_PAGE; 942 } 943 } 944 } 945 else 946 { 947 // switch (toupper(Ir->Event.KeyEvent.uChar.AsciiChar)) 948 // if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 949 if (toupper(Ir->Event.KeyEvent.uChar.AsciiChar) == 'U') /* U */ 950 { 951 /* Retrieve the current installation */ 952 ASSERT(GetNumberOfListEntries(NtOsInstallsList) >= 1); 953 954 CurrentInstallation = 955 (PNTOS_INSTALLATION)GetListEntryData(GetCurrentListEntry(NtOsInstallsList)); 956 957 DPRINT1("Selected installation for repair: \"%S\" ; DiskNumber = %d , PartitionNumber = %d\n", 958 CurrentInstallation->InstallationName, CurrentInstallation->DiskNumber, CurrentInstallation->PartitionNumber); 959 960 RepairUpdateFlag = TRUE; 961 962 // return nextPage; 963 /***/return INSTALL_INTRO_PAGE;/***/ 964 } 965 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && 966 (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) /* a-z */ 967 { 968 GenericListKeyPress(&ListUi, Ir->Event.KeyEvent.uChar.AsciiChar); 969 } 970 } 971 } 972 973 return UPGRADE_REPAIR_PAGE; 974 } 975 976 977 /* 978 * Displays the InstallIntroPage. 979 * 980 * Next pages: 981 * DeviceSettingsPage (At once if repair or update is selected) 982 * SelectPartitionPage (At once if unattended setup) 983 * DeviceSettingsPage (default) 984 * QuitPage 985 * 986 * RETURNS 987 * Number of the next page. 988 */ 989 static PAGE_NUMBER 990 InstallIntroPage(PINPUT_RECORD Ir) 991 { 992 if (RepairUpdateFlag) 993 { 994 #if 1 /* Old code that looks good */ 995 996 // return SELECT_PARTITION_PAGE; 997 return DEVICE_SETTINGS_PAGE; 998 999 #else /* Possible new code? */ 1000 1001 return DEVICE_SETTINGS_PAGE; 1002 // return SCSI_CONTROLLER_PAGE; 1003 1004 #endif 1005 } 1006 1007 if (IsUnattendedSetup) 1008 return SELECT_PARTITION_PAGE; 1009 1010 MUIDisplayPage(INSTALL_INTRO_PAGE); 1011 1012 while (TRUE) 1013 { 1014 CONSOLE_ConInKey(Ir); 1015 1016 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1017 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1018 { 1019 if (ConfirmQuit(Ir)) 1020 return QUIT_PAGE; 1021 1022 break; 1023 } 1024 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1025 { 1026 return UPGRADE_REPAIR_PAGE; 1027 } 1028 } 1029 1030 return INSTALL_INTRO_PAGE; 1031 } 1032 1033 1034 #if 0 1035 static PAGE_NUMBER 1036 ScsiControllerPage(PINPUT_RECORD Ir) 1037 { 1038 // MUIDisplayPage(SCSI_CONTROLLER_PAGE); 1039 1040 CONSOLE_SetTextXY(6, 8, "Setup detected the following mass storage devices:"); 1041 1042 /* FIXME: print loaded mass storage driver descriptions */ 1043 #if 0 1044 CONSOLE_SetTextXY(8, 10, "TEST device"); 1045 #endif 1046 1047 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit"); 1048 1049 while (TRUE) 1050 { 1051 CONSOLE_ConInKey(Ir); 1052 1053 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1054 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1055 { 1056 if (ConfirmQuit(Ir)) 1057 return QUIT_PAGE; 1058 1059 break; 1060 } 1061 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1062 { 1063 return DEVICE_SETTINGS_PAGE; 1064 } 1065 } 1066 1067 return SCSI_CONTROLLER_PAGE; 1068 } 1069 1070 static PAGE_NUMBER 1071 OemDriverPage(PINPUT_RECORD Ir) 1072 { 1073 // MUIDisplayPage(OEM_DRIVER_PAGE); 1074 1075 CONSOLE_SetTextXY(6, 8, "This is the OEM driver page!"); 1076 1077 /* FIXME: Implement!! */ 1078 1079 CONSOLE_SetStatusText(" ENTER = Continue F3 = Quit"); 1080 1081 while (TRUE) 1082 { 1083 CONSOLE_ConInKey(Ir); 1084 1085 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1086 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1087 { 1088 if (ConfirmQuit(Ir)) 1089 return QUIT_PAGE; 1090 1091 break; 1092 } 1093 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1094 { 1095 return DEVICE_SETTINGS_PAGE; 1096 } 1097 } 1098 1099 return OEM_DRIVER_PAGE; 1100 } 1101 #endif 1102 1103 1104 /* 1105 * Displays the DeviceSettingsPage. 1106 * 1107 * Next pages: 1108 * SelectPartitionPage (At once if repair or update is selected) 1109 * ComputerSettingsPage 1110 * DisplaySettingsPage 1111 * KeyboardSettingsPage 1112 * LayoutsettingsPage 1113 * SelectPartitionPage 1114 * QuitPage 1115 * 1116 * SIDEEFFECTS 1117 * Init USetupData.ComputerList 1118 * Init USetupData.DisplayList 1119 * Init USetupData.KeyboardList 1120 * Init USetupData.LayoutList 1121 * 1122 * RETURNS 1123 * Number of the next page. 1124 */ 1125 static PAGE_NUMBER 1126 DeviceSettingsPage(PINPUT_RECORD Ir) 1127 { 1128 static ULONG Line = 16; 1129 1130 /* Initialize the computer settings list */ 1131 if (USetupData.ComputerList == NULL) 1132 { 1133 USetupData.ComputerList = CreateComputerTypeList(USetupData.SetupInf); 1134 if (USetupData.ComputerList == NULL) 1135 { 1136 MUIDisplayError(ERROR_LOAD_COMPUTER, Ir, POPUP_WAIT_ENTER); 1137 return QUIT_PAGE; 1138 } 1139 } 1140 1141 /* Initialize the display settings list */ 1142 if (USetupData.DisplayList == NULL) 1143 { 1144 USetupData.DisplayList = CreateDisplayDriverList(USetupData.SetupInf); 1145 if (USetupData.DisplayList == NULL) 1146 { 1147 MUIDisplayError(ERROR_LOAD_DISPLAY, Ir, POPUP_WAIT_ENTER); 1148 return QUIT_PAGE; 1149 } 1150 } 1151 1152 /* Initialize the keyboard settings list */ 1153 if (USetupData.KeyboardList == NULL) 1154 { 1155 USetupData.KeyboardList = CreateKeyboardDriverList(USetupData.SetupInf); 1156 if (USetupData.KeyboardList == NULL) 1157 { 1158 MUIDisplayError(ERROR_LOAD_KEYBOARD, Ir, POPUP_WAIT_ENTER); 1159 return QUIT_PAGE; 1160 } 1161 } 1162 1163 /* Initialize the keyboard layout list */ 1164 if (USetupData.LayoutList == NULL) 1165 { 1166 USetupData.LayoutList = CreateKeyboardLayoutList(USetupData.SetupInf, SelectedLanguageId, DefaultKBLayout); 1167 if (USetupData.LayoutList == NULL) 1168 { 1169 /* FIXME: report error */ 1170 MUIDisplayError(ERROR_LOAD_KBLAYOUT, Ir, POPUP_WAIT_ENTER); 1171 return QUIT_PAGE; 1172 } 1173 } 1174 1175 if (RepairUpdateFlag) 1176 return SELECT_PARTITION_PAGE; 1177 1178 // if (IsUnattendedSetup) 1179 // return SELECT_PARTITION_PAGE; 1180 1181 MUIDisplayPage(DEVICE_SETTINGS_PAGE); 1182 1183 DrawGenericListCurrentItem(USetupData.ComputerList, GetSettingDescription, 25, 11); 1184 DrawGenericListCurrentItem(USetupData.DisplayList , GetSettingDescription, 25, 12); 1185 DrawGenericListCurrentItem(USetupData.KeyboardList, GetSettingDescription, 25, 13); 1186 DrawGenericListCurrentItem(USetupData.LayoutList , GetSettingDescription, 25, 14); 1187 1188 CONSOLE_InvertTextXY(24, Line, 48, 1); 1189 1190 while (TRUE) 1191 { 1192 CONSOLE_ConInKey(Ir); 1193 1194 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1195 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 1196 { 1197 CONSOLE_NormalTextXY(24, Line, 48, 1); 1198 1199 if (Line == 14) 1200 Line = 16; 1201 else if (Line == 16) 1202 Line = 11; 1203 else 1204 Line++; 1205 1206 CONSOLE_InvertTextXY(24, Line, 48, 1); 1207 } 1208 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1209 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 1210 { 1211 CONSOLE_NormalTextXY(24, Line, 48, 1); 1212 1213 if (Line == 11) 1214 Line = 16; 1215 else if (Line == 16) 1216 Line = 14; 1217 else 1218 Line--; 1219 1220 CONSOLE_InvertTextXY(24, Line, 48, 1); 1221 } 1222 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1223 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1224 { 1225 if (ConfirmQuit(Ir)) 1226 return QUIT_PAGE; 1227 1228 break; 1229 } 1230 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1231 { 1232 if (Line == 11) 1233 return COMPUTER_SETTINGS_PAGE; 1234 else if (Line == 12) 1235 return DISPLAY_SETTINGS_PAGE; 1236 else if (Line == 13) 1237 return KEYBOARD_SETTINGS_PAGE; 1238 else if (Line == 14) 1239 return LAYOUT_SETTINGS_PAGE; 1240 else if (Line == 16) 1241 return SELECT_PARTITION_PAGE; 1242 } 1243 } 1244 1245 return DEVICE_SETTINGS_PAGE; 1246 } 1247 1248 1249 /* 1250 * Handles generic selection lists. 1251 * 1252 * PARAMS 1253 * GenericList: The list to handle. 1254 * nextPage: The page it needs to jump to after this page. 1255 * Ir: The PINPUT_RECORD 1256 */ 1257 static PAGE_NUMBER 1258 HandleGenericList(PGENERIC_LIST_UI ListUi, 1259 PAGE_NUMBER nextPage, 1260 PINPUT_RECORD Ir) 1261 { 1262 while (TRUE) 1263 { 1264 CONSOLE_ConInKey(Ir); 1265 1266 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1267 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 1268 { 1269 ScrollDownGenericList(ListUi); 1270 } 1271 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1272 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 1273 { 1274 ScrollUpGenericList(ListUi); 1275 } 1276 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1277 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_NEXT)) /* PAGE DOWN */ 1278 { 1279 ScrollPageDownGenericList(ListUi); 1280 } 1281 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1282 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_PRIOR)) /* PAGE UP */ 1283 { 1284 ScrollPageUpGenericList(ListUi); 1285 } 1286 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1287 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1288 { 1289 if (ConfirmQuit(Ir)) 1290 return QUIT_PAGE; 1291 else 1292 RedrawGenericList(ListUi); 1293 } 1294 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1295 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */ 1296 { 1297 RestoreGenericListUiState(ListUi); 1298 return nextPage; // Use some "prevPage;" instead? 1299 } 1300 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 1301 { 1302 return nextPage; 1303 } 1304 else if ((Ir->Event.KeyEvent.uChar.AsciiChar > 0x60) && (Ir->Event.KeyEvent.uChar.AsciiChar < 0x7b)) 1305 { 1306 /* a-z */ 1307 GenericListKeyPress(ListUi, Ir->Event.KeyEvent.uChar.AsciiChar); 1308 } 1309 } 1310 } 1311 1312 1313 /* 1314 * Displays the ComputerSettingsPage. 1315 * 1316 * Next pages: 1317 * DeviceSettingsPage 1318 * QuitPage 1319 * 1320 * RETURNS 1321 * Number of the next page. 1322 */ 1323 static PAGE_NUMBER 1324 ComputerSettingsPage(PINPUT_RECORD Ir) 1325 { 1326 GENERIC_LIST_UI ListUi; 1327 MUIDisplayPage(COMPUTER_SETTINGS_PAGE); 1328 1329 InitGenericListUi(&ListUi, USetupData.ComputerList, GetSettingDescription); 1330 DrawGenericList(&ListUi, 1331 2, 18, 1332 xScreen - 3, 1333 yScreen - 3); 1334 1335 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 1336 } 1337 1338 1339 /* 1340 * Displays the DisplaySettingsPage. 1341 * 1342 * Next pages: 1343 * DeviceSettingsPage 1344 * QuitPage 1345 * 1346 * RETURNS 1347 * Number of the next page. 1348 */ 1349 static PAGE_NUMBER 1350 DisplaySettingsPage(PINPUT_RECORD Ir) 1351 { 1352 GENERIC_LIST_UI ListUi; 1353 MUIDisplayPage(DISPLAY_SETTINGS_PAGE); 1354 1355 InitGenericListUi(&ListUi, USetupData.DisplayList, GetSettingDescription); 1356 DrawGenericList(&ListUi, 1357 2, 18, 1358 xScreen - 3, 1359 yScreen - 3); 1360 1361 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 1362 } 1363 1364 1365 /* 1366 * Displays the KeyboardSettingsPage. 1367 * 1368 * Next pages: 1369 * DeviceSettingsPage 1370 * QuitPage 1371 * 1372 * RETURNS 1373 * Number of the next page. 1374 */ 1375 static PAGE_NUMBER 1376 KeyboardSettingsPage(PINPUT_RECORD Ir) 1377 { 1378 GENERIC_LIST_UI ListUi; 1379 MUIDisplayPage(KEYBOARD_SETTINGS_PAGE); 1380 1381 InitGenericListUi(&ListUi, USetupData.KeyboardList, GetSettingDescription); 1382 DrawGenericList(&ListUi, 1383 2, 18, 1384 xScreen - 3, 1385 yScreen - 3); 1386 1387 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 1388 } 1389 1390 1391 /* 1392 * Displays the LayoutSettingsPage. 1393 * 1394 * Next pages: 1395 * DeviceSettingsPage 1396 * QuitPage 1397 * 1398 * RETURNS 1399 * Number of the next page. 1400 */ 1401 static PAGE_NUMBER 1402 LayoutSettingsPage(PINPUT_RECORD Ir) 1403 { 1404 GENERIC_LIST_UI ListUi; 1405 MUIDisplayPage(LAYOUT_SETTINGS_PAGE); 1406 1407 InitGenericListUi(&ListUi, USetupData.LayoutList, GetSettingDescription); 1408 DrawGenericList(&ListUi, 1409 2, 18, 1410 xScreen - 3, 1411 yScreen - 3); 1412 1413 return HandleGenericList(&ListUi, DEVICE_SETTINGS_PAGE, Ir); 1414 } 1415 1416 1417 static BOOL 1418 IsDiskSizeValid(PPARTENTRY PartEntry) 1419 { 1420 ULONGLONG size; 1421 1422 size = PartEntry->SectorCount.QuadPart * PartEntry->DiskEntry->BytesPerSector; 1423 size = (size + (512 * KB)) / MB; /* in MBytes */ 1424 1425 if (size < USetupData.RequiredPartitionDiskSpace) 1426 { 1427 /* Partition is too small so ask for another one */ 1428 DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n", size, USetupData.RequiredPartitionDiskSpace); 1429 return FALSE; 1430 } 1431 else 1432 { 1433 return TRUE; 1434 } 1435 } 1436 1437 1438 /* 1439 * Displays the SelectPartitionPage. 1440 * 1441 * Next pages: 1442 * SelectFileSystemPage (At once if unattended) 1443 * SelectFileSystemPage (Default if free space is selected) 1444 * CreatePrimaryPartitionPage 1445 * CreateExtendedPartitionPage 1446 * CreateLogicalPartitionPage 1447 * ConfirmDeleteSystemPartitionPage (if the selected partition is the system partition, aka with the boot flag set) 1448 * DeletePartitionPage 1449 * QuitPage 1450 * 1451 * SIDEEFFECTS 1452 * Set InstallShortcut (only if not unattended + free space is selected) 1453 * 1454 * RETURNS 1455 * Number of the next page. 1456 */ 1457 static PAGE_NUMBER 1458 SelectPartitionPage(PINPUT_RECORD Ir) 1459 { 1460 PARTLIST_UI ListUi; 1461 ULONG Error; 1462 1463 if (PartitionList == NULL) 1464 { 1465 PartitionList = CreatePartitionList(); 1466 if (PartitionList == NULL) 1467 { 1468 /* FIXME: show an error dialog */ 1469 MUIDisplayError(ERROR_DRIVE_INFORMATION, Ir, POPUP_WAIT_ENTER); 1470 return QUIT_PAGE; 1471 } 1472 else if (IsListEmpty(&PartitionList->DiskListHead)) 1473 { 1474 MUIDisplayError(ERROR_NO_HDD, Ir, POPUP_WAIT_ENTER); 1475 return QUIT_PAGE; 1476 } 1477 1478 /* Reset the formatter machine state */ 1479 TempPartition = NULL; 1480 FormatState = Start; 1481 } 1482 1483 if (RepairUpdateFlag) 1484 { 1485 ASSERT(CurrentInstallation); 1486 1487 /* Determine the selected installation disk & partition */ 1488 InstallPartition = SelectPartition(PartitionList, 1489 CurrentInstallation->DiskNumber, 1490 CurrentInstallation->PartitionNumber); 1491 if (!InstallPartition) 1492 { 1493 DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n"); 1494 ASSERT(FALSE); 1495 } 1496 ASSERT(!IsContainerPartition(InstallPartition->PartitionType)); 1497 1498 return SELECT_FILE_SYSTEM_PAGE; 1499 } 1500 1501 MUIDisplayPage(SELECT_PARTITION_PAGE); 1502 1503 InitPartitionListUi(&ListUi, PartitionList, 1504 CurrentPartition, 1505 2, 23, 1506 xScreen - 3, 1507 yScreen - 3); 1508 DrawPartitionList(&ListUi); 1509 1510 if (IsUnattendedSetup) 1511 { 1512 /* Determine the selected installation disk & partition */ 1513 InstallPartition = SelectPartition(PartitionList, 1514 USetupData.DestinationDiskNumber, 1515 USetupData.DestinationPartitionNumber); 1516 if (!InstallPartition) 1517 { 1518 CurrentPartition = ListUi.CurrentPartition; 1519 1520 if (USetupData.AutoPartition) 1521 { 1522 ASSERT(CurrentPartition != NULL); 1523 ASSERT(!IsContainerPartition(CurrentPartition->PartitionType)); 1524 1525 if (CurrentPartition->LogicalPartition) 1526 { 1527 CreateLogicalPartition(PartitionList, 1528 CurrentPartition, 1529 CurrentPartition->SectorCount.QuadPart, 1530 TRUE); 1531 } 1532 else 1533 { 1534 CreatePrimaryPartition(PartitionList, 1535 CurrentPartition, 1536 CurrentPartition->SectorCount.QuadPart, 1537 TRUE); 1538 } 1539 1540 // FIXME?? Aren't we going to enter an infinite loop, if this test fails?? 1541 if (!IsDiskSizeValid(CurrentPartition)) 1542 { 1543 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY, 1544 USetupData.RequiredPartitionDiskSpace); 1545 return SELECT_PARTITION_PAGE; /* let the user select another partition */ 1546 } 1547 1548 InstallPartition = CurrentPartition; 1549 return SELECT_FILE_SYSTEM_PAGE; 1550 } 1551 } 1552 else 1553 { 1554 ASSERT(!IsContainerPartition(InstallPartition->PartitionType)); 1555 1556 DrawPartitionList(&ListUi); // FIXME: Doesn't make much sense... 1557 1558 // FIXME?? Aren't we going to enter an infinite loop, if this test fails?? 1559 if (!IsDiskSizeValid(InstallPartition)) 1560 { 1561 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY, 1562 USetupData.RequiredPartitionDiskSpace); 1563 return SELECT_PARTITION_PAGE; /* let the user select another partition */ 1564 } 1565 1566 return SELECT_FILE_SYSTEM_PAGE; 1567 } 1568 } 1569 1570 while (TRUE) 1571 { 1572 CurrentPartition = ListUi.CurrentPartition; 1573 1574 /* Update status text */ 1575 if (CurrentPartition == NULL) 1576 { 1577 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION)); 1578 } 1579 else if (CurrentPartition->LogicalPartition) 1580 { 1581 if (CurrentPartition->IsPartitioned) 1582 { 1583 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION)); 1584 } 1585 else 1586 { 1587 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATELOGICAL)); 1588 } 1589 } 1590 else 1591 { 1592 if (CurrentPartition->IsPartitioned) 1593 { 1594 if (IsContainerPartition(CurrentPartition->PartitionType)) 1595 { 1596 CONSOLE_SetStatusText(MUIGetString(STRING_DELETEPARTITION)); 1597 } 1598 else 1599 { 1600 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLDELETEPARTITION)); 1601 } 1602 } 1603 else 1604 { 1605 CONSOLE_SetStatusText(MUIGetString(STRING_INSTALLCREATEPARTITION)); 1606 } 1607 } 1608 1609 CONSOLE_ConInKey(Ir); 1610 1611 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1612 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1613 { 1614 if (ConfirmQuit(Ir)) 1615 { 1616 DestroyPartitionList(PartitionList); 1617 PartitionList = NULL; 1618 return QUIT_PAGE; 1619 } 1620 1621 break; 1622 } 1623 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1624 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 1625 { 1626 ScrollDownPartitionList(&ListUi); 1627 } 1628 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 1629 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 1630 { 1631 ScrollUpPartitionList(&ListUi); 1632 } 1633 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ 1634 { 1635 ASSERT(CurrentPartition != NULL); 1636 1637 if (IsContainerPartition(CurrentPartition->PartitionType)) 1638 continue; // return SELECT_PARTITION_PAGE; 1639 1640 /* 1641 * Check whether the user wants to install ReactOS on a disk that 1642 * is not recognized by the computer's firmware and if so, display 1643 * a warning since such disks may not be bootable. 1644 */ 1645 if (CurrentPartition->DiskEntry->MediaType == FixedMedia && 1646 !CurrentPartition->DiskEntry->BiosFound) 1647 { 1648 PopupError("The disk you have selected for installing ReactOS\n" 1649 "is not visible by the firmware of your computer,\n" 1650 "and so may not be bootable.\n" 1651 "Press ENTER to continue nonetheless.", 1652 MUIGetString(STRING_CONTINUE), 1653 Ir, POPUP_WAIT_ENTER); 1654 // return SELECT_PARTITION_PAGE; 1655 } 1656 1657 if (CurrentPartition->IsPartitioned == FALSE) 1658 { 1659 if (CurrentPartition->LogicalPartition) 1660 { 1661 Error = LogicalPartitionCreationChecks(CurrentPartition); 1662 if (Error != NOT_AN_ERROR) 1663 { 1664 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY); 1665 return SELECT_PARTITION_PAGE; 1666 } 1667 1668 CreateLogicalPartition(PartitionList, 1669 CurrentPartition, 1670 0ULL, 1671 TRUE); 1672 } 1673 else 1674 { 1675 Error = PrimaryPartitionCreationChecks(CurrentPartition); 1676 if (Error != NOT_AN_ERROR) 1677 { 1678 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY); 1679 return SELECT_PARTITION_PAGE; 1680 } 1681 1682 CreatePrimaryPartition(PartitionList, 1683 CurrentPartition, 1684 0ULL, 1685 TRUE); 1686 } 1687 } 1688 1689 if (!IsDiskSizeValid(CurrentPartition)) 1690 { 1691 MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY, 1692 USetupData.RequiredPartitionDiskSpace); 1693 return SELECT_PARTITION_PAGE; /* let the user select another partition */ 1694 } 1695 1696 InstallPartition = CurrentPartition; 1697 return SELECT_FILE_SYSTEM_PAGE; 1698 } 1699 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'P') /* P */ 1700 { 1701 ASSERT(CurrentPartition != NULL); 1702 1703 if (CurrentPartition->LogicalPartition == FALSE) 1704 { 1705 Error = PrimaryPartitionCreationChecks(CurrentPartition); 1706 if (Error != NOT_AN_ERROR) 1707 { 1708 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY); 1709 return SELECT_PARTITION_PAGE; 1710 } 1711 1712 return CREATE_PRIMARY_PARTITION_PAGE; 1713 } 1714 } 1715 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E') /* E */ 1716 { 1717 ASSERT(CurrentPartition != NULL); 1718 1719 if (CurrentPartition->LogicalPartition == FALSE) 1720 { 1721 Error = ExtendedPartitionCreationChecks(CurrentPartition); 1722 if (Error != NOT_AN_ERROR) 1723 { 1724 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY); 1725 return SELECT_PARTITION_PAGE; 1726 } 1727 1728 return CREATE_EXTENDED_PARTITION_PAGE; 1729 } 1730 } 1731 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */ 1732 { 1733 ASSERT(CurrentPartition != NULL); 1734 1735 if (CurrentPartition->LogicalPartition) 1736 { 1737 Error = LogicalPartitionCreationChecks(CurrentPartition); 1738 if (Error != NOT_AN_ERROR) 1739 { 1740 MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY); 1741 return SELECT_PARTITION_PAGE; 1742 } 1743 1744 return CREATE_LOGICAL_PARTITION_PAGE; 1745 } 1746 } 1747 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D') /* D */ 1748 { 1749 UNICODE_STRING CurrentPartitionU; 1750 WCHAR PathBuffer[MAX_PATH]; 1751 1752 ASSERT(CurrentPartition != NULL); 1753 1754 if (CurrentPartition->IsPartitioned == FALSE) 1755 { 1756 MUIDisplayError(ERROR_DELETE_SPACE, Ir, POPUP_WAIT_ANY_KEY); 1757 return SELECT_PARTITION_PAGE; 1758 } 1759 1760 // TODO: Do something similar before trying to format the partition? 1761 if (!CurrentPartition->New && 1762 !IsContainerPartition(CurrentPartition->PartitionType) && 1763 CurrentPartition->FormatState != Unformatted) 1764 { 1765 ASSERT(CurrentPartition->PartitionNumber != 0); 1766 1767 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 1768 L"\\Device\\Harddisk%lu\\Partition%lu\\", 1769 CurrentPartition->DiskEntry->DiskNumber, 1770 CurrentPartition->PartitionNumber); 1771 RtlInitUnicodeString(&CurrentPartitionU, PathBuffer); 1772 1773 /* 1774 * Check whether the user attempts to delete the partition on which 1775 * the installation source is present. If so, fail with an error. 1776 */ 1777 // &USetupData.SourceRootPath 1778 if (RtlPrefixUnicodeString(&CurrentPartitionU, &USetupData.SourcePath, TRUE)) 1779 { 1780 PopupError("You cannot delete the partition containing the installation source!", 1781 MUIGetString(STRING_CONTINUE), 1782 Ir, POPUP_WAIT_ENTER); 1783 return SELECT_PARTITION_PAGE; 1784 } 1785 } 1786 1787 // FIXME TODO: PartitionList->SystemPartition is not yet initialized!!!! 1788 if (CurrentPartition == PartitionList->SystemPartition || 1789 CurrentPartition->BootIndicator) 1790 { 1791 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE; 1792 } 1793 1794 return DELETE_PARTITION_PAGE; 1795 } 1796 } 1797 1798 return SELECT_PARTITION_PAGE; 1799 } 1800 1801 1802 #define PARTITION_SIZE_INPUT_FIELD_LENGTH 9 1803 /* Restriction for MaxSize */ 1804 #define PARTITION_MAXSIZE (pow(10, (PARTITION_SIZE_INPUT_FIELD_LENGTH - 1)) - 1) 1805 1806 static VOID 1807 ShowPartitionSizeInputBox(SHORT Left, 1808 SHORT Top, 1809 SHORT Right, 1810 SHORT Bottom, 1811 ULONG MaxSize, 1812 PWSTR InputBuffer, 1813 PBOOLEAN Quit, 1814 PBOOLEAN Cancel) 1815 { 1816 INPUT_RECORD Ir; 1817 COORD coPos; 1818 DWORD Written; 1819 CHAR Buffer[128]; 1820 INT Length, Pos; 1821 WCHAR ch; 1822 SHORT iLeft; 1823 SHORT iTop; 1824 1825 if (Quit != NULL) 1826 *Quit = FALSE; 1827 1828 if (Cancel != NULL) 1829 *Cancel = FALSE; 1830 1831 DrawBox(Left, Top, Right - Left + 1, Bottom - Top + 1); 1832 1833 /* Print message */ 1834 coPos.X = Left + 2; 1835 coPos.Y = Top + 2; 1836 strcpy(Buffer, MUIGetString(STRING_PARTITIONSIZE)); 1837 iLeft = coPos.X + strlen(Buffer) + 1; 1838 iTop = coPos.Y; 1839 1840 WriteConsoleOutputCharacterA(StdOutput, 1841 Buffer, 1842 strlen(Buffer), 1843 coPos, 1844 &Written); 1845 1846 sprintf(Buffer, MUIGetString(STRING_MAXSIZE), MaxSize); 1847 coPos.X = iLeft + PARTITION_SIZE_INPUT_FIELD_LENGTH + 1; 1848 coPos.Y = iTop; 1849 WriteConsoleOutputCharacterA(StdOutput, 1850 Buffer, 1851 strlen(Buffer), 1852 coPos, 1853 &Written); 1854 1855 swprintf(InputBuffer, L"%lu", MaxSize); 1856 Length = wcslen(InputBuffer); 1857 Pos = Length; 1858 CONSOLE_SetInputTextXY(iLeft, 1859 iTop, 1860 PARTITION_SIZE_INPUT_FIELD_LENGTH, 1861 InputBuffer); 1862 CONSOLE_SetCursorXY(iLeft + Length, iTop); 1863 CONSOLE_SetCursorType(TRUE, TRUE); 1864 1865 while (TRUE) 1866 { 1867 CONSOLE_ConInKey(&Ir); 1868 1869 if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1870 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 1871 { 1872 if (Quit != NULL) 1873 *Quit = TRUE; 1874 1875 InputBuffer[0] = UNICODE_NULL; 1876 CONSOLE_SetCursorType(TRUE, FALSE); 1877 break; 1878 } 1879 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ 1880 { 1881 CONSOLE_SetCursorType(TRUE, FALSE); 1882 break; 1883 } 1884 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESCAPE */ 1885 { 1886 if (Cancel != NULL) 1887 *Cancel = TRUE; 1888 1889 InputBuffer[0] = UNICODE_NULL; 1890 CONSOLE_SetCursorType(TRUE, FALSE); 1891 break; 1892 } 1893 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1894 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */ 1895 { 1896 Pos = 0; 1897 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1898 } 1899 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1900 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */ 1901 { 1902 Pos = Length; 1903 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1904 } 1905 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1906 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */ 1907 { 1908 if (Pos > 0) 1909 { 1910 Pos--; 1911 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1912 } 1913 } 1914 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1915 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */ 1916 { 1917 if (Pos < Length) 1918 { 1919 Pos++; 1920 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1921 } 1922 } 1923 else if ((Ir.Event.KeyEvent.uChar.AsciiChar == 0x00) && 1924 (Ir.Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */ 1925 { 1926 if (Pos < Length) 1927 { 1928 memmove(&InputBuffer[Pos], 1929 &InputBuffer[Pos + 1], 1930 (Length - Pos - 1) * sizeof(WCHAR)); 1931 InputBuffer[Length - 1] = UNICODE_NULL; 1932 1933 Length--; 1934 CONSOLE_SetInputTextXY(iLeft, 1935 iTop, 1936 PARTITION_SIZE_INPUT_FIELD_LENGTH, 1937 InputBuffer); 1938 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1939 } 1940 } 1941 else if (Ir.Event.KeyEvent.wVirtualKeyCode == VK_BACK) /* BACKSPACE */ 1942 { 1943 if (Pos > 0) 1944 { 1945 if (Pos < Length) 1946 memmove(&InputBuffer[Pos - 1], 1947 &InputBuffer[Pos], 1948 (Length - Pos) * sizeof(WCHAR)); 1949 InputBuffer[Length - 1] = UNICODE_NULL; 1950 1951 Pos--; 1952 Length--; 1953 CONSOLE_SetInputTextXY(iLeft, 1954 iTop, 1955 PARTITION_SIZE_INPUT_FIELD_LENGTH, 1956 InputBuffer); 1957 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1958 } 1959 } 1960 else if (Ir.Event.KeyEvent.uChar.AsciiChar != 0x00) 1961 { 1962 if (Length < PARTITION_SIZE_INPUT_FIELD_LENGTH - 1) 1963 { 1964 ch = (WCHAR)Ir.Event.KeyEvent.uChar.AsciiChar; 1965 1966 if ((ch >= L'0') && (ch <= L'9')) 1967 { 1968 if (Pos < Length) 1969 memmove(&InputBuffer[Pos + 1], 1970 &InputBuffer[Pos], 1971 (Length - Pos) * sizeof(WCHAR)); 1972 InputBuffer[Length + 1] = UNICODE_NULL; 1973 InputBuffer[Pos] = ch; 1974 1975 Pos++; 1976 Length++; 1977 CONSOLE_SetInputTextXY(iLeft, 1978 iTop, 1979 PARTITION_SIZE_INPUT_FIELD_LENGTH, 1980 InputBuffer); 1981 CONSOLE_SetCursorXY(iLeft + Pos, iTop); 1982 } 1983 } 1984 } 1985 } 1986 } 1987 1988 1989 /* 1990 * Displays the CreatePrimaryPartitionPage. 1991 * 1992 * Next pages: 1993 * SelectPartitionPage 1994 * SelectFileSystemPage (default) 1995 * QuitPage 1996 * 1997 * RETURNS 1998 * Number of the next page. 1999 */ 2000 static PAGE_NUMBER 2001 CreatePrimaryPartitionPage(PINPUT_RECORD Ir) 2002 { 2003 PPARTENTRY PartEntry; 2004 PDISKENTRY DiskEntry; 2005 BOOLEAN Quit; 2006 BOOLEAN Cancel; 2007 WCHAR InputBuffer[50]; 2008 ULONG MaxSize; 2009 ULONGLONG PartSize; 2010 ULONGLONG DiskSize; 2011 ULONGLONG SectorCount; 2012 PCHAR Unit; 2013 2014 if (PartitionList == NULL || CurrentPartition == NULL) 2015 { 2016 /* FIXME: show an error dialog */ 2017 return QUIT_PAGE; 2018 } 2019 2020 PartEntry = CurrentPartition; 2021 DiskEntry = CurrentPartition->DiskEntry; 2022 2023 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 2024 2025 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSENEWPARTITION)); 2026 2027 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2028 #if 0 2029 if (DiskSize >= 10 * GB) /* 10 GB */ 2030 { 2031 DiskSize = DiskSize / GB; 2032 Unit = MUIGetString(STRING_GB); 2033 } 2034 else 2035 #endif 2036 { 2037 DiskSize = DiskSize / MB; 2038 if (DiskSize == 0) 2039 DiskSize = 1; 2040 2041 Unit = MUIGetString(STRING_MB); 2042 } 2043 2044 if (DiskEntry->DriverName.Length > 0) 2045 { 2046 CONSOLE_PrintTextXY(6, 10, 2047 MUIGetString(STRING_HDINFOPARTCREATE_1), 2048 DiskSize, 2049 Unit, 2050 DiskEntry->DiskNumber, 2051 DiskEntry->Port, 2052 DiskEntry->Bus, 2053 DiskEntry->Id, 2054 &DiskEntry->DriverName, 2055 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 2056 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 2057 "RAW"); 2058 } 2059 else 2060 { 2061 CONSOLE_PrintTextXY(6, 10, 2062 MUIGetString(STRING_HDINFOPARTCREATE_2), 2063 DiskSize, 2064 Unit, 2065 DiskEntry->DiskNumber, 2066 DiskEntry->Port, 2067 DiskEntry->Bus, 2068 DiskEntry->Id, 2069 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 2070 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 2071 "RAW"); 2072 } 2073 2074 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE)); 2075 2076 #if 0 2077 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB", 2078 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB); 2079 #endif 2080 2081 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION)); 2082 2083 PartEntry = CurrentPartition; 2084 while (TRUE) 2085 { 2086 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */ 2087 2088 if (MaxSize > PARTITION_MAXSIZE) 2089 MaxSize = PARTITION_MAXSIZE; 2090 2091 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */ 2092 MaxSize, InputBuffer, &Quit, &Cancel); 2093 2094 if (Quit) 2095 { 2096 if (ConfirmQuit(Ir)) 2097 return QUIT_PAGE; 2098 2099 break; 2100 } 2101 else if (Cancel) 2102 { 2103 return SELECT_PARTITION_PAGE; 2104 } 2105 else 2106 { 2107 PartSize = _wcstoui64(InputBuffer, NULL, 10); 2108 2109 if (PartSize < 1) 2110 { 2111 /* Too small */ 2112 continue; 2113 } 2114 2115 if (PartSize > MaxSize) 2116 { 2117 /* Too large */ 2118 continue; 2119 } 2120 2121 /* Convert to bytes */ 2122 if (PartSize == MaxSize) 2123 { 2124 /* Use all of the unpartitioned disk space */ 2125 SectorCount = PartEntry->SectorCount.QuadPart; 2126 } 2127 else 2128 { 2129 /* Calculate the sector count from the size in MB */ 2130 SectorCount = PartSize * MB / DiskEntry->BytesPerSector; 2131 2132 /* But never get larger than the unpartitioned disk space */ 2133 if (SectorCount > PartEntry->SectorCount.QuadPart) 2134 SectorCount = PartEntry->SectorCount.QuadPart; 2135 } 2136 2137 DPRINT ("Partition size: %I64u bytes\n", PartSize); 2138 2139 CreatePrimaryPartition(PartitionList, 2140 CurrentPartition, 2141 SectorCount, 2142 FALSE); 2143 2144 return SELECT_PARTITION_PAGE; 2145 } 2146 } 2147 2148 return CREATE_PRIMARY_PARTITION_PAGE; 2149 } 2150 2151 2152 /* 2153 * Displays the CreateExtendedPartitionPage. 2154 * 2155 * Next pages: 2156 * SelectPartitionPage (default) 2157 * QuitPage 2158 * 2159 * RETURNS 2160 * Number of the next page. 2161 */ 2162 static PAGE_NUMBER 2163 CreateExtendedPartitionPage(PINPUT_RECORD Ir) 2164 { 2165 PPARTENTRY PartEntry; 2166 PDISKENTRY DiskEntry; 2167 BOOLEAN Quit; 2168 BOOLEAN Cancel; 2169 WCHAR InputBuffer[50]; 2170 ULONG MaxSize; 2171 ULONGLONG PartSize; 2172 ULONGLONG DiskSize; 2173 ULONGLONG SectorCount; 2174 PCHAR Unit; 2175 2176 if (PartitionList == NULL || CurrentPartition == NULL) 2177 { 2178 /* FIXME: show an error dialog */ 2179 return QUIT_PAGE; 2180 } 2181 2182 PartEntry = CurrentPartition; 2183 DiskEntry = CurrentPartition->DiskEntry; 2184 2185 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 2186 2187 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_EXTENDED_PARTITION)); 2188 2189 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2190 #if 0 2191 if (DiskSize >= 10 * GB) /* 10 GB */ 2192 { 2193 DiskSize = DiskSize / GB; 2194 Unit = MUIGetString(STRING_GB); 2195 } 2196 else 2197 #endif 2198 { 2199 DiskSize = DiskSize / MB; 2200 if (DiskSize == 0) 2201 DiskSize = 1; 2202 2203 Unit = MUIGetString(STRING_MB); 2204 } 2205 2206 if (DiskEntry->DriverName.Length > 0) 2207 { 2208 CONSOLE_PrintTextXY(6, 10, 2209 MUIGetString(STRING_HDINFOPARTCREATE_1), 2210 DiskSize, 2211 Unit, 2212 DiskEntry->DiskNumber, 2213 DiskEntry->Port, 2214 DiskEntry->Bus, 2215 DiskEntry->Id, 2216 &DiskEntry->DriverName, 2217 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 2218 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 2219 "RAW"); 2220 } 2221 else 2222 { 2223 CONSOLE_PrintTextXY(6, 10, 2224 MUIGetString(STRING_HDINFOPARTCREATE_2), 2225 DiskSize, 2226 Unit, 2227 DiskEntry->DiskNumber, 2228 DiskEntry->Port, 2229 DiskEntry->Bus, 2230 DiskEntry->Id, 2231 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 2232 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 2233 "RAW"); 2234 } 2235 2236 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE)); 2237 2238 #if 0 2239 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB", 2240 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB); 2241 #endif 2242 2243 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION)); 2244 2245 PartEntry = CurrentPartition; 2246 while (TRUE) 2247 { 2248 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */ 2249 2250 if (MaxSize > PARTITION_MAXSIZE) 2251 MaxSize = PARTITION_MAXSIZE; 2252 2253 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */ 2254 MaxSize, InputBuffer, &Quit, &Cancel); 2255 2256 if (Quit) 2257 { 2258 if (ConfirmQuit(Ir)) 2259 return QUIT_PAGE; 2260 2261 break; 2262 } 2263 else if (Cancel) 2264 { 2265 return SELECT_PARTITION_PAGE; 2266 } 2267 else 2268 { 2269 PartSize = _wcstoui64(InputBuffer, NULL, 10); 2270 2271 if (PartSize < 1) 2272 { 2273 /* Too small */ 2274 continue; 2275 } 2276 2277 if (PartSize > MaxSize) 2278 { 2279 /* Too large */ 2280 continue; 2281 } 2282 2283 /* Convert to bytes */ 2284 if (PartSize == MaxSize) 2285 { 2286 /* Use all of the unpartitioned disk space */ 2287 SectorCount = PartEntry->SectorCount.QuadPart; 2288 } 2289 else 2290 { 2291 /* Calculate the sector count from the size in MB */ 2292 SectorCount = PartSize * MB / DiskEntry->BytesPerSector; 2293 2294 /* But never get larger than the unpartitioned disk space */ 2295 if (SectorCount > PartEntry->SectorCount.QuadPart) 2296 SectorCount = PartEntry->SectorCount.QuadPart; 2297 } 2298 2299 DPRINT ("Partition size: %I64u bytes\n", PartSize); 2300 2301 CreateExtendedPartition(PartitionList, 2302 CurrentPartition, 2303 SectorCount); 2304 2305 return SELECT_PARTITION_PAGE; 2306 } 2307 } 2308 2309 return CREATE_EXTENDED_PARTITION_PAGE; 2310 } 2311 2312 2313 /* 2314 * Displays the CreateLogicalPartitionPage. 2315 * 2316 * Next pages: 2317 * SelectFileSystemPage (default) 2318 * QuitPage 2319 * 2320 * RETURNS 2321 * Number of the next page. 2322 */ 2323 static PAGE_NUMBER 2324 CreateLogicalPartitionPage(PINPUT_RECORD Ir) 2325 { 2326 PPARTENTRY PartEntry; 2327 PDISKENTRY DiskEntry; 2328 BOOLEAN Quit; 2329 BOOLEAN Cancel; 2330 WCHAR InputBuffer[50]; 2331 ULONG MaxSize; 2332 ULONGLONG PartSize; 2333 ULONGLONG DiskSize; 2334 ULONGLONG SectorCount; 2335 PCHAR Unit; 2336 2337 if (PartitionList == NULL || CurrentPartition == NULL) 2338 { 2339 /* FIXME: show an error dialog */ 2340 return QUIT_PAGE; 2341 } 2342 2343 PartEntry = CurrentPartition; 2344 DiskEntry = CurrentPartition->DiskEntry; 2345 2346 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 2347 2348 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHOOSE_NEW_LOGICAL_PARTITION)); 2349 2350 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2351 #if 0 2352 if (DiskSize >= 10 * GB) /* 10 GB */ 2353 { 2354 DiskSize = DiskSize / GB; 2355 Unit = MUIGetString(STRING_GB); 2356 } 2357 else 2358 #endif 2359 { 2360 DiskSize = DiskSize / MB; 2361 if (DiskSize == 0) 2362 DiskSize = 1; 2363 2364 Unit = MUIGetString(STRING_MB); 2365 } 2366 2367 if (DiskEntry->DriverName.Length > 0) 2368 { 2369 CONSOLE_PrintTextXY(6, 10, 2370 MUIGetString(STRING_HDINFOPARTCREATE_1), 2371 DiskSize, 2372 Unit, 2373 DiskEntry->DiskNumber, 2374 DiskEntry->Port, 2375 DiskEntry->Bus, 2376 DiskEntry->Id, 2377 &DiskEntry->DriverName, 2378 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 2379 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 2380 "RAW"); 2381 } 2382 else 2383 { 2384 CONSOLE_PrintTextXY(6, 10, 2385 MUIGetString(STRING_HDINFOPARTCREATE_2), 2386 DiskSize, 2387 Unit, 2388 DiskEntry->DiskNumber, 2389 DiskEntry->Port, 2390 DiskEntry->Bus, 2391 DiskEntry->Id, 2392 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 2393 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 2394 "RAW"); 2395 } 2396 2397 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_HDDSIZE)); 2398 2399 #if 0 2400 CONSOLE_PrintTextXY(8, 10, "Maximum size of the new partition is %I64u MB", 2401 CurrentPartition->SectorCount * DiskEntry->BytesPerSector / MB); 2402 #endif 2403 2404 CONSOLE_SetStatusText(MUIGetString(STRING_CREATEPARTITION)); 2405 2406 PartEntry = CurrentPartition; 2407 while (TRUE) 2408 { 2409 MaxSize = (PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector) / MB; /* in MBytes (rounded) */ 2410 2411 if (MaxSize > PARTITION_MAXSIZE) 2412 MaxSize = PARTITION_MAXSIZE; 2413 2414 ShowPartitionSizeInputBox(12, 14, xScreen - 12, 17, /* left, top, right, bottom */ 2415 MaxSize, InputBuffer, &Quit, &Cancel); 2416 2417 if (Quit) 2418 { 2419 if (ConfirmQuit(Ir)) 2420 return QUIT_PAGE; 2421 2422 break; 2423 } 2424 else if (Cancel) 2425 { 2426 return SELECT_PARTITION_PAGE; 2427 } 2428 else 2429 { 2430 PartSize = _wcstoui64(InputBuffer, NULL, 10); 2431 2432 if (PartSize < 1) 2433 { 2434 /* Too small */ 2435 continue; 2436 } 2437 2438 if (PartSize > MaxSize) 2439 { 2440 /* Too large */ 2441 continue; 2442 } 2443 2444 /* Convert to bytes */ 2445 if (PartSize == MaxSize) 2446 { 2447 /* Use all of the unpartitioned disk space */ 2448 SectorCount = PartEntry->SectorCount.QuadPart; 2449 } 2450 else 2451 { 2452 /* Calculate the sector count from the size in MB */ 2453 SectorCount = PartSize * MB / DiskEntry->BytesPerSector; 2454 2455 /* But never get larger than the unpartitioned disk space */ 2456 if (SectorCount > PartEntry->SectorCount.QuadPart) 2457 SectorCount = PartEntry->SectorCount.QuadPart; 2458 } 2459 2460 DPRINT("Partition size: %I64u bytes\n", PartSize); 2461 2462 CreateLogicalPartition(PartitionList, 2463 CurrentPartition, 2464 SectorCount, 2465 FALSE); 2466 2467 return SELECT_PARTITION_PAGE; 2468 } 2469 } 2470 2471 return CREATE_LOGICAL_PARTITION_PAGE; 2472 } 2473 2474 2475 /* 2476 * Displays the ConfirmDeleteSystemPartitionPage. 2477 * 2478 * Next pages: 2479 * DeletePartitionPage (default) 2480 * SelectPartitionPage 2481 * 2482 * RETURNS 2483 * Number of the next page. 2484 */ 2485 static PAGE_NUMBER 2486 ConfirmDeleteSystemPartitionPage(PINPUT_RECORD Ir) 2487 { 2488 MUIDisplayPage(CONFIRM_DELETE_SYSTEM_PARTITION_PAGE); 2489 2490 while (TRUE) 2491 { 2492 CONSOLE_ConInKey(Ir); 2493 2494 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 2495 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 2496 { 2497 if (ConfirmQuit(Ir)) 2498 return QUIT_PAGE; 2499 2500 break; 2501 } 2502 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ 2503 { 2504 return DELETE_PARTITION_PAGE; 2505 } 2506 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 2507 { 2508 return SELECT_PARTITION_PAGE; 2509 } 2510 } 2511 2512 return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE; 2513 } 2514 2515 2516 /* 2517 * Displays the DeletePartitionPage. 2518 * 2519 * Next pages: 2520 * SelectPartitionPage (default) 2521 * QuitPage 2522 * 2523 * RETURNS 2524 * Number of the next page. 2525 */ 2526 static PAGE_NUMBER 2527 DeletePartitionPage(PINPUT_RECORD Ir) 2528 { 2529 PPARTENTRY PartEntry; 2530 PDISKENTRY DiskEntry; 2531 ULONGLONG DiskSize; 2532 ULONGLONG PartSize; 2533 PCHAR Unit; 2534 CHAR PartTypeString[32]; 2535 2536 if (PartitionList == NULL || CurrentPartition == NULL) 2537 { 2538 /* FIXME: show an error dialog */ 2539 return QUIT_PAGE; 2540 } 2541 2542 PartEntry = CurrentPartition; 2543 DiskEntry = CurrentPartition->DiskEntry; 2544 2545 MUIDisplayPage(DELETE_PARTITION_PAGE); 2546 2547 /* Adjust partition type */ 2548 GetPartTypeStringFromPartitionType(PartEntry->PartitionType, 2549 PartTypeString, 2550 ARRAYSIZE(PartTypeString)); 2551 2552 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2553 #if 0 2554 if (PartSize >= 10 * GB) /* 10 GB */ 2555 { 2556 PartSize = PartSize / GB; 2557 Unit = MUIGetString(STRING_GB); 2558 } 2559 else 2560 #endif 2561 if (PartSize >= 10 * MB) /* 10 MB */ 2562 { 2563 PartSize = PartSize / MB; 2564 Unit = MUIGetString(STRING_MB); 2565 } 2566 else 2567 { 2568 PartSize = PartSize / KB; 2569 Unit = MUIGetString(STRING_KB); 2570 } 2571 2572 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ?? 2573 { 2574 CONSOLE_PrintTextXY(6, 10, 2575 MUIGetString(STRING_HDDINFOUNK2), 2576 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter, 2577 (PartEntry->DriveLetter == 0) ? '-' : ':', 2578 PartEntry->PartitionType, 2579 PartSize, 2580 Unit); 2581 } 2582 else 2583 { 2584 CONSOLE_PrintTextXY(6, 10, 2585 " %c%c %s %I64u %s", 2586 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter, 2587 (PartEntry->DriveLetter == 0) ? '-' : ':', 2588 PartTypeString, 2589 PartSize, 2590 Unit); 2591 } 2592 2593 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2594 #if 0 2595 if (DiskSize >= 10 * GB) /* 10 GB */ 2596 { 2597 DiskSize = DiskSize / GB; 2598 Unit = MUIGetString(STRING_GB); 2599 } 2600 else 2601 #endif 2602 { 2603 DiskSize = DiskSize / MB; 2604 if (DiskSize == 0) 2605 DiskSize = 1; 2606 2607 Unit = MUIGetString(STRING_MB); 2608 } 2609 2610 if (DiskEntry->DriverName.Length > 0) 2611 { 2612 CONSOLE_PrintTextXY(6, 12, 2613 MUIGetString(STRING_HDINFOPARTDELETE_1), 2614 DiskSize, 2615 Unit, 2616 DiskEntry->DiskNumber, 2617 DiskEntry->Port, 2618 DiskEntry->Bus, 2619 DiskEntry->Id, 2620 &DiskEntry->DriverName, 2621 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 2622 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 2623 "RAW"); 2624 } 2625 else 2626 { 2627 CONSOLE_PrintTextXY(6, 12, 2628 MUIGetString(STRING_HDINFOPARTDELETE_2), 2629 DiskSize, 2630 Unit, 2631 DiskEntry->DiskNumber, 2632 DiskEntry->Port, 2633 DiskEntry->Bus, 2634 DiskEntry->Id, 2635 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 2636 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 2637 "RAW"); 2638 } 2639 2640 while (TRUE) 2641 { 2642 CONSOLE_ConInKey(Ir); 2643 2644 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 2645 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 2646 { 2647 if (ConfirmQuit(Ir)) 2648 return QUIT_PAGE; 2649 2650 break; 2651 } 2652 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) /* ESC */ 2653 { 2654 return SELECT_PARTITION_PAGE; 2655 } 2656 else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'L') /* L */ 2657 { 2658 DeletePartition(PartitionList, 2659 CurrentPartition, 2660 &CurrentPartition); 2661 return SELECT_PARTITION_PAGE; 2662 } 2663 } 2664 2665 return DELETE_PARTITION_PAGE; 2666 } 2667 2668 2669 static VOID 2670 ResetFileSystemList(VOID) 2671 { 2672 if (!FileSystemList) 2673 return; 2674 2675 DestroyFileSystemList(FileSystemList); 2676 FileSystemList = NULL; 2677 } 2678 2679 /* 2680 * Displays the SelectFileSystemPage. 2681 * 2682 * Next pages: 2683 * CheckFileSystemPage (At once if RepairUpdate is selected) 2684 * CheckFileSystemPage (At once if Unattended and not USetupData.FormatPartition) 2685 * FormatPartitionPage (At once if Unattended and USetupData.FormatPartition) 2686 * SelectPartitionPage (If the user aborts) 2687 * FormatPartitionPage (Default) 2688 * QuitPage 2689 * 2690 * SIDEEFFECTS 2691 * Calls UpdatePartitionType() 2692 * Calls CheckActiveSystemPartition() 2693 * 2694 * RETURNS 2695 * Number of the next page. 2696 */ 2697 static PAGE_NUMBER 2698 SelectFileSystemPage(PINPUT_RECORD Ir) 2699 { 2700 PPARTENTRY PartEntry; 2701 PDISKENTRY DiskEntry; 2702 ULONGLONG DiskSize; 2703 ULONGLONG PartSize; 2704 PCHAR DiskUnit; 2705 PCHAR PartUnit; 2706 CHAR PartTypeString[32]; 2707 FORMATMACHINESTATE PreviousFormatState; 2708 PCWSTR DefaultFs; 2709 2710 DPRINT("SelectFileSystemPage()\n"); 2711 2712 if (PartitionList == NULL || InstallPartition == NULL) 2713 { 2714 /* FIXME: show an error dialog */ 2715 return QUIT_PAGE; 2716 } 2717 2718 /* Find or set the active system partition when starting formatting */ 2719 if (FormatState == Start) 2720 { 2721 /* Find or set the active system partition */ 2722 CheckActiveSystemPartition(PartitionList, 2723 FALSE, 2724 InstallPartition->DiskEntry, 2725 InstallPartition); 2726 if (PartitionList->SystemPartition == NULL) 2727 { 2728 /* FIXME: show an error dialog */ 2729 // 2730 // Error dialog should say that we cannot find a suitable 2731 // system partition and create one on the system. At this point, 2732 // it may be nice to ask the user whether he wants to continue, 2733 // or use an external drive as the system drive/partition 2734 // (e.g. floppy, USB drive, etc...) 2735 // 2736 return QUIT_PAGE; 2737 } 2738 2739 /* 2740 * If the system partition can be created in some 2741 * non-partitioned space, create it now. 2742 */ 2743 if (!PartitionList->SystemPartition->IsPartitioned) 2744 { 2745 // if (IsUnattendedSetup) 2746 { 2747 CreatePrimaryPartition(PartitionList, 2748 PartitionList->SystemPartition, 2749 0LL, // PartitionList->SystemPartition->SectorCount.QuadPart, 2750 TRUE); 2751 ASSERT(PartitionList->SystemPartition->IsPartitioned); 2752 } 2753 // else 2754 { 2755 } 2756 } 2757 2758 /* Commit all partition changes to all the disks */ 2759 if (!WritePartitionsToDisk(PartitionList)) 2760 { 2761 DPRINT("WritePartitionsToDisk() failed\n"); 2762 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER); 2763 return QUIT_PAGE; 2764 } 2765 2766 /* 2767 * In all cases, whether or not we are going to perform a formatting, 2768 * we must perform a filesystem check of both the system and the 2769 * installation partitions. 2770 */ 2771 InstallPartition->NeedsCheck = TRUE; 2772 if (PartitionList->SystemPartition != InstallPartition) 2773 PartitionList->SystemPartition->NeedsCheck = TRUE; 2774 2775 /* 2776 * In case we just repair an existing installation, or make 2777 * an unattended setup without formatting, just go to the 2778 * filesystem check step. 2779 */ 2780 if (RepairUpdateFlag) 2781 return CHECK_FILE_SYSTEM_PAGE; 2782 2783 if (IsUnattendedSetup && !USetupData.FormatPartition) 2784 return CHECK_FILE_SYSTEM_PAGE; 2785 } 2786 2787 // ASSERT(PartitionList->SystemPartition->IsPartitioned); 2788 2789 /* Reset the filesystem list for each partition that is to be formatted */ 2790 ResetFileSystemList(); 2791 2792 PreviousFormatState = FormatState; 2793 switch (FormatState) 2794 { 2795 case Start: 2796 { 2797 /* 2798 * We start by formatting the system partition in case it is new 2799 * (it didn't exist before) and is not the same as the installation 2800 * partition. Otherwise we just require a filesystem check on it, 2801 * and start by formatting the installation partition instead. 2802 */ 2803 2804 ASSERT(PartitionList->SystemPartition->IsPartitioned); 2805 2806 if ((PartitionList->SystemPartition != InstallPartition) && 2807 (PartitionList->SystemPartition->FormatState == Unformatted)) 2808 { 2809 TempPartition = PartitionList->SystemPartition; 2810 TempPartition->NeedsCheck = TRUE; 2811 2812 // TODO: Should we let the user using a custom file-system, 2813 // or should we always use FAT(32) for it? 2814 // For "compatibility", FAT(32) would be best indeed. 2815 2816 FormatState = FormatSystemPartition; 2817 DPRINT1("FormatState: Start --> FormatSystemPartition\n"); 2818 } 2819 else 2820 { 2821 TempPartition = InstallPartition; 2822 TempPartition->NeedsCheck = TRUE; 2823 2824 if (PartitionList->SystemPartition != InstallPartition) 2825 { 2826 /* The system partition is separate, so it had better be formatted! */ 2827 ASSERT((PartitionList->SystemPartition->FormatState == Preformatted) || 2828 (PartitionList->SystemPartition->FormatState == Formatted)); 2829 2830 /* Require a filesystem check on the system partition too */ 2831 PartitionList->SystemPartition->NeedsCheck = TRUE; 2832 } 2833 2834 FormatState = FormatInstallPartition; 2835 DPRINT1("FormatState: Start --> FormatInstallPartition\n"); 2836 } 2837 break; 2838 } 2839 2840 case FormatSystemPartition: 2841 { 2842 TempPartition = InstallPartition; 2843 TempPartition->NeedsCheck = TRUE; 2844 2845 FormatState = FormatInstallPartition; 2846 DPRINT1("FormatState: FormatSystemPartition --> FormatInstallPartition\n"); 2847 break; 2848 } 2849 2850 case FormatInstallPartition: 2851 case FormatOtherPartition: 2852 { 2853 if (GetNextUnformattedPartition(PartitionList, 2854 NULL, 2855 &TempPartition)) 2856 { 2857 FormatState = FormatOtherPartition; 2858 TempPartition->NeedsCheck = TRUE; 2859 2860 if (FormatState == FormatInstallPartition) 2861 DPRINT1("FormatState: FormatInstallPartition --> FormatOtherPartition\n"); 2862 else 2863 DPRINT1("FormatState: FormatOtherPartition --> FormatOtherPartition\n"); 2864 } 2865 else 2866 { 2867 FormatState = FormatDone; 2868 2869 if (FormatState == FormatInstallPartition) 2870 DPRINT1("FormatState: FormatInstallPartition --> FormatDone\n"); 2871 else 2872 DPRINT1("FormatState: FormatOtherPartition --> FormatDone\n"); 2873 2874 return CHECK_FILE_SYSTEM_PAGE; 2875 } 2876 break; 2877 } 2878 2879 case FormatDone: 2880 { 2881 DPRINT1("FormatState: FormatDone\n"); 2882 return CHECK_FILE_SYSTEM_PAGE; 2883 } 2884 2885 default: 2886 { 2887 DPRINT1("FormatState: Invalid value %ld\n", FormatState); 2888 /* FIXME: show an error dialog */ 2889 return QUIT_PAGE; 2890 } 2891 } 2892 2893 PartEntry = TempPartition; 2894 DiskEntry = TempPartition->DiskEntry; 2895 2896 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); 2897 2898 /* Adjust disk size */ 2899 DiskSize = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2900 if (DiskSize >= 10 * GB) /* 10 GB */ 2901 { 2902 DiskSize = DiskSize / GB; 2903 DiskUnit = MUIGetString(STRING_GB); 2904 } 2905 else 2906 { 2907 DiskSize = DiskSize / MB; 2908 DiskUnit = MUIGetString(STRING_MB); 2909 } 2910 2911 /* Adjust partition size */ 2912 PartSize = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector; 2913 if (PartSize >= 10 * GB) /* 10 GB */ 2914 { 2915 PartSize = PartSize / GB; 2916 PartUnit = MUIGetString(STRING_GB); 2917 } 2918 else 2919 { 2920 PartSize = PartSize / MB; 2921 PartUnit = MUIGetString(STRING_MB); 2922 } 2923 2924 /* Adjust partition type */ 2925 GetPartTypeStringFromPartitionType(PartEntry->PartitionType, 2926 PartTypeString, 2927 ARRAYSIZE(PartTypeString)); 2928 2929 MUIDisplayPage(SELECT_FILE_SYSTEM_PAGE); 2930 2931 if (PartEntry->AutoCreate) 2932 { 2933 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NEWPARTITION)); 2934 2935 #if 0 2936 CONSOLE_PrintTextXY(8, 10, "Partition %lu (%I64u %s) %s of", 2937 PartEntry->PartitionNumber, 2938 PartSize, 2939 PartUnit, 2940 PartTypeString); 2941 #endif 2942 2943 CONSOLE_PrintTextXY(8, 10, MUIGetString(STRING_HDINFOPARTZEROED_1), 2944 DiskEntry->DiskNumber, 2945 DiskSize, 2946 DiskUnit, 2947 DiskEntry->Port, 2948 DiskEntry->Bus, 2949 DiskEntry->Id, 2950 &DiskEntry->DriverName, 2951 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 2952 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 2953 "RAW"); 2954 2955 CONSOLE_SetTextXY(6, 12, MUIGetString(STRING_PARTFORMAT)); 2956 2957 PartEntry->AutoCreate = FALSE; 2958 } 2959 else if (PartEntry->New) 2960 { 2961 switch (FormatState) 2962 { 2963 case FormatSystemPartition: 2964 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDSYSTEMPART)); 2965 break; 2966 2967 case FormatInstallPartition: 2968 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDPART)); 2969 break; 2970 2971 case FormatOtherPartition: 2972 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_NONFORMATTEDOTHERPART)); 2973 break; 2974 2975 default: 2976 break; 2977 } 2978 2979 CONSOLE_SetTextXY(6, 10, MUIGetString(STRING_PARTFORMAT)); 2980 } 2981 else 2982 { 2983 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_INSTALLONPART)); 2984 2985 if (*PartTypeString == '\0') // STRING_FORMATUNKNOWN ?? 2986 { 2987 CONSOLE_PrintTextXY(8, 10, 2988 MUIGetString(STRING_HDDINFOUNK4), 2989 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter, 2990 (PartEntry->DriveLetter == 0) ? '-' : ':', 2991 PartEntry->PartitionType, 2992 PartSize, 2993 PartUnit); 2994 } 2995 else 2996 { 2997 CONSOLE_PrintTextXY(8, 10, 2998 "%c%c %s %I64u %s", 2999 (PartEntry->DriveLetter == 0) ? '-' : (CHAR)PartEntry->DriveLetter, 3000 (PartEntry->DriveLetter == 0) ? '-' : ':', 3001 PartTypeString, 3002 PartSize, 3003 PartUnit); 3004 } 3005 3006 CONSOLE_PrintTextXY(6, 12, MUIGetString(STRING_HDINFOPARTEXISTS_1), 3007 DiskEntry->DiskNumber, 3008 DiskSize, 3009 DiskUnit, 3010 DiskEntry->Port, 3011 DiskEntry->Bus, 3012 DiskEntry->Id, 3013 &DiskEntry->DriverName, 3014 DiskEntry->DiskStyle == PARTITION_STYLE_MBR ? "MBR" : 3015 DiskEntry->DiskStyle == PARTITION_STYLE_GPT ? "GPT" : 3016 "RAW"); 3017 } 3018 3019 ASSERT(FileSystemList == NULL); 3020 3021 if (IsUnattendedSetup) 3022 { 3023 ASSERT(USetupData.FormatPartition); 3024 3025 switch (USetupData.FsType) 3026 { 3027 /* 1 is for BtrFS */ 3028 case 1: 3029 DefaultFs = L"BTRFS"; 3030 break; 3031 3032 /* If we don't understand input, default to FAT */ 3033 default: 3034 DefaultFs = L"FAT"; 3035 break; 3036 } 3037 } 3038 else 3039 { 3040 /* By default select the "FAT" file system */ 3041 DefaultFs = L"FAT"; 3042 } 3043 3044 /* Create the file system list */ 3045 // TODO: Display only the FSes compatible with the selected partition! 3046 FileSystemList = CreateFileSystemList(6, 26, 3047 PartEntry->New || 3048 PartEntry->FormatState == Unformatted, 3049 DefaultFs); 3050 if (FileSystemList == NULL) 3051 { 3052 /* FIXME: show an error dialog */ 3053 return QUIT_PAGE; 3054 } 3055 3056 if (IsUnattendedSetup) 3057 { 3058 ASSERT(USetupData.FormatPartition); 3059 return FORMAT_PARTITION_PAGE; 3060 } 3061 3062 DrawFileSystemList(FileSystemList); 3063 3064 while (TRUE) 3065 { 3066 CONSOLE_ConInKey(Ir); 3067 3068 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3069 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 3070 { 3071 if (ConfirmQuit(Ir)) 3072 { 3073 /* Reset the filesystem list */ 3074 ResetFileSystemList(); 3075 return QUIT_PAGE; 3076 } 3077 3078 break; 3079 } 3080 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3081 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)) /* ESC */ 3082 { 3083 /* Reset the formatter machine state */ 3084 TempPartition = NULL; 3085 FormatState = Start; 3086 3087 /* Reset the filesystem list */ 3088 ResetFileSystemList(); 3089 3090 return SELECT_PARTITION_PAGE; 3091 } 3092 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3093 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 3094 { 3095 ScrollDownFileSystemList(FileSystemList); 3096 } 3097 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3098 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 3099 { 3100 ScrollUpFileSystemList(FileSystemList); 3101 } 3102 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN) /* ENTER */ 3103 { 3104 if (!FileSystemList->Selected->FileSystem) 3105 { 3106 ASSERT(!TempPartition->New && TempPartition->FormatState != Unformatted); 3107 3108 /* 3109 * Skip formatting this partition. We will also ignore 3110 * filesystem checks on it, unless it is either the system 3111 * or the installation partition. 3112 */ 3113 if (TempPartition != PartitionList->SystemPartition && 3114 TempPartition != InstallPartition) 3115 { 3116 PartEntry->NeedsCheck = FALSE; 3117 } 3118 3119 return SELECT_FILE_SYSTEM_PAGE; 3120 } 3121 else 3122 { 3123 /* Format this partition */ 3124 return FORMAT_PARTITION_PAGE; 3125 } 3126 } 3127 } 3128 3129 FormatState = PreviousFormatState; 3130 3131 return SELECT_FILE_SYSTEM_PAGE; 3132 } 3133 3134 3135 /* 3136 * Displays the FormatPartitionPage. 3137 * 3138 * Next pages: 3139 * InstallDirectoryPage (At once if IsUnattendedSetup or InstallShortcut) 3140 * SelectPartitionPage (At once) 3141 * QuitPage 3142 * 3143 * SIDEEFFECTS 3144 * Sets InstallPartition->FormatState 3145 * Sets USetupData.DestinationRootPath 3146 * 3147 * RETURNS 3148 * Number of the next page. 3149 */ 3150 static PAGE_NUMBER 3151 FormatPartitionPage(PINPUT_RECORD Ir) 3152 { 3153 NTSTATUS Status; 3154 PPARTENTRY PartEntry; 3155 PDISKENTRY DiskEntry; 3156 PFILE_SYSTEM_ITEM SelectedFileSystem; 3157 UNICODE_STRING PartitionRootPath; 3158 WCHAR PathBuffer[MAX_PATH]; 3159 CHAR Buffer[MAX_PATH]; 3160 3161 #ifndef NDEBUG 3162 ULONG Line; 3163 ULONG i; 3164 PPARTITION_INFORMATION PartitionInfo; 3165 #endif 3166 3167 DPRINT("FormatPartitionPage()\n"); 3168 3169 MUIDisplayPage(FORMAT_PARTITION_PAGE); 3170 3171 if (PartitionList == NULL || TempPartition == NULL) 3172 { 3173 /* FIXME: show an error dialog */ 3174 return QUIT_PAGE; 3175 } 3176 3177 PartEntry = TempPartition; 3178 DiskEntry = TempPartition->DiskEntry; 3179 3180 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); 3181 3182 SelectedFileSystem = FileSystemList->Selected; 3183 ASSERT(SelectedFileSystem && SelectedFileSystem->FileSystem); 3184 3185 while (TRUE) 3186 { 3187 if (!IsUnattendedSetup) 3188 CONSOLE_ConInKey(Ir); 3189 3190 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3191 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 3192 { 3193 if (ConfirmQuit(Ir)) 3194 { 3195 /* Reset the filesystem list */ 3196 ResetFileSystemList(); 3197 return QUIT_PAGE; 3198 } 3199 3200 break; 3201 } 3202 else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN || IsUnattendedSetup) /* ENTER */ 3203 { 3204 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 3205 3206 if (!PreparePartitionForFormatting(PartEntry, SelectedFileSystem->FileSystem)) 3207 { 3208 /* FIXME: show an error dialog */ 3209 3210 /* Reset the filesystem list */ 3211 ResetFileSystemList(); 3212 3213 return QUIT_PAGE; 3214 } 3215 3216 #ifndef NDEBUG 3217 CONSOLE_PrintTextXY(6, 12, 3218 "Cylinders: %I64u Tracks/Cyl: %lu Sectors/Trk: %lu Bytes/Sec: %lu %c", 3219 DiskEntry->Cylinders, 3220 DiskEntry->TracksPerCylinder, 3221 DiskEntry->SectorsPerTrack, 3222 DiskEntry->BytesPerSector, 3223 DiskEntry->Dirty ? '*' : ' '); 3224 3225 Line = 13; 3226 3227 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++) 3228 { 3229 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i]; 3230 3231 CONSOLE_PrintTextXY(6, Line, 3232 "%2u: %2lu %c %12I64u %12I64u %02x", 3233 i, 3234 PartitionInfo->PartitionNumber, 3235 PartitionInfo->BootIndicator ? 'A' : '-', 3236 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector, 3237 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector, 3238 PartitionInfo->PartitionType); 3239 Line++; 3240 } 3241 #endif 3242 3243 /* Commit the partition changes to the disk */ 3244 Status = WritePartitions(DiskEntry); 3245 if (!NT_SUCCESS(Status)) 3246 { 3247 DPRINT1("WritePartitions(disk %lu) failed, Status 0x%08lx\n", 3248 DiskEntry->DiskNumber, Status); 3249 3250 MUIDisplayError(ERROR_WRITE_PTABLE, Ir, POPUP_WAIT_ENTER); 3251 3252 /* Reset the filesystem list */ 3253 ResetFileSystemList(); 3254 3255 return QUIT_PAGE; 3256 } 3257 3258 /* Set PartitionRootPath */ 3259 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 3260 L"\\Device\\Harddisk%lu\\Partition%lu", 3261 DiskEntry->DiskNumber, 3262 PartEntry->PartitionNumber); 3263 RtlInitUnicodeString(&PartitionRootPath, PathBuffer); 3264 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath); 3265 3266 /* Format the partition */ 3267 Status = FormatPartition(&PartitionRootPath, 3268 SelectedFileSystem->FileSystem, 3269 SelectedFileSystem->QuickFormat); 3270 if (Status == STATUS_NOT_SUPPORTED) 3271 { 3272 sprintf(Buffer, 3273 "Setup is currently unable to format a partition in %S.\n" 3274 "\n" 3275 " \x07 Press ENTER to continue Setup.\n" 3276 " \x07 Press F3 to quit Setup.", 3277 SelectedFileSystem->FileSystem); 3278 3279 PopupError(Buffer, 3280 MUIGetString(STRING_QUITCONTINUE), 3281 NULL, POPUP_WAIT_NONE); 3282 3283 while (TRUE) 3284 { 3285 CONSOLE_ConInKey(Ir); 3286 3287 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 && 3288 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */ 3289 { 3290 if (ConfirmQuit(Ir)) 3291 { 3292 /* Reset the filesystem list */ 3293 ResetFileSystemList(); 3294 return QUIT_PAGE; 3295 } 3296 else 3297 { 3298 return SELECT_FILE_SYSTEM_PAGE; 3299 } 3300 } 3301 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */ 3302 { 3303 return SELECT_FILE_SYSTEM_PAGE; 3304 } 3305 } 3306 } 3307 else if (!NT_SUCCESS(Status)) 3308 { 3309 DPRINT1("FormatPartition() failed with status 0x%08lx\n", Status); 3310 MUIDisplayError(ERROR_FORMATTING_PARTITION, Ir, POPUP_WAIT_ANY_KEY, PathBuffer); 3311 3312 /* Reset the filesystem list */ 3313 ResetFileSystemList(); 3314 3315 return QUIT_PAGE; 3316 } 3317 3318 // 3319 // TODO: Here, call a partlist.c function that update the actual FS name 3320 // and the label fields of the volume. 3321 // 3322 PartEntry->FormatState = Formatted; 3323 // PartEntry->FileSystem = FileSystem; 3324 PartEntry->New = FALSE; 3325 3326 #ifndef NDEBUG 3327 CONSOLE_SetStatusText(" Done. Press any key ..."); 3328 CONSOLE_ConInKey(Ir); 3329 #endif 3330 3331 return SELECT_FILE_SYSTEM_PAGE; 3332 } 3333 } 3334 3335 return FORMAT_PARTITION_PAGE; 3336 } 3337 3338 3339 /* 3340 * Displays the CheckFileSystemPage. 3341 * 3342 * Next pages: 3343 * InstallDirectoryPage (At once) 3344 * QuitPage 3345 * 3346 * SIDEEFFECTS 3347 * Inits or reloads FileSystemList 3348 * 3349 * RETURNS 3350 * Number of the next page. 3351 */ 3352 static PAGE_NUMBER 3353 CheckFileSystemPage(PINPUT_RECORD Ir) 3354 { 3355 NTSTATUS Status; 3356 PDISKENTRY DiskEntry; 3357 PPARTENTRY PartEntry; 3358 UNICODE_STRING PartitionRootPath; 3359 WCHAR PathBuffer[MAX_PATH]; 3360 CHAR Buffer[MAX_PATH]; 3361 3362 if (PartitionList == NULL) 3363 { 3364 /* FIXME: show an error dialog */ 3365 return QUIT_PAGE; 3366 } 3367 3368 if (!GetNextUncheckedPartition(PartitionList, &DiskEntry, &PartEntry)) 3369 { 3370 return INSTALL_DIRECTORY_PAGE; 3371 } 3372 3373 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); 3374 3375 CONSOLE_SetTextXY(6, 8, MUIGetString(STRING_CHECKINGPART)); 3376 3377 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 3378 3379 DPRINT1("CheckFileSystemPage -- PartitionType: 0x%02X ; FileSystem: %S\n", 3380 PartEntry->PartitionType, (*PartEntry->FileSystem ? PartEntry->FileSystem : L"n/a")); 3381 3382 /* HACK: Do not try to check a partition with an unknown filesystem */ 3383 if (!*PartEntry->FileSystem) 3384 { 3385 PartEntry->NeedsCheck = FALSE; 3386 return CHECK_FILE_SYSTEM_PAGE; 3387 } 3388 3389 /* Set PartitionRootPath */ 3390 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 3391 L"\\Device\\Harddisk%lu\\Partition%lu", 3392 DiskEntry->DiskNumber, 3393 PartEntry->PartitionNumber); 3394 RtlInitUnicodeString(&PartitionRootPath, PathBuffer); 3395 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath); 3396 3397 /* Check the partition */ 3398 Status = ChkdskPartition(&PartitionRootPath, PartEntry->FileSystem); 3399 if (Status == STATUS_NOT_SUPPORTED) 3400 { 3401 /* 3402 * Partition checking is not supported with the current filesystem, 3403 * so disable FS checks on it. 3404 */ 3405 PartEntry->NeedsCheck = FALSE; 3406 3407 RtlStringCbPrintfA(Buffer, 3408 sizeof(Buffer), 3409 "Setup is currently unable to check a partition formatted in %S.\n" 3410 "\n" 3411 " \x07 Press ENTER to continue Setup.\n" 3412 " \x07 Press F3 to quit Setup.", 3413 PartEntry->FileSystem); 3414 3415 PopupError(Buffer, 3416 MUIGetString(STRING_QUITCONTINUE), 3417 NULL, POPUP_WAIT_NONE); 3418 3419 while (TRUE) 3420 { 3421 CONSOLE_ConInKey(Ir); 3422 3423 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x00 && 3424 Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3) /* F3 */ 3425 { 3426 if (ConfirmQuit(Ir)) 3427 return QUIT_PAGE; 3428 else 3429 return CHECK_FILE_SYSTEM_PAGE; 3430 } 3431 else if (Ir->Event.KeyEvent.uChar.AsciiChar == VK_RETURN) /* ENTER */ 3432 { 3433 return CHECK_FILE_SYSTEM_PAGE; 3434 } 3435 } 3436 } 3437 else if (!NT_SUCCESS(Status)) 3438 { 3439 DPRINT("ChkdskPartition() failed with status 0x%08lx\n", Status); 3440 // sprintf(Buffer, "Setup failed to verify the selected partition.\n" 3441 sprintf(Buffer, "ChkDsk detected some disk errors.\n" 3442 "(Status 0x%08lx).\n", Status); 3443 PopupError(Buffer, 3444 // MUIGetString(STRING_REBOOTCOMPUTER), 3445 MUIGetString(STRING_CONTINUE), 3446 Ir, POPUP_WAIT_ENTER); 3447 3448 // return QUIT_PAGE; 3449 } 3450 3451 PartEntry->NeedsCheck = FALSE; 3452 return CHECK_FILE_SYSTEM_PAGE; 3453 } 3454 3455 3456 static NTSTATUS 3457 BuildInstallPaths( 3458 IN PCWSTR InstallDir, 3459 IN PPARTENTRY PartEntry) 3460 { 3461 NTSTATUS Status; 3462 3463 Status = InitDestinationPaths(&USetupData, InstallDir, PartEntry); 3464 3465 if (!NT_SUCCESS(Status)) 3466 { 3467 DPRINT1("InitDestinationPaths() failed with status 0x%08lx\n", Status); 3468 return Status; 3469 } 3470 3471 /* Initialize DestinationDriveLetter */ 3472 DestinationDriveLetter = PartEntry->DriveLetter; 3473 3474 return STATUS_SUCCESS; 3475 } 3476 3477 3478 static BOOLEAN 3479 IsValidPath( 3480 IN PCWSTR InstallDir) 3481 { 3482 UINT i, Length; 3483 3484 Length = wcslen(InstallDir); 3485 3486 // TODO: Add check for 8.3 too. 3487 3488 /* Path must be at least 2 characters long */ 3489 // if (Length < 2) 3490 // return FALSE; 3491 3492 /* Path must start with a backslash */ 3493 // if (InstallDir[0] != L'\\') 3494 // return FALSE; 3495 3496 /* Path must not end with a backslash */ 3497 if (InstallDir[Length - 1] == L'\\') 3498 return FALSE; 3499 3500 /* Path must not contain whitespace characters */ 3501 for (i = 0; i < Length; i++) 3502 { 3503 if (iswspace(InstallDir[i])) 3504 return FALSE; 3505 } 3506 3507 /* Path component must not end with a dot */ 3508 for (i = 0; i < Length; i++) 3509 { 3510 if (InstallDir[i] == L'\\' && i > 0) 3511 { 3512 if (InstallDir[i - 1] == L'.') 3513 return FALSE; 3514 } 3515 } 3516 3517 if (InstallDir[Length - 1] == L'.') 3518 return FALSE; 3519 3520 return TRUE; 3521 } 3522 3523 3524 /* 3525 * Displays the InstallDirectoryPage. 3526 * 3527 * Next pages: 3528 * PrepareCopyPage 3529 * QuitPage 3530 * 3531 * RETURNS 3532 * Number of the next page. 3533 */ 3534 static PAGE_NUMBER 3535 InstallDirectoryPage(PINPUT_RECORD Ir) 3536 { 3537 NTSTATUS Status; 3538 ULONG Length, Pos; 3539 WCHAR c; 3540 WCHAR InstallDir[MAX_PATH]; 3541 3542 /* We do not need the filesystem list anymore */ 3543 ResetFileSystemList(); 3544 3545 if (PartitionList == NULL || InstallPartition == NULL) 3546 { 3547 /* FIXME: show an error dialog */ 3548 return QUIT_PAGE; 3549 } 3550 3551 // if (IsUnattendedSetup) 3552 if (RepairUpdateFlag) 3553 wcscpy(InstallDir, CurrentInstallation->PathComponent); // SystemNtPath 3554 else if (USetupData.InstallationDirectory[0]) 3555 wcscpy(InstallDir, USetupData.InstallationDirectory); 3556 else 3557 wcscpy(InstallDir, L"\\ReactOS"); 3558 3559 /* 3560 * Check the validity of the predefined 'InstallDir'. If we are either 3561 * in unattended setup or in update/repair mode, and the installation path 3562 * is valid, just perform the installation. Otherwise (either in the case 3563 * of an invalid path, or we are in regular setup), display the UI and allow 3564 * the user to specify a new installation path. 3565 */ 3566 if ((RepairUpdateFlag || IsUnattendedSetup) && IsValidPath(InstallDir)) 3567 { 3568 Status = BuildInstallPaths(InstallDir, InstallPartition); 3569 if (!NT_SUCCESS(Status)) 3570 { 3571 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status); 3572 PopupError("Failed to build the installation paths for the ReactOS installation directory!", 3573 MUIGetString(STRING_CONTINUE), 3574 Ir, POPUP_WAIT_ENTER); 3575 return QUIT_PAGE; 3576 } 3577 3578 /* 3579 * Check whether the user attempts to install ReactOS within the 3580 * installation source directory, or in a subdirectory thereof. 3581 * If so, fail with an error. 3582 */ 3583 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE)) 3584 { 3585 PopupError("You cannot install ReactOS within the installation source directory!", 3586 MUIGetString(STRING_CONTINUE), 3587 Ir, POPUP_WAIT_ENTER); 3588 return INSTALL_DIRECTORY_PAGE; 3589 } 3590 3591 return PREPARE_COPY_PAGE; 3592 } 3593 3594 Length = wcslen(InstallDir); 3595 Pos = Length; 3596 3597 MUIDisplayPage(INSTALL_DIRECTORY_PAGE); 3598 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir); 3599 CONSOLE_SetCursorXY(8 + Pos, 11); 3600 CONSOLE_SetCursorType(TRUE, TRUE); 3601 3602 while (TRUE) 3603 { 3604 CONSOLE_ConInKey(Ir); 3605 3606 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3607 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 3608 { 3609 CONSOLE_SetCursorType(TRUE, FALSE); 3610 3611 if (ConfirmQuit(Ir)) 3612 return QUIT_PAGE; 3613 3614 CONSOLE_SetCursorType(TRUE, TRUE); 3615 break; 3616 } 3617 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3618 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DELETE)) /* DEL */ 3619 { 3620 if (Pos < Length) 3621 { 3622 memmove(&InstallDir[Pos], 3623 &InstallDir[Pos + 1], 3624 (Length - Pos - 1) * sizeof(WCHAR)); 3625 InstallDir[Length - 1] = UNICODE_NULL; 3626 3627 Length--; 3628 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir); 3629 CONSOLE_SetCursorXY(8 + Pos, 11); 3630 } 3631 } 3632 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3633 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */ 3634 { 3635 Pos = 0; 3636 CONSOLE_SetCursorXY(8 + Pos, 11); 3637 } 3638 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3639 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */ 3640 { 3641 Pos = Length; 3642 CONSOLE_SetCursorXY(8 + Pos, 11); 3643 } 3644 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3645 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_LEFT)) /* LEFT */ 3646 { 3647 if (Pos > 0) 3648 { 3649 Pos--; 3650 CONSOLE_SetCursorXY(8 + Pos, 11); 3651 } 3652 } 3653 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 3654 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)) /* RIGHT */ 3655 { 3656 if (Pos < Length) 3657 { 3658 Pos++; 3659 CONSOLE_SetCursorXY(8 + Pos, 11); 3660 } 3661 } 3662 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 3663 { 3664 CONSOLE_SetCursorType(TRUE, FALSE); 3665 3666 /* 3667 * Check for the validity of the installation directory and pop up 3668 * an error if it is not the case. Then the user can fix its input. 3669 */ 3670 if (!IsValidPath(InstallDir)) 3671 { 3672 MUIDisplayError(ERROR_DIRECTORY_NAME, Ir, POPUP_WAIT_ENTER); 3673 return INSTALL_DIRECTORY_PAGE; 3674 } 3675 3676 Status = BuildInstallPaths(InstallDir, InstallPartition); 3677 if (!NT_SUCCESS(Status)) 3678 { 3679 DPRINT1("BuildInstallPaths() failed. Status code: 0x%lx", Status); 3680 PopupError("Failed to build the installation paths for the ReactOS installation directory!", 3681 MUIGetString(STRING_CONTINUE), 3682 Ir, POPUP_WAIT_ENTER); 3683 return QUIT_PAGE; 3684 } 3685 3686 /* 3687 * Check whether the user attempts to install ReactOS within the 3688 * installation source directory, or in a subdirectory thereof. 3689 * If so, fail with an error. 3690 */ 3691 if (RtlPrefixUnicodeString(&USetupData.SourcePath, &USetupData.DestinationPath, TRUE)) 3692 { 3693 PopupError("You cannot install ReactOS within the installation source directory!", 3694 MUIGetString(STRING_CONTINUE), 3695 Ir, POPUP_WAIT_ENTER); 3696 return INSTALL_DIRECTORY_PAGE; 3697 } 3698 3699 return PREPARE_COPY_PAGE; 3700 } 3701 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x08) /* BACKSPACE */ 3702 { 3703 if (Pos > 0) 3704 { 3705 if (Pos < Length) 3706 memmove(&InstallDir[Pos - 1], 3707 &InstallDir[Pos], 3708 (Length - Pos) * sizeof(WCHAR)); 3709 InstallDir[Length - 1] = UNICODE_NULL; 3710 3711 Pos--; 3712 Length--; 3713 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir); 3714 CONSOLE_SetCursorXY(8 + Pos, 11); 3715 } 3716 } 3717 else if (isprint(Ir->Event.KeyEvent.uChar.AsciiChar)) 3718 { 3719 if (Length < 50) 3720 { 3721 c = (WCHAR)Ir->Event.KeyEvent.uChar.AsciiChar; 3722 if (iswalpha(c) || iswdigit(c) || c == '.' || c == '\\' || c == '-' || c == '_') 3723 { 3724 if (Pos < Length) 3725 memmove(&InstallDir[Pos + 1], 3726 &InstallDir[Pos], 3727 (Length - Pos) * sizeof(WCHAR)); 3728 InstallDir[Length + 1] = UNICODE_NULL; 3729 InstallDir[Pos] = c; 3730 3731 Pos++; 3732 Length++; 3733 CONSOLE_SetInputTextXY(8, 11, 51, InstallDir); 3734 CONSOLE_SetCursorXY(8 + Pos, 11); 3735 } 3736 } 3737 } 3738 } 3739 3740 return INSTALL_DIRECTORY_PAGE; 3741 } 3742 3743 3744 // PSETUP_ERROR_ROUTINE 3745 static VOID 3746 __cdecl 3747 USetupErrorRoutine( 3748 IN PUSETUP_DATA pSetupData, 3749 ...) 3750 { 3751 INPUT_RECORD Ir; 3752 va_list arg_ptr; 3753 3754 va_start(arg_ptr, pSetupData); 3755 3756 if (pSetupData->LastErrorNumber >= ERROR_SUCCESS && 3757 pSetupData->LastErrorNumber < ERROR_LAST_ERROR_CODE) 3758 { 3759 // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber... 3760 MUIDisplayErrorV(pSetupData->LastErrorNumber, &Ir, POPUP_WAIT_ENTER, arg_ptr); 3761 } 3762 3763 va_end(arg_ptr); 3764 } 3765 3766 /* 3767 * Displays the PrepareCopyPage. 3768 * 3769 * Next pages: 3770 * FileCopyPage(At once) 3771 * QuitPage 3772 * 3773 * SIDEEFFECTS 3774 * Calls PrepareFileCopy 3775 * 3776 * RETURNS 3777 * Number of the next page. 3778 */ 3779 static PAGE_NUMBER 3780 PrepareCopyPage(PINPUT_RECORD Ir) 3781 { 3782 // ERROR_NUMBER ErrorNumber; 3783 BOOLEAN Success; 3784 3785 MUIDisplayPage(PREPARE_COPY_PAGE); 3786 3787 /* ErrorNumber = */ Success = PrepareFileCopy(&USetupData, NULL); 3788 if (/*ErrorNumber != ERROR_SUCCESS*/ !Success) 3789 { 3790 // MUIDisplayError(ErrorNumber, Ir, POPUP_WAIT_ENTER); 3791 return QUIT_PAGE; 3792 } 3793 3794 return FILE_COPY_PAGE; 3795 } 3796 3797 typedef struct _COPYCONTEXT 3798 { 3799 ULONG TotalOperations; 3800 ULONG CompletedOperations; 3801 PPROGRESSBAR ProgressBar; 3802 PPROGRESSBAR MemoryBars[4]; 3803 } COPYCONTEXT, *PCOPYCONTEXT; 3804 3805 static VOID 3806 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext, 3807 IN BOOLEAN First) 3808 { 3809 SYSTEM_PERFORMANCE_INFORMATION PerfInfo; 3810 3811 /* Get the memory information from the system */ 3812 NtQuerySystemInformation(SystemPerformanceInformation, 3813 &PerfInfo, 3814 sizeof(PerfInfo), 3815 NULL); 3816 3817 /* Check if this is initial setup */ 3818 if (First) 3819 { 3820 /* Set maximum limits to be total RAM pages */ 3821 ProgressSetStepCount(CopyContext->MemoryBars[0], PerfInfo.CommitLimit); 3822 ProgressSetStepCount(CopyContext->MemoryBars[1], PerfInfo.CommitLimit); 3823 ProgressSetStepCount(CopyContext->MemoryBars[2], PerfInfo.CommitLimit); 3824 } 3825 3826 /* Set current values */ 3827 ProgressSetStep(CopyContext->MemoryBars[0], PerfInfo.PagedPoolPages + PerfInfo.NonPagedPoolPages); 3828 ProgressSetStep(CopyContext->MemoryBars[1], PerfInfo.ResidentSystemCachePage); 3829 ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages); 3830 } 3831 3832 static UINT 3833 CALLBACK 3834 FileCopyCallback(PVOID Context, 3835 UINT Notification, 3836 UINT_PTR Param1, 3837 UINT_PTR Param2) 3838 { 3839 PCOPYCONTEXT CopyContext = (PCOPYCONTEXT)Context; 3840 PFILEPATHS_W FilePathInfo; 3841 PCWSTR SrcFileName, DstFileName; 3842 3843 switch (Notification) 3844 { 3845 case SPFILENOTIFY_STARTSUBQUEUE: 3846 { 3847 CopyContext->TotalOperations = (ULONG)Param2; 3848 CopyContext->CompletedOperations = 0; 3849 ProgressSetStepCount(CopyContext->ProgressBar, 3850 CopyContext->TotalOperations); 3851 SetupUpdateMemoryInfo(CopyContext, TRUE); 3852 break; 3853 } 3854 3855 case SPFILENOTIFY_STARTDELETE: 3856 case SPFILENOTIFY_STARTRENAME: 3857 case SPFILENOTIFY_STARTCOPY: 3858 { 3859 FilePathInfo = (PFILEPATHS_W)Param1; 3860 3861 if (Notification == SPFILENOTIFY_STARTDELETE) 3862 { 3863 /* Display delete message */ 3864 ASSERT(Param2 == FILEOP_DELETE); 3865 3866 DstFileName = wcsrchr(FilePathInfo->Target, L'\\'); 3867 if (DstFileName) ++DstFileName; 3868 else DstFileName = FilePathInfo->Target; 3869 3870 CONSOLE_SetStatusText(MUIGetString(STRING_DELETING), 3871 DstFileName); 3872 } 3873 else if (Notification == SPFILENOTIFY_STARTRENAME) 3874 { 3875 /* Display move/rename message */ 3876 ASSERT(Param2 == FILEOP_RENAME); 3877 3878 SrcFileName = wcsrchr(FilePathInfo->Source, L'\\'); 3879 if (SrcFileName) ++SrcFileName; 3880 else SrcFileName = FilePathInfo->Source; 3881 3882 DstFileName = wcsrchr(FilePathInfo->Target, L'\\'); 3883 if (DstFileName) ++DstFileName; 3884 else DstFileName = FilePathInfo->Target; 3885 3886 if (!wcsicmp(SrcFileName, DstFileName)) 3887 Param2 = STRING_MOVING; 3888 else 3889 Param2 = STRING_RENAMING; 3890 3891 CONSOLE_SetStatusText(MUIGetString(Param2), 3892 SrcFileName, DstFileName); 3893 } 3894 else if (Notification == SPFILENOTIFY_STARTCOPY) 3895 { 3896 /* Display copy message */ 3897 ASSERT(Param2 == FILEOP_COPY); 3898 3899 /* NOTE: When extracting from CABs the Source is the CAB name */ 3900 DstFileName = wcsrchr(FilePathInfo->Target, L'\\'); 3901 if (DstFileName) ++DstFileName; 3902 else DstFileName = FilePathInfo->Target; 3903 3904 CONSOLE_SetStatusText(MUIGetString(STRING_COPYING), 3905 DstFileName); 3906 } 3907 3908 SetupUpdateMemoryInfo(CopyContext, FALSE); 3909 break; 3910 } 3911 3912 case SPFILENOTIFY_COPYERROR: 3913 { 3914 FilePathInfo = (PFILEPATHS_W)Param1; 3915 3916 DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n", 3917 FilePathInfo->Target, FilePathInfo->Win32Error); 3918 return FILEOP_SKIP; 3919 } 3920 3921 case SPFILENOTIFY_ENDDELETE: 3922 case SPFILENOTIFY_ENDRENAME: 3923 case SPFILENOTIFY_ENDCOPY: 3924 { 3925 CopyContext->CompletedOperations++; 3926 3927 /* SYSREG checkpoint */ 3928 if (CopyContext->TotalOperations >> 1 == CopyContext->CompletedOperations) 3929 DPRINT1("CHECKPOINT:HALF_COPIED\n"); 3930 3931 ProgressNextStep(CopyContext->ProgressBar); 3932 SetupUpdateMemoryInfo(CopyContext, FALSE); 3933 break; 3934 } 3935 } 3936 3937 return FILEOP_DOIT; 3938 } 3939 3940 3941 /* 3942 * Displays the FileCopyPage. 3943 * 3944 * Next pages: 3945 * RegistryPage(At once) 3946 * 3947 * SIDEEFFECTS 3948 * Calls DoFileCopy 3949 * 3950 * RETURNS 3951 * Number of the next page. 3952 */ 3953 static PAGE_NUMBER 3954 FileCopyPage(PINPUT_RECORD Ir) 3955 { 3956 COPYCONTEXT CopyContext; 3957 UINT MemBarWidth; 3958 3959 MUIDisplayPage(FILE_COPY_PAGE); 3960 3961 /* Create context for the copy process */ 3962 CopyContext.TotalOperations = 0; 3963 CopyContext.CompletedOperations = 0; 3964 3965 /* Create the progress bar as well */ 3966 CopyContext.ProgressBar = CreateProgressBar(13, 3967 26, 3968 xScreen - 13, 3969 yScreen - 20, 3970 10, 3971 24, 3972 TRUE, 3973 MUIGetString(STRING_SETUPCOPYINGFILES)); 3974 3975 // fit memory bars to screen width, distribute them uniform 3976 MemBarWidth = (xScreen - 26) / 5; 3977 MemBarWidth -= MemBarWidth % 2; // make even 3978 /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */ 3979 /* Create the paged pool progress bar */ 3980 CopyContext.MemoryBars[0] = CreateProgressBar(13, 3981 40, 3982 13 + MemBarWidth, 3983 43, 3984 13, 3985 44, 3986 FALSE, 3987 "Kernel Pool"); 3988 3989 /* Create the non paged pool progress bar */ 3990 CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (MemBarWidth / 2), 3991 40, 3992 (xScreen / 2) + (MemBarWidth / 2), 3993 43, 3994 (xScreen / 2)- (MemBarWidth / 2), 3995 44, 3996 FALSE, 3997 "Kernel Cache"); 3998 3999 /* Create the global memory progress bar */ 4000 CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - MemBarWidth, 4001 40, 4002 xScreen - 13, 4003 43, 4004 xScreen - 13 - MemBarWidth, 4005 44, 4006 FALSE, 4007 "Free Memory"); 4008 4009 /* Do the file copying */ 4010 DoFileCopy(&USetupData, FileCopyCallback, &CopyContext); 4011 4012 /* If we get here, we're done, so cleanup the progress bar */ 4013 DestroyProgressBar(CopyContext.ProgressBar); 4014 DestroyProgressBar(CopyContext.MemoryBars[0]); 4015 DestroyProgressBar(CopyContext.MemoryBars[1]); 4016 DestroyProgressBar(CopyContext.MemoryBars[2]); 4017 4018 /* Create the $winnt$.inf file */ 4019 InstallSetupInfFile(&USetupData); 4020 4021 /* Go display the next page */ 4022 return REGISTRY_PAGE; 4023 } 4024 4025 4026 static VOID 4027 __cdecl 4028 RegistryStatus(IN REGISTRY_STATUS RegStatus, ...) 4029 { 4030 /* WARNING: Please keep this lookup table in sync with the resources! */ 4031 static const UINT StringIDs[] = 4032 { 4033 STRING_DONE, /* Success */ 4034 STRING_REGHIVEUPDATE, /* RegHiveUpdate */ 4035 STRING_IMPORTFILE, /* ImportRegHive */ 4036 STRING_DISPLAYSETTINGSUPDATE, /* DisplaySettingsUpdate */ 4037 STRING_LOCALESETTINGSUPDATE, /* LocaleSettingsUpdate */ 4038 STRING_ADDKBLAYOUTS, /* KeybLayouts */ 4039 STRING_KEYBOARDSETTINGSUPDATE, /* KeybSettingsUpdate */ 4040 STRING_CODEPAGEINFOUPDATE, /* CodePageInfoUpdate */ 4041 }; 4042 4043 va_list args; 4044 4045 if (RegStatus < ARRAYSIZE(StringIDs)) 4046 { 4047 va_start(args, RegStatus); 4048 CONSOLE_SetStatusTextV(MUIGetString(StringIDs[RegStatus]), args); 4049 va_end(args); 4050 } 4051 else 4052 { 4053 CONSOLE_SetStatusText("Unknown status %d", RegStatus); 4054 } 4055 } 4056 4057 /* 4058 * Displays the RegistryPage. 4059 * 4060 * Next pages: 4061 * SuccessPage (if RepairUpdate) 4062 * BootLoaderPage (default) 4063 * QuitPage 4064 * 4065 * SIDEEFFECTS 4066 * Calls UpdateRegistry 4067 * 4068 * RETURNS 4069 * Number of the next page. 4070 */ 4071 static PAGE_NUMBER 4072 RegistryPage(PINPUT_RECORD Ir) 4073 { 4074 ULONG Error; 4075 4076 MUIDisplayPage(REGISTRY_PAGE); 4077 4078 Error = UpdateRegistry(&USetupData, 4079 RepairUpdateFlag, 4080 PartitionList, 4081 DestinationDriveLetter, 4082 SelectedLanguageId, 4083 RegistryStatus); 4084 if (Error != ERROR_SUCCESS) 4085 { 4086 MUIDisplayError(Error, Ir, POPUP_WAIT_ENTER); 4087 return QUIT_PAGE; 4088 } 4089 else 4090 { 4091 CONSOLE_SetStatusText(MUIGetString(STRING_DONE)); 4092 return BOOT_LOADER_PAGE; 4093 } 4094 } 4095 4096 4097 /* 4098 * Displays the BootLoaderPage. 4099 * 4100 * Next pages: 4101 * SuccessPage (if RepairUpdate) 4102 * BootLoaderHarddiskMbrPage 4103 * BootLoaderHarddiskVbrPage 4104 * BootLoaderFloppyPage 4105 * SuccessPage 4106 * QuitPage 4107 * 4108 * SIDEEFFECTS 4109 * Calls RegInitializeRegistry 4110 * Calls ImportRegistryFile 4111 * Calls SetDefaultPagefile 4112 * Calls SetMountedDeviceValues 4113 * 4114 * RETURNS 4115 * Number of the next page. 4116 */ 4117 static PAGE_NUMBER 4118 BootLoaderPage(PINPUT_RECORD Ir) 4119 { 4120 UCHAR PartitionType; 4121 BOOLEAN InstallOnFloppy; 4122 USHORT Line = 12; 4123 WCHAR PathBuffer[MAX_PATH]; 4124 4125 CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 4126 4127 ASSERT(PartitionList->SystemPartition->IsPartitioned && PartitionList->SystemPartition->PartitionNumber != 0); 4128 4129 RtlFreeUnicodeString(&USetupData.SystemRootPath); 4130 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 4131 L"\\Device\\Harddisk%lu\\Partition%lu\\", 4132 PartitionList->SystemPartition->DiskEntry->DiskNumber, 4133 PartitionList->SystemPartition->PartitionNumber); 4134 RtlCreateUnicodeString(&USetupData.SystemRootPath, PathBuffer); 4135 DPRINT1("SystemRootPath: %wZ\n", &USetupData.SystemRootPath); 4136 4137 PartitionType = PartitionList->SystemPartition->PartitionType; 4138 4139 /* For unattended setup, skip MBR installation or install on floppy if needed */ 4140 if (IsUnattendedSetup) 4141 { 4142 if ((USetupData.MBRInstallType == 0) || 4143 (USetupData.MBRInstallType == 1)) 4144 { 4145 goto Quit; 4146 } 4147 } 4148 4149 /* 4150 * We may install an MBR or VBR, but before that, check whether 4151 * we need to actually install the VBR on floppy. 4152 */ 4153 if (PartitionType == PARTITION_ENTRY_UNUSED) 4154 { 4155 DPRINT("Error: system partition invalid (unused)\n"); 4156 InstallOnFloppy = TRUE; 4157 } 4158 else if (PartitionType == PARTITION_OS2BOOTMGR) 4159 { 4160 /* OS/2 boot manager partition */ 4161 DPRINT("Found OS/2 boot manager partition\n"); 4162 InstallOnFloppy = TRUE; 4163 } 4164 else if (PartitionType == PARTITION_LINUX) 4165 { 4166 /* Linux partition */ 4167 DPRINT("Found Linux native partition (ext2/ext3/ReiserFS/BTRFS/etc)\n"); 4168 InstallOnFloppy = FALSE; 4169 } 4170 else if (PartitionType == PARTITION_IFS) 4171 { 4172 /* NTFS partition */ 4173 DPRINT("Found NTFS partition\n"); 4174 4175 // FIXME: Make it FALSE when we'll support NTFS installation! 4176 InstallOnFloppy = TRUE; 4177 } 4178 else if ((PartitionType == PARTITION_FAT_12) || 4179 (PartitionType == PARTITION_FAT_16) || 4180 (PartitionType == PARTITION_HUGE) || 4181 (PartitionType == PARTITION_XINT13) || 4182 (PartitionType == PARTITION_FAT32) || 4183 (PartitionType == PARTITION_FAT32_XINT13)) 4184 { 4185 DPRINT("Found FAT partition\n"); 4186 InstallOnFloppy = FALSE; 4187 } 4188 else 4189 { 4190 /* Unknown partition */ 4191 DPRINT("Unknown partition found\n"); 4192 InstallOnFloppy = TRUE; 4193 } 4194 4195 /* We should install on floppy */ 4196 if (InstallOnFloppy) 4197 { 4198 USetupData.MBRInstallType = 1; 4199 goto Quit; 4200 } 4201 4202 /* Is it an unattended install on hdd? */ 4203 if (IsUnattendedSetup) 4204 { 4205 if ((USetupData.MBRInstallType == 2) || 4206 (USetupData.MBRInstallType == 3)) 4207 { 4208 goto Quit; 4209 } 4210 } 4211 4212 MUIDisplayPage(BOOT_LOADER_PAGE); 4213 CONSOLE_InvertTextXY(8, Line, 60, 1); 4214 4215 while (TRUE) 4216 { 4217 CONSOLE_ConInKey(Ir); 4218 4219 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 4220 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN)) /* DOWN */ 4221 { 4222 CONSOLE_NormalTextXY(8, Line, 60, 1); 4223 4224 Line++; 4225 if (Line < 12) 4226 Line = 15; 4227 4228 if (Line > 15) 4229 Line = 12; 4230 4231 CONSOLE_InvertTextXY(8, Line, 60, 1); 4232 } 4233 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 4234 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_UP)) /* UP */ 4235 { 4236 CONSOLE_NormalTextXY(8, Line, 60, 1); 4237 4238 Line--; 4239 if (Line < 12) 4240 Line = 15; 4241 4242 if (Line > 15) 4243 Line = 12; 4244 4245 CONSOLE_InvertTextXY(8, Line, 60, 1); 4246 } 4247 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 4248 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_HOME)) /* HOME */ 4249 { 4250 CONSOLE_NormalTextXY(8, Line, 60, 1); 4251 4252 Line = 12; 4253 4254 CONSOLE_InvertTextXY(8, Line, 60, 1); 4255 } 4256 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 4257 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_END)) /* END */ 4258 { 4259 CONSOLE_NormalTextXY(8, Line, 60, 1); 4260 4261 Line = 15; 4262 4263 CONSOLE_InvertTextXY(8, Line, 60, 1); 4264 } 4265 else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 4266 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 4267 { 4268 if (ConfirmQuit(Ir)) 4269 return QUIT_PAGE; 4270 4271 break; 4272 } 4273 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 4274 { 4275 if (Line == 12) 4276 { 4277 /* Install on both MBR and VBR */ 4278 USetupData.MBRInstallType = 2; 4279 break; 4280 } 4281 else if (Line == 13) 4282 { 4283 /* Install on VBR only */ 4284 USetupData.MBRInstallType = 3; 4285 break; 4286 } 4287 else if (Line == 14) 4288 { 4289 /* Install on floppy */ 4290 USetupData.MBRInstallType = 1; 4291 break; 4292 } 4293 else if (Line == 15) 4294 { 4295 /* Skip MBR installation */ 4296 USetupData.MBRInstallType = 0; 4297 break; 4298 } 4299 4300 return BOOT_LOADER_PAGE; 4301 } 4302 } 4303 4304 Quit: 4305 switch (USetupData.MBRInstallType) 4306 { 4307 /* Skip MBR installation */ 4308 case 0: 4309 return SUCCESS_PAGE; 4310 4311 /* Install on floppy */ 4312 case 1: 4313 return BOOT_LOADER_FLOPPY_PAGE; 4314 4315 /* Install on both MBR and VBR */ 4316 case 2: 4317 return BOOT_LOADER_HARDDISK_MBR_PAGE; 4318 4319 /* Install on VBR only */ 4320 case 3: 4321 return BOOT_LOADER_HARDDISK_VBR_PAGE; 4322 } 4323 4324 return BOOT_LOADER_PAGE; 4325 } 4326 4327 4328 /* 4329 * Displays the BootLoaderFloppyPage. 4330 * 4331 * Next pages: 4332 * SuccessPage (At once) 4333 * QuitPage 4334 * 4335 * SIDEEFFECTS 4336 * Calls InstallFatBootcodeToFloppy() 4337 * 4338 * RETURNS 4339 * Number of the next page. 4340 */ 4341 static PAGE_NUMBER 4342 BootLoaderFloppyPage(PINPUT_RECORD Ir) 4343 { 4344 NTSTATUS Status; 4345 4346 MUIDisplayPage(BOOT_LOADER_FLOPPY_PAGE); 4347 4348 // CONSOLE_SetStatusText(MUIGetString(STRING_PLEASEWAIT)); 4349 4350 while (TRUE) 4351 { 4352 CONSOLE_ConInKey(Ir); 4353 4354 if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) && 4355 (Ir->Event.KeyEvent.wVirtualKeyCode == VK_F3)) /* F3 */ 4356 { 4357 if (ConfirmQuit(Ir)) 4358 return QUIT_PAGE; 4359 4360 break; 4361 } 4362 else if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 4363 { 4364 Status = InstallFatBootcodeToFloppy(&USetupData.SourceRootPath, 4365 &USetupData.DestinationArcPath); 4366 if (!NT_SUCCESS(Status)) 4367 { 4368 if (Status == STATUS_DEVICE_NOT_READY) 4369 MUIDisplayError(ERROR_NO_FLOPPY, Ir, POPUP_WAIT_ENTER); 4370 4371 /* TODO: Print error message */ 4372 return BOOT_LOADER_FLOPPY_PAGE; 4373 } 4374 4375 return SUCCESS_PAGE; 4376 } 4377 } 4378 4379 return BOOT_LOADER_FLOPPY_PAGE; 4380 } 4381 4382 4383 /* 4384 * Displays the BootLoaderHarddiskVbrPage. 4385 * 4386 * Next pages: 4387 * SuccessPage (At once) 4388 * QuitPage 4389 * 4390 * SIDEEFFECTS 4391 * Calls InstallVBRToPartition() 4392 * 4393 * RETURNS 4394 * Number of the next page. 4395 */ 4396 static PAGE_NUMBER 4397 BootLoaderHarddiskVbrPage(PINPUT_RECORD Ir) 4398 { 4399 NTSTATUS Status; 4400 4401 // FIXME! We must not use the partition type, but instead use the partition FileSystem!! 4402 Status = InstallVBRToPartition(&USetupData.SystemRootPath, 4403 &USetupData.SourceRootPath, 4404 &USetupData.DestinationArcPath, 4405 PartitionList->SystemPartition->PartitionType); 4406 if (!NT_SUCCESS(Status)) 4407 { 4408 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER, 4409 PartitionList->SystemPartition->FileSystem); 4410 return QUIT_PAGE; 4411 } 4412 4413 return SUCCESS_PAGE; 4414 } 4415 4416 4417 /* 4418 * Displays the BootLoaderHarddiskMbrPage. 4419 * 4420 * Next pages: 4421 * SuccessPage (At once) 4422 * QuitPage 4423 * 4424 * SIDEEFFECTS 4425 * Calls InstallVBRToPartition() 4426 * Calls InstallMbrBootCodeToDisk() 4427 * 4428 * RETURNS 4429 * Number of the next page. 4430 */ 4431 static PAGE_NUMBER 4432 BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir) 4433 { 4434 NTSTATUS Status; 4435 WCHAR DestinationDevicePathBuffer[MAX_PATH]; 4436 4437 /* Step 1: Write the VBR */ 4438 // FIXME! We must not use the partition type, but instead use the partition FileSystem!! 4439 Status = InstallVBRToPartition(&USetupData.SystemRootPath, 4440 &USetupData.SourceRootPath, 4441 &USetupData.DestinationArcPath, 4442 PartitionList->SystemPartition->PartitionType); 4443 if (!NT_SUCCESS(Status)) 4444 { 4445 MUIDisplayError(ERROR_WRITE_BOOT, Ir, POPUP_WAIT_ENTER, 4446 PartitionList->SystemPartition->FileSystem); 4447 return QUIT_PAGE; 4448 } 4449 4450 /* Step 2: Write the MBR if the disk containing the system partition is not a super-floppy */ 4451 if (!IsSuperFloppy(PartitionList->SystemPartition->DiskEntry)) 4452 { 4453 RtlStringCchPrintfW(DestinationDevicePathBuffer, ARRAYSIZE(DestinationDevicePathBuffer), 4454 L"\\Device\\Harddisk%d\\Partition0", 4455 PartitionList->SystemPartition->DiskEntry->DiskNumber); 4456 Status = InstallMbrBootCodeToDisk(&USetupData.SystemRootPath, 4457 &USetupData.SourceRootPath, 4458 DestinationDevicePathBuffer); 4459 if (!NT_SUCCESS(Status)) 4460 { 4461 DPRINT1("InstallMbrBootCodeToDisk() failed (Status %lx)\n", Status); 4462 MUIDisplayError(ERROR_INSTALL_BOOTCODE, Ir, POPUP_WAIT_ENTER, L"MBR"); 4463 return QUIT_PAGE; 4464 } 4465 } 4466 4467 return SUCCESS_PAGE; 4468 } 4469 4470 4471 /** 4472 * @name ProgressTimeOutStringHandler 4473 * 4474 * Handles the generation (displaying) of the timeout 4475 * countdown to the screen dynamically. 4476 * 4477 * @param Bar 4478 * A pointer to a progress bar. 4479 * 4480 * @param AlwaysUpdate 4481 * Constantly update the progress bar (boolean type). 4482 * 4483 * @param Buffer 4484 * A pointer to a string buffer. 4485 * 4486 * @param cchBufferSize 4487 * The buffer's size in number of characters. 4488 * 4489 * @return 4490 * TRUE or FALSE on function termination. 4491 * 4492 */ 4493 static 4494 BOOLEAN NTAPI 4495 ProgressTimeOutStringHandler( 4496 IN PPROGRESSBAR Bar, 4497 IN BOOLEAN AlwaysUpdate, 4498 OUT PSTR Buffer, 4499 IN SIZE_T cchBufferSize) 4500 { 4501 ULONG OldProgress = Bar->Progress; 4502 4503 if (Bar->StepCount == 0) 4504 { 4505 Bar->Progress = 0; 4506 } 4507 else 4508 { 4509 Bar->Progress = Bar->StepCount - Bar->CurrentStep; 4510 } 4511 4512 /* Build the progress string if it has changed */ 4513 if (Bar->ProgressFormatText && 4514 (AlwaysUpdate || (Bar->Progress != OldProgress))) 4515 { 4516 RtlStringCchPrintfA(Buffer, cchBufferSize, 4517 Bar->ProgressFormatText, Bar->Progress / max(1, Bar->Width) + 1); 4518 4519 return TRUE; 4520 } 4521 4522 return FALSE; 4523 } 4524 4525 /** 4526 * @name ProgressCountdown 4527 * 4528 * Displays and draws a red-coloured progress bar with a countdown. 4529 * When the timeout is reached, the flush page is displayed for reboot. 4530 * 4531 * @param Ir 4532 * A pointer to an input keyboard record. 4533 * 4534 * @param TimeOut 4535 * Initial countdown value in seconds. 4536 * 4537 * @return 4538 * Nothing. 4539 * 4540 */ 4541 static VOID 4542 ProgressCountdown( 4543 IN PINPUT_RECORD Ir, 4544 IN LONG TimeOut) 4545 { 4546 NTSTATUS Status; 4547 ULONG StartTime, BarWidth, TimerDiv; 4548 LONG TimeElapsed; 4549 LONG TimerValue, OldTimerValue; 4550 LARGE_INTEGER Timeout; 4551 PPROGRESSBAR ProgressBar; 4552 BOOLEAN RefreshProgress = TRUE; 4553 4554 /* Bail out if the timeout is already zero */ 4555 if (TimeOut <= 0) 4556 return; 4557 4558 /* Create the timeout progress bar and set it up */ 4559 ProgressBar = CreateProgressBarEx(13, 4560 26, 4561 xScreen - 13, 4562 yScreen - 20, 4563 10, 4564 24, 4565 TRUE, 4566 FOREGROUND_RED | BACKGROUND_BLUE, 4567 0, 4568 NULL, 4569 MUIGetString(STRING_REBOOTPROGRESSBAR), 4570 ProgressTimeOutStringHandler); 4571 4572 BarWidth = max(1, ProgressBar->Width); 4573 TimerValue = TimeOut * BarWidth; 4574 ProgressSetStepCount(ProgressBar, TimerValue); 4575 4576 StartTime = NtGetTickCount(); 4577 CONSOLE_Flush(); 4578 4579 TimerDiv = 1000 / BarWidth; 4580 TimerDiv = max(1, TimerDiv); 4581 OldTimerValue = TimerValue; 4582 while (TRUE) 4583 { 4584 /* Decrease the timer */ 4585 4586 /* 4587 * Compute how much time the previous operations took. 4588 * This allows us in particular to take account for any time 4589 * elapsed if something slowed down. 4590 */ 4591 TimeElapsed = NtGetTickCount() - StartTime; 4592 if (TimeElapsed >= TimerDiv) 4593 { 4594 /* Increase StartTime by steps of 1 / ProgressBar->Width seconds */ 4595 TimeElapsed /= TimerDiv; 4596 StartTime += (TimerDiv * TimeElapsed); 4597 4598 if (TimeElapsed <= TimerValue) 4599 TimerValue -= TimeElapsed; 4600 else 4601 TimerValue = 0; 4602 4603 RefreshProgress = TRUE; 4604 } 4605 4606 if (RefreshProgress) 4607 { 4608 ProgressSetStep(ProgressBar, OldTimerValue - TimerValue); 4609 RefreshProgress = FALSE; 4610 } 4611 4612 /* Stop when the timer reaches zero */ 4613 if (TimerValue <= 0) 4614 break; 4615 4616 /* Check for user key presses */ 4617 4618 /* 4619 * If the timer is used, use a passive wait of maximum 1 second 4620 * while monitoring for incoming console input events, so that 4621 * we are still able to display the timing count. 4622 */ 4623 4624 /* Wait a maximum of 1 second for input events */ 4625 TimeElapsed = NtGetTickCount() - StartTime; 4626 if (TimeElapsed < TimerDiv) 4627 { 4628 /* Convert the time to NT Format */ 4629 Timeout.QuadPart = (TimerDiv - TimeElapsed) * -10000LL; 4630 Status = NtWaitForSingleObject(StdInput, FALSE, &Timeout); 4631 } 4632 else 4633 { 4634 Status = STATUS_TIMEOUT; 4635 } 4636 4637 /* Check whether the input event has been signaled, or a timeout happened */ 4638 if (Status == STATUS_TIMEOUT) 4639 { 4640 continue; 4641 } 4642 if (Status != STATUS_WAIT_0) 4643 { 4644 /* An error happened, bail out */ 4645 DPRINT1("NtWaitForSingleObject() failed, Status 0x%08lx\n", Status); 4646 break; 4647 } 4648 4649 /* Check for an ENTER key press */ 4650 while (CONSOLE_ConInKeyPeek(Ir)) 4651 { 4652 if (Ir->Event.KeyEvent.uChar.AsciiChar == 0x0D) /* ENTER */ 4653 { 4654 /* Found it, stop waiting */ 4655 goto Exit; 4656 } 4657 } 4658 } 4659 4660 Exit: 4661 /* Destroy the progress bar and quit */ 4662 DestroyProgressBar(ProgressBar); 4663 } 4664 4665 4666 /* 4667 * Displays the QuitPage. 4668 * 4669 * Next pages: 4670 * FlushPage (At once) 4671 * 4672 * SIDEEFFECTS 4673 * Destroy the Lists 4674 * 4675 * RETURNS 4676 * Number of the next page. 4677 */ 4678 static PAGE_NUMBER 4679 QuitPage(PINPUT_RECORD Ir) 4680 { 4681 MUIDisplayPage(QUIT_PAGE); 4682 4683 /* Destroy the NTOS installations list */ 4684 if (NtOsInstallsList != NULL) 4685 { 4686 DestroyGenericList(NtOsInstallsList, TRUE); 4687 NtOsInstallsList = NULL; 4688 } 4689 4690 /* Destroy the partition list */ 4691 if (PartitionList != NULL) 4692 { 4693 DestroyPartitionList(PartitionList); 4694 PartitionList = NULL; 4695 } 4696 4697 /* Reset the formatter machine state */ 4698 TempPartition = NULL; 4699 FormatState = Start; 4700 4701 /* Destroy the filesystem list */ 4702 ResetFileSystemList(); 4703 4704 CONSOLE_SetStatusText(MUIGetString(STRING_REBOOTCOMPUTER2)); 4705 4706 /* Wait for maximum 15 seconds or an ENTER key before quitting */ 4707 ProgressCountdown(Ir, 15); 4708 return FLUSH_PAGE; 4709 } 4710 4711 4712 /* 4713 * Displays the SuccessPage. 4714 * 4715 * Next pages: 4716 * FlushPage (At once) 4717 * 4718 * SIDEEFFECTS 4719 * Destroy the Lists 4720 * 4721 * RETURNS 4722 * Number of the next page. 4723 */ 4724 static PAGE_NUMBER 4725 SuccessPage(PINPUT_RECORD Ir) 4726 { 4727 MUIDisplayPage(SUCCESS_PAGE); 4728 4729 if (IsUnattendedSetup) 4730 return FLUSH_PAGE; 4731 4732 /* Wait for maximum 15 seconds or an ENTER key before quitting */ 4733 ProgressCountdown(Ir, 15); 4734 return FLUSH_PAGE; 4735 } 4736 4737 4738 /* 4739 * Displays the FlushPage. 4740 * 4741 * Next pages: 4742 * RebootPage (At once) 4743 * 4744 * RETURNS 4745 * Number of the next page. 4746 */ 4747 static PAGE_NUMBER 4748 FlushPage(PINPUT_RECORD Ir) 4749 { 4750 MUIDisplayPage(FLUSH_PAGE); 4751 return REBOOT_PAGE; 4752 } 4753 4754 4755 /* 4756 * The start routine and page management 4757 */ 4758 NTSTATUS 4759 RunUSetup(VOID) 4760 { 4761 NTSTATUS Status; 4762 INPUT_RECORD Ir; 4763 PAGE_NUMBER Page; 4764 BOOLEAN Old; 4765 4766 InfSetHeap(ProcessHeap); 4767 4768 /* Tell the Cm this is a setup boot, and it has to behave accordingly */ 4769 Status = NtInitializeRegistry(CM_BOOT_FLAG_SETUP); 4770 if (!NT_SUCCESS(Status)) 4771 DPRINT1("NtInitializeRegistry() failed (Status 0x%08lx)\n", Status); 4772 4773 /* Initialize the user-mode PnP manager */ 4774 Status = InitializeUserModePnpManager(&USetupData.SetupInf); 4775 if (!NT_SUCCESS(Status)) 4776 { 4777 // PrintString(??); 4778 DPRINT1("The user-mode PnP manager could not initialize (Status 0x%08lx), expect unavailable devices!\n", Status); 4779 } 4780 4781 if (!CONSOLE_Init()) 4782 { 4783 PrintString(MUIGetString(STRING_CONSOLEFAIL1)); 4784 PrintString(MUIGetString(STRING_CONSOLEFAIL2)); 4785 PrintString(MUIGetString(STRING_CONSOLEFAIL3)); 4786 4787 /* We failed to initialize the video, just quit the installer */ 4788 return STATUS_APP_INIT_FAILURE; 4789 } 4790 4791 /* Initialize Setup, phase 0 */ 4792 InitializeSetup(&USetupData, 0); 4793 USetupData.ErrorRoutine = USetupErrorRoutine; 4794 4795 /* Hide the cursor and clear the screen and keyboard buffer */ 4796 CONSOLE_SetCursorType(TRUE, FALSE); 4797 CONSOLE_ClearScreen(); 4798 CONSOLE_Flush(); 4799 4800 /* Global Initialization page */ 4801 Page = SetupStartPage(&Ir); 4802 4803 while (Page != REBOOT_PAGE && Page != RECOVERY_PAGE) 4804 { 4805 CONSOLE_ClearScreen(); 4806 CONSOLE_Flush(); 4807 4808 // CONSOLE_SetUnderlinedTextXY(4, 3, " ReactOS " KERNEL_VERSION_STR " Setup "); 4809 // CONSOLE_Flush(); 4810 4811 switch (Page) 4812 { 4813 /* Language page */ 4814 case LANGUAGE_PAGE: 4815 Page = LanguagePage(&Ir); 4816 break; 4817 4818 /* Welcome page */ 4819 case WELCOME_PAGE: 4820 Page = WelcomePage(&Ir); 4821 break; 4822 4823 /* License page */ 4824 case LICENSE_PAGE: 4825 Page = LicensePage(&Ir); 4826 break; 4827 4828 /* Install pages */ 4829 case INSTALL_INTRO_PAGE: 4830 Page = InstallIntroPage(&Ir); 4831 break; 4832 4833 #if 0 4834 case SCSI_CONTROLLER_PAGE: 4835 Page = ScsiControllerPage(&Ir); 4836 break; 4837 4838 case OEM_DRIVER_PAGE: 4839 Page = OemDriverPage(&Ir); 4840 break; 4841 #endif 4842 4843 case DEVICE_SETTINGS_PAGE: 4844 Page = DeviceSettingsPage(&Ir); 4845 break; 4846 4847 case COMPUTER_SETTINGS_PAGE: 4848 Page = ComputerSettingsPage(&Ir); 4849 break; 4850 4851 case DISPLAY_SETTINGS_PAGE: 4852 Page = DisplaySettingsPage(&Ir); 4853 break; 4854 4855 case KEYBOARD_SETTINGS_PAGE: 4856 Page = KeyboardSettingsPage(&Ir); 4857 break; 4858 4859 case LAYOUT_SETTINGS_PAGE: 4860 Page = LayoutSettingsPage(&Ir); 4861 break; 4862 4863 case SELECT_PARTITION_PAGE: 4864 Page = SelectPartitionPage(&Ir); 4865 break; 4866 4867 case CREATE_PRIMARY_PARTITION_PAGE: 4868 Page = CreatePrimaryPartitionPage(&Ir); 4869 break; 4870 4871 case CREATE_EXTENDED_PARTITION_PAGE: 4872 Page = CreateExtendedPartitionPage(&Ir); 4873 break; 4874 4875 case CREATE_LOGICAL_PARTITION_PAGE: 4876 Page = CreateLogicalPartitionPage(&Ir); 4877 break; 4878 4879 case CONFIRM_DELETE_SYSTEM_PARTITION_PAGE: 4880 Page = ConfirmDeleteSystemPartitionPage(&Ir); 4881 break; 4882 4883 case DELETE_PARTITION_PAGE: 4884 Page = DeletePartitionPage(&Ir); 4885 break; 4886 4887 case SELECT_FILE_SYSTEM_PAGE: 4888 Page = SelectFileSystemPage(&Ir); 4889 break; 4890 4891 case FORMAT_PARTITION_PAGE: 4892 Page = FormatPartitionPage(&Ir); 4893 break; 4894 4895 case CHECK_FILE_SYSTEM_PAGE: 4896 Page = CheckFileSystemPage(&Ir); 4897 break; 4898 4899 case INSTALL_DIRECTORY_PAGE: 4900 Page = InstallDirectoryPage(&Ir); 4901 break; 4902 4903 case PREPARE_COPY_PAGE: 4904 Page = PrepareCopyPage(&Ir); 4905 break; 4906 4907 case FILE_COPY_PAGE: 4908 Page = FileCopyPage(&Ir); 4909 break; 4910 4911 case REGISTRY_PAGE: 4912 Page = RegistryPage(&Ir); 4913 break; 4914 4915 case BOOT_LOADER_PAGE: 4916 Page = BootLoaderPage(&Ir); 4917 break; 4918 4919 case BOOT_LOADER_FLOPPY_PAGE: 4920 Page = BootLoaderFloppyPage(&Ir); 4921 break; 4922 4923 case BOOT_LOADER_HARDDISK_MBR_PAGE: 4924 Page = BootLoaderHarddiskMbrPage(&Ir); 4925 break; 4926 4927 case BOOT_LOADER_HARDDISK_VBR_PAGE: 4928 Page = BootLoaderHarddiskVbrPage(&Ir); 4929 break; 4930 4931 /* Repair pages */ 4932 case REPAIR_INTRO_PAGE: 4933 Page = RepairIntroPage(&Ir); 4934 break; 4935 4936 case UPGRADE_REPAIR_PAGE: 4937 Page = UpgradeRepairPage(&Ir); 4938 break; 4939 4940 case SUCCESS_PAGE: 4941 Page = SuccessPage(&Ir); 4942 break; 4943 4944 case FLUSH_PAGE: 4945 Page = FlushPage(&Ir); 4946 break; 4947 4948 case QUIT_PAGE: 4949 Page = QuitPage(&Ir); 4950 break; 4951 4952 /* Virtual pages */ 4953 case SETUP_INIT_PAGE: 4954 case REBOOT_PAGE: 4955 case RECOVERY_PAGE: 4956 break; 4957 } 4958 } 4959 4960 /* Terminate the user-mode PnP manager */ 4961 TerminateUserModePnpManager(); 4962 4963 /* Setup has finished */ 4964 FinishSetup(&USetupData); 4965 4966 if (Page == RECOVERY_PAGE) 4967 RecoveryConsole(); 4968 4969 FreeConsole(); 4970 4971 /* Reboot */ 4972 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE, FALSE, &Old); 4973 NtShutdownSystem(ShutdownReboot); 4974 RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE, Old, FALSE, &Old); 4975 4976 return STATUS_SUCCESS; 4977 } 4978 4979 4980 VOID NTAPI 4981 NtProcessStartup(PPEB Peb) 4982 { 4983 NTSTATUS Status; 4984 LARGE_INTEGER Time; 4985 4986 RtlNormalizeProcessParams(Peb->ProcessParameters); 4987 4988 ProcessHeap = Peb->ProcessHeap; 4989 4990 NtQuerySystemTime(&Time); 4991 4992 Status = RunUSetup(); 4993 4994 if (NT_SUCCESS(Status)) 4995 { 4996 /* 4997 * Avoid a bugcheck if RunUSetup() finishes too quickly by implementing 4998 * a protective waiting. 4999 * This wait is needed because, since we are started as SMSS.EXE, 5000 * the NT kernel explicitly waits 5 seconds for the initial process 5001 * SMSS.EXE to initialize (as a protective measure), and otherwise 5002 * bugchecks with the code SESSION5_INITIALIZATION_FAILED. 5003 */ 5004 Time.QuadPart += 50000000; 5005 NtDelayExecution(FALSE, &Time); 5006 } 5007 else 5008 { 5009 /* The installer failed to start: raise a hard error (crash the system/BSOD) */ 5010 Status = NtRaiseHardError(STATUS_SYSTEM_PROCESS_TERMINATED, 5011 0, 0, NULL, 0, NULL); 5012 } 5013 5014 NtTerminateProcess(NtCurrentProcess(), Status); 5015 } 5016 5017 /* EOF */ 5018