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