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 /* Initialize error handling */ 793 pSetupData->LastErrorNumber = ERROR_SUCCESS; 794 pSetupData->ErrorRoutine = NULL; 795 796 /* Initialize global unicode strings */ 797 RtlInitUnicodeString(&pSetupData->SourcePath, NULL); 798 RtlInitUnicodeString(&pSetupData->SourceRootPath, NULL); 799 RtlInitUnicodeString(&pSetupData->SourceRootDir, NULL); 800 RtlInitUnicodeString(&pSetupData->DestinationArcPath, NULL); 801 RtlInitUnicodeString(&pSetupData->DestinationPath, NULL); 802 RtlInitUnicodeString(&pSetupData->DestinationRootPath, NULL); 803 RtlInitUnicodeString(&pSetupData->SystemRootPath, NULL); 804 805 // FIXME: This is only temporary!! Must be removed later! 806 /***/RtlInitUnicodeString(&pSetupData->InstallPath, NULL);/***/ 807 808 // 809 // TODO: Load and start SetupDD, and ask it for the information 810 // 811 812 return ERROR_SUCCESS; 813 } 814 else 815 if (InitPhase == 1) 816 { 817 ERROR_NUMBER Error; 818 NTSTATUS Status; 819 820 /* Get the source path and source root path */ 821 // 822 // NOTE: Sometimes the source path may not be in SystemRoot !! 823 // (and this is the case when using the 1st-stage GUI setup!) 824 // 825 Status = GetSourcePaths(&pSetupData->SourcePath, 826 &pSetupData->SourceRootPath, 827 &pSetupData->SourceRootDir); 828 if (!NT_SUCCESS(Status)) 829 { 830 DPRINT1("GetSourcePaths() failed (Status 0x%08lx)\n", Status); 831 return ERROR_NO_SOURCE_DRIVE; 832 } 833 /* 834 * Example of output: 835 * SourcePath: '\Device\CdRom0\I386' 836 * SourceRootPath: '\Device\CdRom0' 837 * SourceRootDir: '\I386' 838 */ 839 DPRINT1("SourcePath (1): '%wZ'\n", &pSetupData->SourcePath); 840 DPRINT1("SourceRootPath (1): '%wZ'\n", &pSetupData->SourceRootPath); 841 DPRINT1("SourceRootDir (1): '%wZ'\n", &pSetupData->SourceRootDir); 842 843 /* Load 'txtsetup.sif' from the installation media */ 844 Error = LoadSetupInf(pSetupData); 845 if (Error != ERROR_SUCCESS) 846 { 847 DPRINT1("LoadSetupInf() failed (Error 0x%lx)\n", Error); 848 return Error; 849 } 850 DPRINT1("SourcePath (2): '%wZ'\n", &pSetupData->SourcePath); 851 DPRINT1("SourceRootPath (2): '%wZ'\n", &pSetupData->SourceRootPath); 852 DPRINT1("SourceRootDir (2): '%wZ'\n", &pSetupData->SourceRootDir); 853 854 return ERROR_SUCCESS; 855 } 856 857 return ERROR_SUCCESS; 858 } 859 860 VOID 861 FinishSetup( 862 IN OUT PUSETUP_DATA pSetupData) 863 { 864 /* Destroy the computer settings list */ 865 if (pSetupData->ComputerList != NULL) 866 { 867 DestroyGenericList(pSetupData->ComputerList, TRUE); 868 pSetupData->ComputerList = NULL; 869 } 870 871 /* Destroy the display settings list */ 872 if (pSetupData->DisplayList != NULL) 873 { 874 DestroyGenericList(pSetupData->DisplayList, TRUE); 875 pSetupData->DisplayList = NULL; 876 } 877 878 /* Destroy the keyboard settings list */ 879 if (pSetupData->KeyboardList != NULL) 880 { 881 DestroyGenericList(pSetupData->KeyboardList, TRUE); 882 pSetupData->KeyboardList = NULL; 883 } 884 885 /* Destroy the keyboard layout list */ 886 if (pSetupData->LayoutList != NULL) 887 { 888 DestroyGenericList(pSetupData->LayoutList, TRUE); 889 pSetupData->LayoutList = NULL; 890 } 891 892 /* Destroy the languages list */ 893 if (pSetupData->LanguageList != NULL) 894 { 895 DestroyGenericList(pSetupData->LanguageList, FALSE); 896 pSetupData->LanguageList = NULL; 897 } 898 899 /* Close the Setup INF */ 900 SpInfCloseInfFile(pSetupData->SetupInf); 901 } 902 903 /* 904 * SIDEEFFECTS 905 * Calls RegInitializeRegistry 906 * Calls ImportRegistryFile 907 * Calls SetDefaultPagefile 908 * Calls SetMountedDeviceValues 909 */ 910 ERROR_NUMBER 911 UpdateRegistry( 912 IN OUT PUSETUP_DATA pSetupData, 913 /**/IN BOOLEAN RepairUpdateFlag, /* HACK HACK! */ 914 /**/IN PPARTLIST PartitionList, /* HACK HACK! */ 915 /**/IN WCHAR DestinationDriveLetter, /* HACK HACK! */ 916 /**/IN PCWSTR SelectedLanguageId, /* HACK HACK! */ 917 IN PREGISTRY_STATUS_ROUTINE StatusRoutine OPTIONAL, 918 IN PFONTSUBSTSETTINGS SubstSettings OPTIONAL) 919 { 920 ERROR_NUMBER ErrorNumber; 921 NTSTATUS Status; 922 INFCONTEXT InfContext; 923 PCWSTR Action; 924 PCWSTR File; 925 PCWSTR Section; 926 BOOLEAN Success; 927 BOOLEAN ShouldRepairRegistry = FALSE; 928 BOOLEAN Delete; 929 930 if (RepairUpdateFlag) 931 { 932 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n"); 933 934 /* Verify the registry hives and check whether we need to update or repair any of them */ 935 Status = VerifyRegistryHives(&pSetupData->DestinationPath, &ShouldRepairRegistry); 936 if (!NT_SUCCESS(Status)) 937 { 938 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status); 939 ShouldRepairRegistry = FALSE; 940 } 941 if (!ShouldRepairRegistry) 942 DPRINT1("No need to repair the registry\n"); 943 } 944 945 DoUpdate: 946 ErrorNumber = ERROR_SUCCESS; 947 948 /* Update the registry */ 949 if (StatusRoutine) StatusRoutine(RegHiveUpdate); 950 951 /* Initialize the registry and setup the registry hives */ 952 Status = RegInitializeRegistry(&pSetupData->DestinationPath); 953 if (!NT_SUCCESS(Status)) 954 { 955 DPRINT1("RegInitializeRegistry() failed\n"); 956 /********** HACK!!!!!!!!!!! **********/ 957 if (Status == STATUS_NOT_IMPLEMENTED) 958 { 959 /* The hack was called, return its corresponding error */ 960 return ERROR_INITIALIZE_REGISTRY; 961 } 962 else 963 /*************************************/ 964 { 965 /* Something else failed */ 966 return ERROR_CREATE_HIVE; 967 } 968 } 969 970 if (!RepairUpdateFlag || ShouldRepairRegistry) 971 { 972 /* 973 * We fully setup the hives, in case we are doing a fresh installation 974 * (RepairUpdateFlag == FALSE), or in case we are doing an update 975 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to 976 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE). 977 */ 978 979 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Fresh", NULL, &InfContext); // Windows-compatible 980 if (!Success) 981 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Install", NULL, &InfContext); // ReactOS-specific 982 983 if (!Success) 984 { 985 DPRINT1("SpInfFindFirstLine() failed\n"); 986 ErrorNumber = ERROR_FIND_REGISTRY; 987 goto Cleanup; 988 } 989 } 990 else // if (RepairUpdateFlag && !ShouldRepairRegistry) 991 { 992 /* 993 * In case we are doing an update (RepairUpdateFlag == TRUE) and 994 * NO registry hives need a repair (ShouldRepairRegistry == FALSE), 995 * we only update the hives. 996 */ 997 998 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Upgrade", NULL, &InfContext); 999 if (!Success) 1000 { 1001 /* Nothing to do for update! */ 1002 DPRINT1("No update needed for the registry!\n"); 1003 goto Cleanup; 1004 } 1005 } 1006 1007 do 1008 { 1009 INF_GetDataField(&InfContext, 0, &Action); 1010 INF_GetDataField(&InfContext, 1, &File); 1011 INF_GetDataField(&InfContext, 2, &Section); 1012 1013 DPRINT("Action: %S File: %S Section %S\n", Action, File, Section); 1014 1015 if (Action == NULL) 1016 { 1017 INF_FreeData(Action); 1018 INF_FreeData(File); 1019 INF_FreeData(Section); 1020 break; // Hackfix 1021 } 1022 1023 if (!_wcsicmp(Action, L"AddReg")) 1024 Delete = FALSE; 1025 else if (!_wcsicmp(Action, L"DelReg")) 1026 Delete = TRUE; 1027 else 1028 { 1029 DPRINT1("Unrecognized registry INF action '%S'\n", Action); 1030 INF_FreeData(Action); 1031 INF_FreeData(File); 1032 INF_FreeData(Section); 1033 continue; 1034 } 1035 1036 INF_FreeData(Action); 1037 1038 if (StatusRoutine) StatusRoutine(ImportRegHive, File); 1039 1040 if (!ImportRegistryFile(pSetupData->SourcePath.Buffer, 1041 File, Section, 1042 pSetupData->LanguageId, Delete)) 1043 { 1044 DPRINT1("Importing %S failed\n", File); 1045 INF_FreeData(File); 1046 INF_FreeData(Section); 1047 ErrorNumber = ERROR_IMPORT_HIVE; 1048 goto Cleanup; 1049 } 1050 } while (SpInfFindNextLine(&InfContext, &InfContext)); 1051 1052 if (!RepairUpdateFlag || ShouldRepairRegistry) 1053 { 1054 /* See the explanation for this test above */ 1055 1056 PGENERIC_LIST_ENTRY Entry; 1057 PCWSTR LanguageId; // LocaleID; 1058 1059 Entry = GetCurrentListEntry(pSetupData->DisplayList); 1060 ASSERT(Entry); 1061 pSetupData->DisplayType = ((PGENENTRY)GetListEntryData(Entry))->Id; 1062 ASSERT(pSetupData->DisplayType); 1063 1064 /* Update display registry settings */ 1065 if (StatusRoutine) StatusRoutine(DisplaySettingsUpdate); 1066 if (!ProcessDisplayRegistry(pSetupData->SetupInf, pSetupData->DisplayType)) 1067 { 1068 ErrorNumber = ERROR_UPDATE_DISPLAY_SETTINGS; 1069 goto Cleanup; 1070 } 1071 1072 Entry = GetCurrentListEntry(pSetupData->LanguageList); 1073 ASSERT(Entry); 1074 LanguageId = ((PGENENTRY)GetListEntryData(Entry))->Id; 1075 ASSERT(LanguageId); 1076 1077 /* Set the locale */ 1078 if (StatusRoutine) StatusRoutine(LocaleSettingsUpdate); 1079 if (!ProcessLocaleRegistry(/*pSetupData->*/LanguageId)) 1080 { 1081 ErrorNumber = ERROR_UPDATE_LOCALESETTINGS; 1082 goto Cleanup; 1083 } 1084 1085 /* Add the keyboard layouts for the given language (without user override) */ 1086 if (StatusRoutine) StatusRoutine(KeybLayouts); 1087 if (!AddKeyboardLayouts(SelectedLanguageId)) 1088 { 1089 ErrorNumber = ERROR_ADDING_KBLAYOUTS; 1090 goto Cleanup; 1091 } 1092 1093 if (!IsUnattendedSetup) 1094 { 1095 Entry = GetCurrentListEntry(pSetupData->LayoutList); 1096 ASSERT(Entry); 1097 pSetupData->LayoutId = ((PGENENTRY)GetListEntryData(Entry))->Id; 1098 ASSERT(pSetupData->LayoutId); 1099 1100 /* Update keyboard layout settings with user-overridden values */ 1101 // FIXME: Wouldn't it be better to do it all at once 1102 // with the AddKeyboardLayouts() step? 1103 if (StatusRoutine) StatusRoutine(KeybSettingsUpdate); 1104 if (!ProcessKeyboardLayoutRegistry(pSetupData->LayoutId, SelectedLanguageId)) 1105 { 1106 ErrorNumber = ERROR_UPDATE_KBSETTINGS; 1107 goto Cleanup; 1108 } 1109 } 1110 1111 /* Set GeoID */ 1112 if (!SetGeoID(MUIGetGeoID(SelectedLanguageId))) 1113 { 1114 ErrorNumber = ERROR_UPDATE_GEOID; 1115 goto Cleanup; 1116 } 1117 1118 /* Add codepage information to registry */ 1119 if (StatusRoutine) StatusRoutine(CodePageInfoUpdate); 1120 if (!AddCodePage(SelectedLanguageId)) 1121 { 1122 ErrorNumber = ERROR_ADDING_CODEPAGE; 1123 goto Cleanup; 1124 } 1125 1126 /* Set the default pagefile entry */ 1127 SetDefaultPagefile(DestinationDriveLetter); 1128 1129 /* Update the mounted devices list */ 1130 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)! 1131 SetMountedDeviceValues(PartitionList); 1132 } 1133 1134 #ifdef __REACTOS__ 1135 if (SubstSettings) 1136 { 1137 /* HACK */ 1138 DoRegistryFontFixup(SubstSettings, wcstoul(SelectedLanguageId, NULL, 16)); 1139 } 1140 #endif 1141 1142 Cleanup: 1143 // 1144 // TODO: Unload all the registry stuff, perform cleanup, 1145 // and copy the created hive files into .sav files. 1146 // 1147 RegCleanupRegistry(&pSetupData->DestinationPath); 1148 1149 /* 1150 * Check whether we were in update/repair mode but we were actually 1151 * repairing the registry hives. If so, we have finished repairing them, 1152 * and we now reset the flag and run the proper registry update. 1153 * Otherwise we have finished the registry update! 1154 */ 1155 if (RepairUpdateFlag && ShouldRepairRegistry) 1156 { 1157 ShouldRepairRegistry = FALSE; 1158 goto DoUpdate; 1159 } 1160 1161 return ErrorNumber; 1162 } 1163 1164 /* EOF */ 1165