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