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