1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Setup Library 4 * FILE: base/setup/lib/setuplib.c 5 * PURPOSE: Setup Library - Main initialization helpers 6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include "precomp.h" 13 #include "filesup.h" 14 #include "infsupp.h" 15 #include "inicache.h" 16 17 #include "setuplib.h" 18 19 #define NDEBUG 20 #include <debug.h> 21 22 23 /* GLOBALS ******************************************************************/ 24 25 /* FUNCTIONS ****************************************************************/ 26 27 VOID 28 CheckUnattendedSetup( 29 IN OUT PUSETUP_DATA pSetupData) 30 { 31 INFCONTEXT Context; 32 HINF UnattendInf; 33 UINT ErrorLine; 34 INT IntValue; 35 PCWSTR Value; 36 WCHAR UnattendInfPath[MAX_PATH]; 37 38 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, 39 pSetupData->SourcePath.Buffer, L"unattend.inf"); 40 41 DPRINT("UnattendInf path: '%S'\n", UnattendInfPath); 42 43 if (DoesFileExist(NULL, UnattendInfPath) == FALSE) 44 { 45 DPRINT("Does not exist: %S\n", UnattendInfPath); 46 return; 47 } 48 49 /* Load 'unattend.inf' from installation media */ 50 UnattendInf = SpInfOpenInfFile(UnattendInfPath, 51 NULL, 52 INF_STYLE_OLDNT, 53 pSetupData->LanguageId, 54 &ErrorLine); 55 if (UnattendInf == INVALID_HANDLE_VALUE) 56 { 57 DPRINT("SpInfOpenInfFile() failed\n"); 58 return; 59 } 60 61 /* Open 'Unattend' section */ 62 if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"Signature", &Context)) 63 { 64 DPRINT("SpInfFindFirstLine() failed for section 'Unattend'\n"); 65 goto Quit; 66 } 67 68 /* Get pointer 'Signature' key */ 69 if (!INF_GetData(&Context, NULL, &Value)) 70 { 71 DPRINT("INF_GetData() failed for key 'Signature'\n"); 72 goto Quit; 73 } 74 75 /* Check 'Signature' string */ 76 if (_wcsicmp(Value, L"$ReactOS$") != 0) 77 { 78 DPRINT("Signature not $ReactOS$\n"); 79 INF_FreeData(Value); 80 goto Quit; 81 } 82 83 INF_FreeData(Value); 84 85 /* Check if Unattend setup is enabled */ 86 if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"UnattendSetupEnabled", &Context)) 87 { 88 DPRINT("Can't find key 'UnattendSetupEnabled'\n"); 89 goto Quit; 90 } 91 92 if (!INF_GetData(&Context, NULL, &Value)) 93 { 94 DPRINT("Can't read key 'UnattendSetupEnabled'\n"); 95 goto Quit; 96 } 97 98 if (_wcsicmp(Value, L"yes") != 0) 99 { 100 DPRINT("Unattend setup is disabled by 'UnattendSetupEnabled' key!\n"); 101 INF_FreeData(Value); 102 goto Quit; 103 } 104 105 INF_FreeData(Value); 106 107 /* Search for 'DestinationDiskNumber' in the 'Unattend' section */ 108 if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"DestinationDiskNumber", &Context)) 109 { 110 DPRINT("SpInfFindFirstLine() failed for key 'DestinationDiskNumber'\n"); 111 goto Quit; 112 } 113 114 if (!SpInfGetIntField(&Context, 1, &IntValue)) 115 { 116 DPRINT("SpInfGetIntField() failed for key 'DestinationDiskNumber'\n"); 117 goto Quit; 118 } 119 120 pSetupData->DestinationDiskNumber = (LONG)IntValue; 121 122 /* Search for 'DestinationPartitionNumber' in the 'Unattend' section */ 123 if (!SpInfFindFirstLine(UnattendInf, L"Unattend", L"DestinationPartitionNumber", &Context)) 124 { 125 DPRINT("SpInfFindFirstLine() failed for key 'DestinationPartitionNumber'\n"); 126 goto Quit; 127 } 128 129 if (!SpInfGetIntField(&Context, 1, &IntValue)) 130 { 131 DPRINT("SpInfGetIntField() failed for key 'DestinationPartitionNumber'\n"); 132 goto Quit; 133 } 134 135 pSetupData->DestinationPartitionNumber = (LONG)IntValue; 136 137 /* Search for 'InstallationDirectory' in the 'Unattend' section (optional) */ 138 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"InstallationDirectory", &Context)) 139 { 140 /* Get pointer 'InstallationDirectory' key */ 141 if (!INF_GetData(&Context, NULL, &Value)) 142 { 143 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n"); 144 goto Quit; 145 } 146 147 RtlStringCchCopyW(pSetupData->InstallationDirectory, 148 ARRAYSIZE(pSetupData->InstallationDirectory), 149 Value); 150 151 INF_FreeData(Value); 152 } 153 154 IsUnattendedSetup = TRUE; 155 DPRINT("Running unattended setup\n"); 156 157 /* Search for 'MBRInstallType' in the 'Unattend' section */ 158 pSetupData->MBRInstallType = -1; 159 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"MBRInstallType", &Context)) 160 { 161 if (SpInfGetIntField(&Context, 1, &IntValue)) 162 { 163 pSetupData->MBRInstallType = IntValue; 164 } 165 } 166 167 /* Search for 'FormatPartition' in the 'Unattend' section */ 168 pSetupData->FormatPartition = 0; 169 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"FormatPartition", &Context)) 170 { 171 if (SpInfGetIntField(&Context, 1, &IntValue)) 172 { 173 pSetupData->FormatPartition = IntValue; 174 } 175 } 176 177 pSetupData->AutoPartition = 0; 178 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"AutoPartition", &Context)) 179 { 180 if (SpInfGetIntField(&Context, 1, &IntValue)) 181 { 182 pSetupData->AutoPartition = IntValue; 183 } 184 } 185 186 /* Search for LocaleID in the 'Unattend' section */ 187 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"LocaleID", &Context)) 188 { 189 if (INF_GetData(&Context, NULL, &Value)) 190 { 191 LONG Id = wcstol(Value, NULL, 16); 192 RtlStringCchPrintfW(pSetupData->LocaleID, 193 ARRAYSIZE(pSetupData->LocaleID), 194 L"%08lx", Id); 195 INF_FreeData(Value); 196 } 197 } 198 199 /* Search for FsType in the 'Unattend' section */ 200 pSetupData->FsType = 0; 201 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"FsType", &Context)) 202 { 203 if (SpInfGetIntField(&Context, 1, &IntValue)) 204 { 205 pSetupData->FsType = IntValue; 206 } 207 } 208 209 Quit: 210 SpInfCloseInfFile(UnattendInf); 211 } 212 213 VOID 214 InstallSetupInfFile( 215 IN OUT PUSETUP_DATA pSetupData) 216 { 217 NTSTATUS Status; 218 PINICACHE IniCache; 219 220 #if 0 // HACK FIXME! 221 PINICACHE UnattendCache; 222 PINICACHEITERATOR Iterator; 223 #else 224 // WCHAR CrLf[] = {L'\r', L'\n'}; 225 CHAR CrLf[] = {'\r', '\n'}; 226 HANDLE FileHandle, UnattendFileHandle, SectionHandle; 227 FILE_STANDARD_INFORMATION FileInfo; 228 ULONG FileSize; 229 PVOID ViewBase; 230 UNICODE_STRING FileName; 231 OBJECT_ATTRIBUTES ObjectAttributes; 232 IO_STATUS_BLOCK IoStatusBlock; 233 #endif 234 235 PINI_SECTION IniSection; 236 WCHAR PathBuffer[MAX_PATH]; 237 WCHAR UnattendInfPath[MAX_PATH]; 238 239 /* Create a $winnt$.inf file with default entries */ 240 IniCache = IniCacheCreate(); 241 if (!IniCache) 242 return; 243 244 IniSection = IniAddSection(IniCache, L"SetupParams"); 245 if (IniSection) 246 { 247 /* Key "skipmissingfiles" */ 248 // RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 249 // L"\"%s\"", L"WinNt5.2"); 250 // IniAddKey(IniSection, L"Version", PathBuffer); 251 } 252 253 IniSection = IniAddSection(IniCache, L"Data"); 254 if (IniSection) 255 { 256 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 257 L"\"%s\"", IsUnattendedSetup ? L"yes" : L"no"); 258 IniAddKey(IniSection, L"UnattendedInstall", PathBuffer); 259 260 // "floppylessbootpath" (yes/no) 261 262 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 263 L"\"%s\"", L"winnt"); 264 IniAddKey(IniSection, L"ProductType", PathBuffer); 265 266 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 267 L"\"%s\\\"", pSetupData->SourceRootPath.Buffer); 268 IniAddKey(IniSection, L"SourcePath", PathBuffer); 269 270 // "floppyless" ("0") 271 } 272 273 #if 0 274 275 /* TODO: Append the standard unattend.inf file */ 276 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, 277 pSetupData->SourcePath.Buffer, L"unattend.inf"); 278 if (DoesFileExist(NULL, UnattendInfPath) == FALSE) 279 { 280 DPRINT("Does not exist: %S\n", UnattendInfPath); 281 goto Quit; 282 } 283 284 Status = IniCacheLoad(&UnattendCache, UnattendInfPath, FALSE); 285 if (!NT_SUCCESS(Status)) 286 { 287 DPRINT1("Cannot load %S as an INI file!\n", UnattendInfPath); 288 goto Quit; 289 } 290 291 IniCacheDestroy(UnattendCache); 292 293 Quit: 294 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2, 295 pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf"); 296 IniCacheSave(IniCache, PathBuffer); 297 IniCacheDestroy(IniCache); 298 299 #else 300 301 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2, 302 pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf"); 303 IniCacheSave(IniCache, PathBuffer); 304 IniCacheDestroy(IniCache); 305 306 /* TODO: Append the standard unattend.inf file */ 307 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, 308 pSetupData->SourcePath.Buffer, L"unattend.inf"); 309 if (DoesFileExist(NULL, UnattendInfPath) == FALSE) 310 { 311 DPRINT("Does not exist: %S\n", UnattendInfPath); 312 return; 313 } 314 315 RtlInitUnicodeString(&FileName, PathBuffer); 316 InitializeObjectAttributes(&ObjectAttributes, 317 &FileName, 318 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 319 NULL, 320 NULL); 321 Status = NtOpenFile(&FileHandle, 322 FILE_APPEND_DATA | SYNCHRONIZE, 323 &ObjectAttributes, 324 &IoStatusBlock, 325 FILE_SHARE_READ, 326 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); 327 if (!NT_SUCCESS(Status)) 328 { 329 DPRINT1("Cannot load %S as an INI file!\n", PathBuffer); 330 return; 331 } 332 333 /* Query the file size */ 334 Status = NtQueryInformationFile(FileHandle, 335 &IoStatusBlock, 336 &FileInfo, 337 sizeof(FileInfo), 338 FileStandardInformation); 339 if (!NT_SUCCESS(Status)) 340 { 341 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status); 342 FileInfo.EndOfFile.QuadPart = 0ULL; 343 } 344 345 Status = OpenAndMapFile(NULL, 346 UnattendInfPath, 347 &UnattendFileHandle, 348 &FileSize, 349 &SectionHandle, 350 &ViewBase, 351 FALSE); 352 if (!NT_SUCCESS(Status)) 353 { 354 DPRINT1("Cannot load %S !\n", UnattendInfPath); 355 NtClose(FileHandle); 356 return; 357 } 358 359 /* Write to the INI file */ 360 361 /* "\r\n" */ 362 Status = NtWriteFile(FileHandle, 363 NULL, 364 NULL, 365 NULL, 366 &IoStatusBlock, 367 (PVOID)CrLf, 368 sizeof(CrLf), 369 &FileInfo.EndOfFile, 370 NULL); 371 372 Status = NtWriteFile(FileHandle, 373 NULL, 374 NULL, 375 NULL, 376 &IoStatusBlock, 377 ViewBase, 378 FileSize, 379 NULL, 380 NULL); 381 if (!NT_SUCCESS(Status)) 382 { 383 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 384 } 385 386 /* Finally, unmap and close the file */ 387 UnMapAndCloseFile(UnattendFileHandle, SectionHandle, ViewBase); 388 389 NtClose(FileHandle); 390 #endif 391 } 392 393 NTSTATUS 394 GetSourcePaths( 395 OUT PUNICODE_STRING SourcePath, 396 OUT PUNICODE_STRING SourceRootPath, 397 OUT PUNICODE_STRING SourceRootDir) 398 { 399 NTSTATUS Status; 400 HANDLE LinkHandle; 401 OBJECT_ATTRIBUTES ObjectAttributes; 402 UCHAR ImageFileBuffer[sizeof(UNICODE_STRING) + MAX_PATH * sizeof(WCHAR)]; 403 PUNICODE_STRING InstallSourcePath = (PUNICODE_STRING)&ImageFileBuffer; 404 WCHAR SystemRootBuffer[MAX_PATH] = L""; 405 UNICODE_STRING SystemRootPath = RTL_CONSTANT_STRING(L"\\SystemRoot"); 406 ULONG BufferSize; 407 PWCHAR Ptr; 408 409 // FIXME: commented out to allow installation from USB 410 #if 0 411 /* Determine the installation source path via the full path of the installer */ 412 RtlInitEmptyUnicodeString(InstallSourcePath, 413 (PWSTR)((ULONG_PTR)ImageFileBuffer + sizeof(UNICODE_STRING)), 414 sizeof(ImageFileBuffer) - sizeof(UNICODE_STRING) 415 /* Reserve space for a NULL terminator */ - sizeof(UNICODE_NULL)); 416 BufferSize = sizeof(ImageFileBuffer); 417 Status = NtQueryInformationProcess(NtCurrentProcess(), 418 ProcessImageFileName, 419 InstallSourcePath, 420 BufferSize, 421 NULL); 422 // STATUS_INFO_LENGTH_MISMATCH or STATUS_BUFFER_TOO_SMALL ? 423 if (!NT_SUCCESS(Status)) 424 return Status; 425 426 /* Manually NULL-terminate */ 427 InstallSourcePath->Buffer[InstallSourcePath->Length / sizeof(WCHAR)] = UNICODE_NULL; 428 429 /* Strip the trailing file name */ 430 Ptr = wcsrchr(InstallSourcePath->Buffer, OBJ_NAME_PATH_SEPARATOR); 431 if (Ptr) 432 *Ptr = UNICODE_NULL; 433 InstallSourcePath->Length = wcslen(InstallSourcePath->Buffer) * sizeof(WCHAR); 434 #endif 435 436 /* 437 * Now resolve the full path to \SystemRoot. In case it prefixes 438 * the installation source path determined from the full path of 439 * the installer, we use instead the resolved \SystemRoot as the 440 * installation source path. 441 * Otherwise, we use instead the path from the full installer path. 442 */ 443 444 InitializeObjectAttributes(&ObjectAttributes, 445 &SystemRootPath, 446 OBJ_CASE_INSENSITIVE, 447 NULL, 448 NULL); 449 450 Status = NtOpenSymbolicLinkObject(&LinkHandle, 451 SYMBOLIC_LINK_QUERY, 452 &ObjectAttributes); 453 if (!NT_SUCCESS(Status)) 454 { 455 /* 456 * We failed at opening the \SystemRoot link (usually due to wrong 457 * access rights). Do not consider this as a fatal error, but use 458 * instead the image file path as the installation source path. 459 */ 460 DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed with Status 0x%08lx\n", 461 &SystemRootPath, Status); 462 goto InitPaths; 463 } 464 465 RtlInitEmptyUnicodeString(&SystemRootPath, 466 SystemRootBuffer, 467 sizeof(SystemRootBuffer)); 468 469 /* Resolve the link and close its handle */ 470 Status = NtQuerySymbolicLinkObject(LinkHandle, 471 &SystemRootPath, 472 &BufferSize); 473 NtClose(LinkHandle); 474 475 if (!NT_SUCCESS(Status)) 476 return Status; // Unexpected error 477 478 /* Check whether the resolved \SystemRoot is a prefix of the image file path */ 479 // FIXME: commented out to allow installation from USB 480 // if (RtlPrefixUnicodeString(&SystemRootPath, InstallSourcePath, TRUE)) 481 { 482 /* Yes it is, so we use instead SystemRoot as the installation source path */ 483 InstallSourcePath = &SystemRootPath; 484 } 485 486 487 InitPaths: 488 /* 489 * Retrieve the different source path components 490 */ 491 RtlCreateUnicodeString(SourcePath, InstallSourcePath->Buffer); 492 493 /* Strip trailing directory */ 494 Ptr = wcsrchr(InstallSourcePath->Buffer, OBJ_NAME_PATH_SEPARATOR); 495 if (Ptr) 496 { 497 RtlCreateUnicodeString(SourceRootDir, Ptr); 498 *Ptr = UNICODE_NULL; 499 } 500 else 501 { 502 RtlCreateUnicodeString(SourceRootDir, L""); 503 } 504 505 RtlCreateUnicodeString(SourceRootPath, InstallSourcePath->Buffer); 506 507 return STATUS_SUCCESS; 508 } 509 510 ERROR_NUMBER 511 LoadSetupInf( 512 IN OUT PUSETUP_DATA pSetupData) 513 { 514 INFCONTEXT Context; 515 UINT ErrorLine; 516 INT IntValue; 517 PCWSTR Value; 518 WCHAR FileNameBuffer[MAX_PATH]; 519 520 CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2, 521 pSetupData->SourcePath.Buffer, L"txtsetup.sif"); 522 523 DPRINT("SetupInf path: '%S'\n", FileNameBuffer); 524 525 pSetupData->SetupInf = 526 SpInfOpenInfFile(FileNameBuffer, 527 NULL, 528 INF_STYLE_WIN4, 529 pSetupData->LanguageId, 530 &ErrorLine); 531 if (pSetupData->SetupInf == INVALID_HANDLE_VALUE) 532 return ERROR_LOAD_TXTSETUPSIF; 533 534 /* Open 'Version' section */ 535 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"Version", L"Signature", &Context)) 536 return ERROR_CORRUPT_TXTSETUPSIF; 537 538 /* Get pointer 'Signature' key */ 539 if (!INF_GetData(&Context, NULL, &Value)) 540 return ERROR_CORRUPT_TXTSETUPSIF; 541 542 /* Check 'Signature' string */ 543 if (_wcsicmp(Value, L"$ReactOS$") != 0 && 544 _wcsicmp(Value, L"$Windows NT$") != 0) 545 { 546 INF_FreeData(Value); 547 return ERROR_SIGNATURE_TXTSETUPSIF; 548 } 549 550 INF_FreeData(Value); 551 552 /* Open 'DiskSpaceRequirements' section */ 553 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context)) 554 return ERROR_CORRUPT_TXTSETUPSIF; 555 556 pSetupData->RequiredPartitionDiskSpace = ~0; 557 558 /* Get the 'FreeSysPartDiskSpace' value */ 559 if (!SpInfGetIntField(&Context, 1, &IntValue)) 560 return ERROR_CORRUPT_TXTSETUPSIF; 561 562 pSetupData->RequiredPartitionDiskSpace = (ULONG)IntValue; 563 564 // 565 // Support "SetupSourceDevice" and "SetupSourcePath" in txtsetup.sif 566 // See CORE-9023 567 // Support for that should also be added in setupldr. 568 // 569 570 /* Update the Setup Source paths */ 571 if (SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"SetupSourceDevice", &Context)) 572 { 573 /* 574 * Get optional pointer 'SetupSourceDevice' key, its presence 575 * will dictate whether we also need 'SetupSourcePath'. 576 */ 577 if (INF_GetData(&Context, NULL, &Value)) 578 { 579 /* Free the old source root path string and create the new one */ 580 RtlFreeUnicodeString(&pSetupData->SourceRootPath); 581 RtlCreateUnicodeString(&pSetupData->SourceRootPath, Value); 582 INF_FreeData(Value); 583 584 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"SetupSourcePath", &Context)) 585 { 586 /* The 'SetupSourcePath' value is mandatory! */ 587 return ERROR_CORRUPT_TXTSETUPSIF; 588 } 589 590 /* Get pointer 'SetupSourcePath' key */ 591 if (!INF_GetData(&Context, NULL, &Value)) 592 { 593 /* The 'SetupSourcePath' value is mandatory! */ 594 return ERROR_CORRUPT_TXTSETUPSIF; 595 } 596 597 /* Free the old source path string and create the new one */ 598 RtlFreeUnicodeString(&pSetupData->SourceRootDir); 599 RtlCreateUnicodeString(&pSetupData->SourceRootDir, Value); 600 INF_FreeData(Value); 601 } 602 } 603 604 /* Search for 'DefaultPath' in the 'SetupData' section */ 605 pSetupData->InstallationDirectory[0] = 0; 606 if (SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"DefaultPath", &Context)) 607 { 608 /* Get pointer 'DefaultPath' key */ 609 if (!INF_GetData(&Context, NULL, &Value)) 610 return ERROR_CORRUPT_TXTSETUPSIF; 611 612 RtlStringCchCopyW(pSetupData->InstallationDirectory, 613 ARRAYSIZE(pSetupData->InstallationDirectory), 614 Value); 615 616 INF_FreeData(Value); 617 } 618 619 return ERROR_SUCCESS; 620 } 621 622 NTSTATUS 623 InitDestinationPaths( 624 IN OUT PUSETUP_DATA pSetupData, 625 IN PCWSTR InstallationDir, 626 IN PPARTENTRY PartEntry) // FIXME: HACK! 627 { 628 NTSTATUS Status; 629 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 630 WCHAR PathBuffer[MAX_PATH]; 631 632 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); 633 634 /* Create 'pSetupData->DestinationRootPath' string */ 635 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 636 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 637 L"\\Device\\Harddisk%lu\\Partition%lu\\", 638 DiskEntry->DiskNumber, 639 PartEntry->PartitionNumber); 640 641 if (!NT_SUCCESS(Status)) 642 { 643 DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status); 644 return Status; 645 } 646 647 Status = RtlCreateUnicodeString(&pSetupData->DestinationRootPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY; 648 649 if (!NT_SUCCESS(Status)) 650 { 651 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status); 652 return Status; 653 } 654 655 DPRINT("DestinationRootPath: %wZ\n", &pSetupData->DestinationRootPath); 656 657 // FIXME! Which variable to choose? 658 if (!InstallationDir) 659 InstallationDir = pSetupData->InstallationDirectory; 660 661 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/ 662 /* Create 'pSetupData->DestinationArcPath' */ 663 RtlFreeUnicodeString(&pSetupData->DestinationArcPath); 664 665 if (DiskEntry->MediaType == FixedMedia) 666 { 667 if (DiskEntry->BiosFound) 668 { 669 #if 1 670 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 671 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\", 672 DiskEntry->HwFixedDiskNumber, 673 PartEntry->OnDiskPartitionNumber); 674 #else 675 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 676 L"multi(%lu)disk(%lu)rdisk(%lu)partition(%lu)\\", 677 DiskEntry->HwAdapterNumber, 678 DiskEntry->HwControllerNumber, 679 DiskEntry->HwFixedDiskNumber, 680 PartEntry->OnDiskPartitionNumber); 681 #endif 682 DPRINT1("Fixed disk found by BIOS, using MULTI ARC path '%S'\n", PathBuffer); 683 } 684 else 685 { 686 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 687 L"scsi(%u)disk(%u)rdisk(%u)partition(%lu)\\", 688 DiskEntry->Port, 689 DiskEntry->Bus, 690 DiskEntry->Id, 691 PartEntry->OnDiskPartitionNumber); 692 DPRINT1("Fixed disk not found by BIOS, using SCSI ARC path '%S'\n", PathBuffer); 693 } 694 } 695 else // if (DiskEntry->MediaType == RemovableMedia) 696 { 697 #if 1 698 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 699 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\", 700 0, 1); 701 DPRINT1("Removable disk, using MULTI ARC path '%S'\n", PathBuffer); 702 #else 703 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 704 L"signature(%08x)disk(%u)rdisk(%u)partition(%lu)\\", 705 DiskEntry->LayoutBuffer->Signature, 706 DiskEntry->Bus, 707 DiskEntry->Id, 708 PartEntry->OnDiskPartitionNumber); 709 DPRINT1("Removable disk, using SIGNATURE ARC path '%S'\n", PathBuffer); 710 #endif 711 } 712 713 if (!NT_SUCCESS(Status)) 714 { 715 DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status); 716 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 717 return Status; 718 } 719 720 Status = ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallationDir); 721 722 if (!NT_SUCCESS(Status)) 723 { 724 DPRINT1("ConcatPaths() failed with status 0x%08lx\n", Status); 725 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 726 return Status; 727 } 728 729 Status = RtlCreateUnicodeString(&pSetupData->DestinationArcPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY; 730 731 if (!NT_SUCCESS(Status)) 732 { 733 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status); 734 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 735 return Status; 736 } 737 738 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/ 739 /* Create 'pSetupData->DestinationPath' string */ 740 RtlFreeUnicodeString(&pSetupData->DestinationPath); 741 Status = CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2, 742 pSetupData->DestinationRootPath.Buffer, InstallationDir); 743 744 if (!NT_SUCCESS(Status)) 745 { 746 DPRINT1("CombinePaths() failed with status 0x%08lx\n", Status); 747 RtlFreeUnicodeString(&pSetupData->DestinationArcPath); 748 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 749 return Status; 750 } 751 752 Status = RtlCreateUnicodeString(&pSetupData->DestinationPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY; 753 754 if (!NT_SUCCESS(Status)) 755 { 756 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status); 757 RtlFreeUnicodeString(&pSetupData->DestinationArcPath); 758 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 759 return Status; 760 } 761 762 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/ 763 // FIXME: This is only temporary!! Must be removed later! 764 Status = RtlCreateUnicodeString(&pSetupData->InstallPath, InstallationDir) ? STATUS_SUCCESS : STATUS_NO_MEMORY; 765 766 if (!NT_SUCCESS(Status)) 767 { 768 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status); 769 RtlFreeUnicodeString(&pSetupData->DestinationPath); 770 RtlFreeUnicodeString(&pSetupData->DestinationArcPath); 771 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 772 return Status; 773 } 774 775 return STATUS_SUCCESS; 776 } 777 778 // NTSTATUS 779 ERROR_NUMBER 780 InitializeSetup( 781 IN OUT PUSETUP_DATA pSetupData, 782 IN ULONG InitPhase) 783 { 784 if (InitPhase == 0) 785 { 786 RtlZeroMemory(pSetupData, sizeof(*pSetupData)); 787 788 /* Initialize error handling */ 789 pSetupData->LastErrorNumber = ERROR_SUCCESS; 790 pSetupData->ErrorRoutine = NULL; 791 792 /* Initialize global unicode strings */ 793 RtlInitUnicodeString(&pSetupData->SourcePath, NULL); 794 RtlInitUnicodeString(&pSetupData->SourceRootPath, NULL); 795 RtlInitUnicodeString(&pSetupData->SourceRootDir, NULL); 796 RtlInitUnicodeString(&pSetupData->DestinationArcPath, NULL); 797 RtlInitUnicodeString(&pSetupData->DestinationPath, NULL); 798 RtlInitUnicodeString(&pSetupData->DestinationRootPath, NULL); 799 RtlInitUnicodeString(&pSetupData->SystemRootPath, NULL); 800 801 // FIXME: This is only temporary!! Must be removed later! 802 /***/RtlInitUnicodeString(&pSetupData->InstallPath, NULL);/***/ 803 804 // 805 // TODO: Load and start SetupDD, and ask it for the information 806 // 807 808 return ERROR_SUCCESS; 809 } 810 else 811 if (InitPhase == 1) 812 { 813 ERROR_NUMBER Error; 814 NTSTATUS Status; 815 816 /* Get the source path and source root path */ 817 // 818 // NOTE: Sometimes the source path may not be in SystemRoot !! 819 // (and this is the case when using the 1st-stage GUI setup!) 820 // 821 Status = GetSourcePaths(&pSetupData->SourcePath, 822 &pSetupData->SourceRootPath, 823 &pSetupData->SourceRootDir); 824 if (!NT_SUCCESS(Status)) 825 { 826 DPRINT1("GetSourcePaths() failed (Status 0x%08lx)\n", Status); 827 return ERROR_NO_SOURCE_DRIVE; 828 } 829 /* 830 * Example of output: 831 * SourcePath: '\Device\CdRom0\I386' 832 * SourceRootPath: '\Device\CdRom0' 833 * SourceRootDir: '\I386' 834 */ 835 DPRINT1("SourcePath (1): '%wZ'\n", &pSetupData->SourcePath); 836 DPRINT1("SourceRootPath (1): '%wZ'\n", &pSetupData->SourceRootPath); 837 DPRINT1("SourceRootDir (1): '%wZ'\n", &pSetupData->SourceRootDir); 838 839 /* Load 'txtsetup.sif' from the installation media */ 840 Error = LoadSetupInf(pSetupData); 841 if (Error != ERROR_SUCCESS) 842 { 843 DPRINT1("LoadSetupInf() failed (Error 0x%lx)\n", Error); 844 return Error; 845 } 846 DPRINT1("SourcePath (2): '%wZ'\n", &pSetupData->SourcePath); 847 DPRINT1("SourceRootPath (2): '%wZ'\n", &pSetupData->SourceRootPath); 848 DPRINT1("SourceRootDir (2): '%wZ'\n", &pSetupData->SourceRootDir); 849 850 return ERROR_SUCCESS; 851 } 852 853 return ERROR_SUCCESS; 854 } 855 856 VOID 857 FinishSetup( 858 IN OUT PUSETUP_DATA pSetupData) 859 { 860 /* Destroy the computer settings list */ 861 if (pSetupData->ComputerList != NULL) 862 { 863 DestroyGenericList(pSetupData->ComputerList, TRUE); 864 pSetupData->ComputerList = NULL; 865 } 866 867 /* Destroy the display settings list */ 868 if (pSetupData->DisplayList != NULL) 869 { 870 DestroyGenericList(pSetupData->DisplayList, TRUE); 871 pSetupData->DisplayList = NULL; 872 } 873 874 /* Destroy the keyboard settings list */ 875 if (pSetupData->KeyboardList != NULL) 876 { 877 DestroyGenericList(pSetupData->KeyboardList, TRUE); 878 pSetupData->KeyboardList = NULL; 879 } 880 881 /* Destroy the keyboard layout list */ 882 if (pSetupData->LayoutList != NULL) 883 { 884 DestroyGenericList(pSetupData->LayoutList, TRUE); 885 pSetupData->LayoutList = NULL; 886 } 887 888 /* Destroy the languages list */ 889 if (pSetupData->LanguageList != NULL) 890 { 891 DestroyGenericList(pSetupData->LanguageList, FALSE); 892 pSetupData->LanguageList = NULL; 893 } 894 895 /* Close the Setup INF */ 896 SpInfCloseInfFile(pSetupData->SetupInf); 897 } 898 899 /* 900 * SIDEEFFECTS 901 * Calls RegInitializeRegistry 902 * Calls ImportRegistryFile 903 * Calls SetDefaultPagefile 904 * Calls SetMountedDeviceValues 905 */ 906 ERROR_NUMBER 907 UpdateRegistry( 908 IN OUT PUSETUP_DATA pSetupData, 909 /**/IN BOOLEAN RepairUpdateFlag, /* HACK HACK! */ 910 /**/IN PPARTLIST PartitionList, /* HACK HACK! */ 911 /**/IN WCHAR DestinationDriveLetter, /* HACK HACK! */ 912 /**/IN PCWSTR SelectedLanguageId, /* HACK HACK! */ 913 IN PREGISTRY_STATUS_ROUTINE StatusRoutine OPTIONAL, 914 IN PFONTSUBSTSETTINGS SubstSettings OPTIONAL) 915 { 916 ERROR_NUMBER ErrorNumber; 917 NTSTATUS Status; 918 INFCONTEXT InfContext; 919 PCWSTR Action; 920 PCWSTR File; 921 PCWSTR Section; 922 BOOLEAN Success; 923 BOOLEAN ShouldRepairRegistry = FALSE; 924 BOOLEAN Delete; 925 926 if (RepairUpdateFlag) 927 { 928 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n"); 929 930 /* Verify the registry hives and check whether we need to update or repair any of them */ 931 Status = VerifyRegistryHives(&pSetupData->DestinationPath, &ShouldRepairRegistry); 932 if (!NT_SUCCESS(Status)) 933 { 934 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status); 935 ShouldRepairRegistry = FALSE; 936 } 937 if (!ShouldRepairRegistry) 938 DPRINT1("No need to repair the registry\n"); 939 } 940 941 DoUpdate: 942 ErrorNumber = ERROR_SUCCESS; 943 944 /* Update the registry */ 945 if (StatusRoutine) StatusRoutine(RegHiveUpdate); 946 947 /* Initialize the registry and setup the registry hives */ 948 Status = RegInitializeRegistry(&pSetupData->DestinationPath); 949 if (!NT_SUCCESS(Status)) 950 { 951 DPRINT1("RegInitializeRegistry() failed\n"); 952 /********** HACK!!!!!!!!!!! **********/ 953 if (Status == STATUS_NOT_IMPLEMENTED) 954 { 955 /* The hack was called, return its corresponding error */ 956 return ERROR_INITIALIZE_REGISTRY; 957 } 958 else 959 /*************************************/ 960 { 961 /* Something else failed */ 962 return ERROR_CREATE_HIVE; 963 } 964 } 965 966 if (!RepairUpdateFlag || ShouldRepairRegistry) 967 { 968 /* 969 * We fully setup the hives, in case we are doing a fresh installation 970 * (RepairUpdateFlag == FALSE), or in case we are doing an update 971 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to 972 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE). 973 */ 974 975 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Fresh", NULL, &InfContext); // Windows-compatible 976 if (!Success) 977 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Install", NULL, &InfContext); // ReactOS-specific 978 979 if (!Success) 980 { 981 DPRINT1("SpInfFindFirstLine() failed\n"); 982 ErrorNumber = ERROR_FIND_REGISTRY; 983 goto Cleanup; 984 } 985 } 986 else // if (RepairUpdateFlag && !ShouldRepairRegistry) 987 { 988 /* 989 * In case we are doing an update (RepairUpdateFlag == TRUE) and 990 * NO registry hives need a repair (ShouldRepairRegistry == FALSE), 991 * we only update the hives. 992 */ 993 994 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Upgrade", NULL, &InfContext); 995 if (!Success) 996 { 997 /* Nothing to do for update! */ 998 DPRINT1("No update needed for the registry!\n"); 999 goto Cleanup; 1000 } 1001 } 1002 1003 do 1004 { 1005 INF_GetDataField(&InfContext, 0, &Action); 1006 INF_GetDataField(&InfContext, 1, &File); 1007 INF_GetDataField(&InfContext, 2, &Section); 1008 1009 DPRINT("Action: %S File: %S Section %S\n", Action, File, Section); 1010 1011 if (Action == NULL) 1012 { 1013 INF_FreeData(Action); 1014 INF_FreeData(File); 1015 INF_FreeData(Section); 1016 break; // Hackfix 1017 } 1018 1019 if (!_wcsicmp(Action, L"AddReg")) 1020 Delete = FALSE; 1021 else if (!_wcsicmp(Action, L"DelReg")) 1022 Delete = TRUE; 1023 else 1024 { 1025 DPRINT1("Unrecognized registry INF action '%S'\n", Action); 1026 INF_FreeData(Action); 1027 INF_FreeData(File); 1028 INF_FreeData(Section); 1029 continue; 1030 } 1031 1032 INF_FreeData(Action); 1033 1034 if (StatusRoutine) StatusRoutine(ImportRegHive, File); 1035 1036 if (!ImportRegistryFile(pSetupData->SourcePath.Buffer, 1037 File, Section, 1038 pSetupData->LanguageId, Delete)) 1039 { 1040 DPRINT1("Importing %S failed\n", File); 1041 INF_FreeData(File); 1042 INF_FreeData(Section); 1043 ErrorNumber = ERROR_IMPORT_HIVE; 1044 goto Cleanup; 1045 } 1046 } while (SpInfFindNextLine(&InfContext, &InfContext)); 1047 1048 if (!RepairUpdateFlag || ShouldRepairRegistry) 1049 { 1050 /* See the explanation for this test above */ 1051 1052 PGENERIC_LIST_ENTRY Entry; 1053 PCWSTR LanguageId; // LocaleID; 1054 1055 Entry = GetCurrentListEntry(pSetupData->DisplayList); 1056 ASSERT(Entry); 1057 pSetupData->DisplayType = ((PGENENTRY)GetListEntryData(Entry))->Id; 1058 ASSERT(pSetupData->DisplayType); 1059 1060 /* Update display registry settings */ 1061 if (StatusRoutine) StatusRoutine(DisplaySettingsUpdate); 1062 if (!ProcessDisplayRegistry(pSetupData->SetupInf, pSetupData->DisplayType)) 1063 { 1064 ErrorNumber = ERROR_UPDATE_DISPLAY_SETTINGS; 1065 goto Cleanup; 1066 } 1067 1068 Entry = GetCurrentListEntry(pSetupData->LanguageList); 1069 ASSERT(Entry); 1070 LanguageId = ((PGENENTRY)GetListEntryData(Entry))->Id; 1071 ASSERT(LanguageId); 1072 1073 /* Set the locale */ 1074 if (StatusRoutine) StatusRoutine(LocaleSettingsUpdate); 1075 if (!ProcessLocaleRegistry(/*pSetupData->*/LanguageId)) 1076 { 1077 ErrorNumber = ERROR_UPDATE_LOCALESETTINGS; 1078 goto Cleanup; 1079 } 1080 1081 /* Add the keyboard layouts for the given language (without user override) */ 1082 if (StatusRoutine) StatusRoutine(KeybLayouts); 1083 if (!AddKeyboardLayouts(SelectedLanguageId)) 1084 { 1085 ErrorNumber = ERROR_ADDING_KBLAYOUTS; 1086 goto Cleanup; 1087 } 1088 1089 if (!IsUnattendedSetup) 1090 { 1091 Entry = GetCurrentListEntry(pSetupData->LayoutList); 1092 ASSERT(Entry); 1093 pSetupData->LayoutId = ((PGENENTRY)GetListEntryData(Entry))->Id; 1094 ASSERT(pSetupData->LayoutId); 1095 1096 /* Update keyboard layout settings with user-overridden values */ 1097 // FIXME: Wouldn't it be better to do it all at once 1098 // with the AddKeyboardLayouts() step? 1099 if (StatusRoutine) StatusRoutine(KeybSettingsUpdate); 1100 if (!ProcessKeyboardLayoutRegistry(pSetupData->LayoutId, SelectedLanguageId)) 1101 { 1102 ErrorNumber = ERROR_UPDATE_KBSETTINGS; 1103 goto Cleanup; 1104 } 1105 } 1106 1107 /* Set GeoID */ 1108 if (!SetGeoID(MUIGetGeoID(SelectedLanguageId))) 1109 { 1110 ErrorNumber = ERROR_UPDATE_GEOID; 1111 goto Cleanup; 1112 } 1113 1114 /* Add codepage information to registry */ 1115 if (StatusRoutine) StatusRoutine(CodePageInfoUpdate); 1116 if (!AddCodePage(SelectedLanguageId)) 1117 { 1118 ErrorNumber = ERROR_ADDING_CODEPAGE; 1119 goto Cleanup; 1120 } 1121 1122 /* Set the default pagefile entry */ 1123 SetDefaultPagefile(DestinationDriveLetter); 1124 1125 /* Update the mounted devices list */ 1126 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)! 1127 SetMountedDeviceValues(PartitionList); 1128 } 1129 1130 #ifdef __REACTOS__ 1131 if (SubstSettings) 1132 { 1133 /* HACK */ 1134 DoRegistryFontFixup(SubstSettings, wcstoul(SelectedLanguageId, NULL, 16)); 1135 } 1136 #endif 1137 1138 Cleanup: 1139 // 1140 // TODO: Unload all the registry stuff, perform cleanup, 1141 // and copy the created hive files into .sav files. 1142 // 1143 RegCleanupRegistry(&pSetupData->DestinationPath); 1144 1145 /* 1146 * Check whether we were in update/repair mode but we were actually 1147 * repairing the registry hives. If so, we have finished repairing them, 1148 * and we now reset the flag and run the proper registry update. 1149 * Otherwise we have finished the registry update! 1150 */ 1151 if (RepairUpdateFlag && ShouldRepairRegistry) 1152 { 1153 ShouldRepairRegistry = FALSE; 1154 goto DoUpdate; 1155 } 1156 1157 return ErrorNumber; 1158 } 1159 1160 /* EOF */ 1161