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