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' */ 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' */ 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' (optional) */ 138 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"InstallationDirectory", &Context)) 139 { 140 if (INF_GetData(&Context, NULL, &Value)) 141 { 142 RtlStringCchCopyW(pSetupData->InstallationDirectory, 143 ARRAYSIZE(pSetupData->InstallationDirectory), 144 Value); 145 INF_FreeData(Value); 146 } 147 else 148 { 149 DPRINT("INF_GetData() failed for key 'InstallationDirectory'\n"); 150 } 151 } 152 153 IsUnattendedSetup = TRUE; 154 DPRINT("Running unattended setup\n"); 155 156 /* Search for 'BootLoaderLocation' (optional) */ 157 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"BootLoaderLocation", &Context)) 158 { 159 if (SpInfGetIntField(&Context, 1, &IntValue)) 160 pSetupData->BootLoaderLocation = IntValue; 161 } 162 163 /* Search for 'FormatPartition' (optional) */ 164 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"FormatPartition", &Context)) 165 { 166 if (SpInfGetIntField(&Context, 1, &IntValue)) 167 pSetupData->FormatPartition = IntValue; 168 } 169 170 /* Search for 'AutoPartition' (optional) */ 171 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"AutoPartition", &Context)) 172 { 173 if (SpInfGetIntField(&Context, 1, &IntValue)) 174 pSetupData->AutoPartition = IntValue; 175 } 176 177 /* Search for 'LocaleID' (optional) */ 178 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"LocaleID", &Context)) 179 { 180 if (INF_GetData(&Context, NULL, &Value)) 181 { 182 LONG Id = wcstol(Value, NULL, 16); 183 RtlStringCchPrintfW(pSetupData->LocaleID, 184 ARRAYSIZE(pSetupData->LocaleID), 185 L"%08lx", Id); 186 INF_FreeData(Value); 187 } 188 } 189 190 /* Search for 'FsType' (optional) */ 191 if (SpInfFindFirstLine(UnattendInf, L"Unattend", L"FsType", &Context)) 192 { 193 if (SpInfGetIntField(&Context, 1, &IntValue)) 194 pSetupData->FsType = IntValue; 195 } 196 197 Quit: 198 SpInfCloseInfFile(UnattendInf); 199 } 200 201 VOID 202 InstallSetupInfFile( 203 IN OUT PUSETUP_DATA pSetupData) 204 { 205 NTSTATUS Status; 206 PINICACHE IniCache; 207 208 #if 0 // HACK FIXME! 209 PINICACHE UnattendCache; 210 PINICACHEITERATOR Iterator; 211 #else 212 // WCHAR CrLf[] = {L'\r', L'\n'}; 213 CHAR CrLf[] = {'\r', '\n'}; 214 HANDLE FileHandle, UnattendFileHandle, SectionHandle; 215 FILE_STANDARD_INFORMATION FileInfo; 216 ULONG FileSize; 217 PVOID ViewBase; 218 UNICODE_STRING FileName; 219 OBJECT_ATTRIBUTES ObjectAttributes; 220 IO_STATUS_BLOCK IoStatusBlock; 221 #endif 222 223 PINI_SECTION IniSection; 224 WCHAR PathBuffer[MAX_PATH]; 225 WCHAR UnattendInfPath[MAX_PATH]; 226 227 /* Create a $winnt$.inf file with default entries */ 228 IniCache = IniCacheCreate(); 229 if (!IniCache) 230 return; 231 232 IniSection = IniAddSection(IniCache, L"SetupParams"); 233 if (IniSection) 234 { 235 /* Key "skipmissingfiles" */ 236 // RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 237 // L"\"%s\"", L"WinNt5.2"); 238 // IniAddKey(IniSection, L"Version", PathBuffer); 239 } 240 241 IniSection = IniAddSection(IniCache, L"Data"); 242 if (IniSection) 243 { 244 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 245 L"\"%s\"", IsUnattendedSetup ? L"yes" : L"no"); 246 IniAddKey(IniSection, L"UnattendedInstall", PathBuffer); 247 248 // "floppylessbootpath" (yes/no) 249 250 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 251 L"\"%s\"", L"winnt"); 252 IniAddKey(IniSection, L"ProductType", PathBuffer); 253 254 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 255 L"\"%s\\\"", pSetupData->SourceRootPath.Buffer); 256 IniAddKey(IniSection, L"SourcePath", PathBuffer); 257 258 // "floppyless" ("0") 259 } 260 261 #if 0 262 263 /* TODO: Append the standard unattend.inf file */ 264 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, 265 pSetupData->SourcePath.Buffer, L"unattend.inf"); 266 if (DoesFileExist(NULL, UnattendInfPath) == FALSE) 267 { 268 DPRINT("Does not exist: %S\n", UnattendInfPath); 269 goto Quit; 270 } 271 272 Status = IniCacheLoad(&UnattendCache, UnattendInfPath, FALSE); 273 if (!NT_SUCCESS(Status)) 274 { 275 DPRINT1("Cannot load %S as an INI file!\n", UnattendInfPath); 276 goto Quit; 277 } 278 279 IniCacheDestroy(UnattendCache); 280 281 Quit: 282 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2, 283 pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf"); 284 IniCacheSave(IniCache, PathBuffer); 285 IniCacheDestroy(IniCache); 286 287 #else 288 289 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2, 290 pSetupData->DestinationPath.Buffer, L"System32\\$winnt$.inf"); 291 IniCacheSave(IniCache, PathBuffer); 292 IniCacheDestroy(IniCache); 293 294 /* TODO: Append the standard unattend.inf file */ 295 CombinePaths(UnattendInfPath, ARRAYSIZE(UnattendInfPath), 2, 296 pSetupData->SourcePath.Buffer, L"unattend.inf"); 297 if (DoesFileExist(NULL, UnattendInfPath) == FALSE) 298 { 299 DPRINT("Does not exist: %S\n", UnattendInfPath); 300 return; 301 } 302 303 RtlInitUnicodeString(&FileName, PathBuffer); 304 InitializeObjectAttributes(&ObjectAttributes, 305 &FileName, 306 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 307 NULL, 308 NULL); 309 Status = NtOpenFile(&FileHandle, 310 FILE_APPEND_DATA | SYNCHRONIZE, 311 &ObjectAttributes, 312 &IoStatusBlock, 313 FILE_SHARE_READ, 314 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); 315 if (!NT_SUCCESS(Status)) 316 { 317 DPRINT1("Cannot load %S as an INI file!\n", PathBuffer); 318 return; 319 } 320 321 /* Query the file size */ 322 Status = NtQueryInformationFile(FileHandle, 323 &IoStatusBlock, 324 &FileInfo, 325 sizeof(FileInfo), 326 FileStandardInformation); 327 if (!NT_SUCCESS(Status)) 328 { 329 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status); 330 FileInfo.EndOfFile.QuadPart = 0ULL; 331 } 332 333 Status = OpenAndMapFile(NULL, 334 UnattendInfPath, 335 &UnattendFileHandle, 336 &FileSize, 337 &SectionHandle, 338 &ViewBase, 339 FALSE); 340 if (!NT_SUCCESS(Status)) 341 { 342 DPRINT1("Cannot load %S !\n", UnattendInfPath); 343 NtClose(FileHandle); 344 return; 345 } 346 347 /* Write to the INI file */ 348 349 /* "\r\n" */ 350 Status = NtWriteFile(FileHandle, 351 NULL, 352 NULL, 353 NULL, 354 &IoStatusBlock, 355 (PVOID)CrLf, 356 sizeof(CrLf), 357 &FileInfo.EndOfFile, 358 NULL); 359 360 Status = NtWriteFile(FileHandle, 361 NULL, 362 NULL, 363 NULL, 364 &IoStatusBlock, 365 ViewBase, 366 FileSize, 367 NULL, 368 NULL); 369 if (!NT_SUCCESS(Status)) 370 { 371 DPRINT("NtWriteFile() failed (Status %lx)\n", Status); 372 } 373 374 /* Finally, unmap and close the file */ 375 UnMapAndCloseFile(UnattendFileHandle, SectionHandle, ViewBase); 376 377 NtClose(FileHandle); 378 #endif 379 } 380 381 /** 382 * @brief 383 * Determine the installation source path and isolate its useful 384 * path components (root path and source sub-directory). 385 * 386 * The installation source path is based either on the installer's 387 * image file path, or on the \SystemRoot full path. 388 * 389 * In case the \SystemRoot full path prefixes the image file path, 390 * use the resolved \SystemRoot as the installation source path. 391 * Otherwise, use the image file path. 392 * 393 * The returned strings are allocated with RtlCreateUnicodeString(), 394 * and need to be freed with RtlFreeUnicodeString() after being used. 395 * 396 * Example of output: 397 * SourcePath: '\Device\CdRom0\I386' 398 * SourceRootPath: '\Device\CdRom0' 399 * SourceRootDir: '\I386' 400 **/ 401 NTSTATUS 402 GetSourcePaths( 403 _Out_ PUNICODE_STRING SourcePath, 404 _Out_ PUNICODE_STRING SourceRootPath, 405 _Out_ PUNICODE_STRING SourceRootDir) 406 { 407 NTSTATUS Status; 408 ULONG BufferSize; 409 PWCHAR Ptr; 410 HANDLE LinkHandle; 411 OBJECT_ATTRIBUTES ObjectAttributes; 412 IO_STATUS_BLOCK IoStatusBlock; 413 struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } ImageFileBuffer; 414 PUNICODE_STRING InstallSourcePath = &ImageFileBuffer.Name; 415 struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } SystemRootBuffer; 416 PUNICODE_STRING SystemRootPath = &SystemRootBuffer.Name; 417 const UNICODE_STRING SystemRoot = RTL_CONSTANT_STRING(L"\\SystemRoot"); 418 419 /* Retrieve the installer's full image file path */ 420 RtlInitEmptyUnicodeString(InstallSourcePath, 421 ImageFileBuffer.Buffer, 422 sizeof(ImageFileBuffer.Buffer)); 423 BufferSize = sizeof(ImageFileBuffer); 424 Status = NtQueryInformationProcess(NtCurrentProcess(), 425 ProcessImageFileName, 426 InstallSourcePath, 427 BufferSize, 428 NULL); 429 // STATUS_INFO_LENGTH_MISMATCH or STATUS_BUFFER_TOO_SMALL ? 430 if (!NT_SUCCESS(Status)) 431 return Status; 432 ASSERT(InstallSourcePath->Length < InstallSourcePath->MaximumLength); 433 434 /* Go to the beginning of the path component, stop at the separator */ 435 Ptr = ImageFileBuffer.Buffer + (InstallSourcePath->Length / sizeof(WCHAR)); 436 while ((Ptr > ImageFileBuffer.Buffer) && (*Ptr != OBJ_NAME_PATH_SEPARATOR)) 437 --Ptr; 438 /* Strip the trailing file name (at the separator or beginning of buffer) 439 * and manually NULL-terminate */ 440 InstallSourcePath->Length = (ULONG_PTR)Ptr - (ULONG_PTR)ImageFileBuffer.Buffer; 441 InstallSourcePath->Buffer[InstallSourcePath->Length / sizeof(WCHAR)] = UNICODE_NULL; 442 443 444 /* 445 * Now, resolve the \SystemRoot symlink target full path. 446 * 447 * The symlink target path resolution requires reparsing, because it 448 * can reference other symlinks. This is what happens, for example when 449 * booting the installation from a removable hard-disk. We can have: 450 * 451 * \SystemRoot ---> \Device\Harddisk1\Partition1\ReactOS 452 * and: \Device\Harddisk1\Partition1 ---> \Device\HarddiskVolume2 453 * etc. 454 * and we wish to resolve \SystemRoot to: \Device\HarddiskVolume2\ReactOS 455 * 456 * We then verify whether it prefixes the image file path obtained 457 * from the step above, which is a fully reparsed path. 458 * 459 * - Using NtOpenSymbolicLinkObject(SYMBOLIC_LINK_QUERY) followed by 460 * NtQuerySymbolicLinkObject() would only resolve the first symlink 461 * but not the others (\Device\Harddisk1\Partition1 left as is). 462 * 463 * - Since \SystemRoot has to point to a directory, we try opening 464 * the directory itself: NtOpenFile(..., FILE_DIRECTORY_FILE). 465 * 466 * - A call to NtQueryInformationFile(FileNameInformation) alone on 467 * the obtained handle would only retrieve the FS directory name, 468 * i.e. \ReactOS , but not the whole NT path. 469 * 470 * - We therefore use NtQueryObject(), which allows retrieving the 471 * full resolved NT path (device name + FS directory name). 472 */ 473 474 InitializeObjectAttributes(&ObjectAttributes, 475 (PUNICODE_STRING)&SystemRoot, 476 OBJ_CASE_INSENSITIVE, 477 NULL, 478 NULL); 479 480 RtlInitEmptyUnicodeString(SystemRootPath, 481 SystemRootBuffer.Buffer, 482 sizeof(SystemRootBuffer.Buffer)); 483 484 Status = NtOpenFile(&LinkHandle, 485 SYNCHRONIZE, 486 &ObjectAttributes, 487 &IoStatusBlock, 488 FILE_SHARE_READ | FILE_SHARE_WRITE, 489 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT 490 /*| FILE_OPEN_FOR_BACKUP_INTENT*/); 491 if (NT_SUCCESS(Status)) 492 { 493 /* Resolve the path and close its handle */ 494 Status = NtQueryObject(LinkHandle, 495 ObjectNameInformation, 496 &SystemRootBuffer, 497 sizeof(SystemRootBuffer), 498 &BufferSize); 499 NtClose(LinkHandle); 500 } 501 /* If any of the calls above failed, try to naively resolve the symlink */ 502 if (!NT_SUCCESS(Status)) 503 { 504 RtlInitEmptyUnicodeString(SystemRootPath, 505 SystemRootBuffer.Buffer, 506 sizeof(SystemRootBuffer.Buffer)); 507 508 Status = NtOpenSymbolicLinkObject(&LinkHandle, 509 SYMBOLIC_LINK_QUERY, 510 &ObjectAttributes); 511 if (NT_SUCCESS(Status)) 512 { 513 /* Resolve the link and close its handle */ 514 Status = NtQuerySymbolicLinkObject(LinkHandle, 515 SystemRootPath, 516 &BufferSize); 517 NtClose(LinkHandle); 518 } 519 } 520 ASSERT(SystemRootPath->Length < SystemRootPath->MaximumLength); 521 522 /* 523 * If the resolved \SystemRoot is a prefix of the image file path, 524 * use \SystemRoot instead as the installation source path. 525 * 526 * If opening the \SystemRoot link failed (usually due to wrong 527 * access rights), do not consider this as a fatal error, and 528 * use the image file path as the installation source path. 529 */ 530 if (NT_SUCCESS(Status) && RtlPrefixUnicodeString(SystemRootPath, InstallSourcePath, TRUE)) 531 InstallSourcePath = SystemRootPath; 532 533 534 /* 535 * Retrieve the different source path components. 536 */ 537 RtlCreateUnicodeString(SourcePath, InstallSourcePath->Buffer); 538 539 /* Isolate and strip the trailing (source root) directory */ 540 Ptr = wcsrchr(InstallSourcePath->Buffer, OBJ_NAME_PATH_SEPARATOR); 541 if (Ptr) 542 { 543 RtlCreateUnicodeString(SourceRootDir, Ptr); 544 *Ptr = UNICODE_NULL; 545 } 546 else 547 { 548 RtlCreateUnicodeString(SourceRootDir, L""); 549 } 550 551 RtlCreateUnicodeString(SourceRootPath, InstallSourcePath->Buffer); 552 553 return STATUS_SUCCESS; 554 } 555 556 ERROR_NUMBER 557 LoadSetupInf( 558 IN OUT PUSETUP_DATA pSetupData) 559 { 560 INFCONTEXT Context; 561 UINT ErrorLine; 562 INT IntValue; 563 PCWSTR Value; 564 WCHAR FileNameBuffer[MAX_PATH]; 565 566 CombinePaths(FileNameBuffer, ARRAYSIZE(FileNameBuffer), 2, 567 pSetupData->SourcePath.Buffer, L"txtsetup.sif"); 568 569 DPRINT("SetupInf path: '%S'\n", FileNameBuffer); 570 571 pSetupData->SetupInf = 572 SpInfOpenInfFile(FileNameBuffer, 573 NULL, 574 INF_STYLE_WIN4, 575 pSetupData->LanguageId, 576 &ErrorLine); 577 if (pSetupData->SetupInf == INVALID_HANDLE_VALUE) 578 return ERROR_LOAD_TXTSETUPSIF; 579 580 /* Open 'Version' section */ 581 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"Version", L"Signature", &Context)) 582 return ERROR_CORRUPT_TXTSETUPSIF; 583 584 /* Get pointer 'Signature' key */ 585 if (!INF_GetData(&Context, NULL, &Value)) 586 return ERROR_CORRUPT_TXTSETUPSIF; 587 588 /* Check 'Signature' string */ 589 if (_wcsicmp(Value, L"$ReactOS$") != 0 && 590 _wcsicmp(Value, L"$Windows NT$") != 0) 591 { 592 INF_FreeData(Value); 593 return ERROR_SIGNATURE_TXTSETUPSIF; 594 } 595 596 INF_FreeData(Value); 597 598 /* Open 'DiskSpaceRequirements' section */ 599 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"DiskSpaceRequirements", L"FreeSysPartDiskSpace", &Context)) 600 return ERROR_CORRUPT_TXTSETUPSIF; 601 602 pSetupData->RequiredPartitionDiskSpace = ~0; 603 604 /* Get the 'FreeSysPartDiskSpace' value */ 605 if (!SpInfGetIntField(&Context, 1, &IntValue)) 606 return ERROR_CORRUPT_TXTSETUPSIF; 607 608 pSetupData->RequiredPartitionDiskSpace = (ULONG)IntValue; 609 610 // 611 // Support "SetupSourceDevice" and "SetupSourcePath" in txtsetup.sif 612 // See CORE-9023 613 // Support for that should also be added in setupldr. 614 // 615 616 /* Update the Setup Source paths */ 617 if (SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"SetupSourceDevice", &Context)) 618 { 619 /* 620 * Get optional pointer 'SetupSourceDevice' key, its presence 621 * will dictate whether we also need 'SetupSourcePath'. 622 */ 623 if (INF_GetData(&Context, NULL, &Value)) 624 { 625 /* Free the old source root path string and create the new one */ 626 RtlFreeUnicodeString(&pSetupData->SourceRootPath); 627 RtlCreateUnicodeString(&pSetupData->SourceRootPath, Value); 628 INF_FreeData(Value); 629 630 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"SetupSourcePath", &Context)) 631 { 632 /* The 'SetupSourcePath' value is mandatory! */ 633 return ERROR_CORRUPT_TXTSETUPSIF; 634 } 635 636 /* Get pointer 'SetupSourcePath' key */ 637 if (!INF_GetData(&Context, NULL, &Value)) 638 { 639 /* The 'SetupSourcePath' value is mandatory! */ 640 return ERROR_CORRUPT_TXTSETUPSIF; 641 } 642 643 /* Free the old source path string and create the new one */ 644 RtlFreeUnicodeString(&pSetupData->SourceRootDir); 645 RtlCreateUnicodeString(&pSetupData->SourceRootDir, Value); 646 INF_FreeData(Value); 647 } 648 } 649 650 /* Search for 'DefaultPath' in the 'SetupData' section */ 651 pSetupData->InstallationDirectory[0] = 0; 652 if (SpInfFindFirstLine(pSetupData->SetupInf, L"SetupData", L"DefaultPath", &Context)) 653 { 654 /* Get pointer 'DefaultPath' key */ 655 if (!INF_GetData(&Context, NULL, &Value)) 656 return ERROR_CORRUPT_TXTSETUPSIF; 657 658 RtlStringCchCopyW(pSetupData->InstallationDirectory, 659 ARRAYSIZE(pSetupData->InstallationDirectory), 660 Value); 661 662 INF_FreeData(Value); 663 } 664 665 return ERROR_SUCCESS; 666 } 667 668 /** 669 * @brief Find or set the active system partition. 670 **/ 671 BOOLEAN 672 InitSystemPartition( 673 /**/_In_ PPARTLIST PartitionList, /* HACK HACK! */ 674 /**/_In_ PPARTENTRY InstallPartition, /* HACK HACK! */ 675 /**/_Out_ PPARTENTRY* pSystemPartition, /* HACK HACK! */ 676 _In_opt_ PFSVOL_CALLBACK FsVolCallback, 677 _In_opt_ PVOID Context) 678 { 679 FSVOL_OP Result; 680 PPARTENTRY SystemPartition; 681 PPARTENTRY OldActivePart; 682 683 /* 684 * If we install on a fixed disk, try to find a supported system 685 * partition on the system. Otherwise if we install on a removable disk 686 * use the install partition as the system partition. 687 */ 688 if (InstallPartition->DiskEntry->MediaType == FixedMedia) 689 { 690 SystemPartition = FindSupportedSystemPartition(PartitionList, 691 FALSE, 692 InstallPartition->DiskEntry, 693 InstallPartition); 694 /* Use the original system partition as the old active partition hint */ 695 OldActivePart = PartitionList->SystemPartition; 696 697 if ( SystemPartition && PartitionList->SystemPartition && 698 (SystemPartition != PartitionList->SystemPartition) ) 699 { 700 DPRINT1("We are using a different system partition!!\n"); 701 702 Result = FsVolCallback(Context, 703 ChangeSystemPartition, 704 (ULONG_PTR)SystemPartition, 705 0); 706 if (Result != FSVOL_DOIT) 707 return FALSE; 708 } 709 } 710 else // if (InstallPartition->DiskEntry->MediaType == RemovableMedia) 711 { 712 SystemPartition = InstallPartition; 713 /* Don't specify any old active partition hint */ 714 OldActivePart = NULL; 715 } 716 717 if (!SystemPartition) 718 { 719 FsVolCallback(Context, 720 FSVOLNOTIFY_PARTITIONERROR, 721 ERROR_SYSTEM_PARTITION_NOT_FOUND, 722 0); 723 return FALSE; 724 } 725 726 *pSystemPartition = SystemPartition; 727 728 /* 729 * If the system partition can be created in some 730 * non-partitioned space, create it now. 731 */ 732 if (!SystemPartition->IsPartitioned) 733 { 734 /* Automatically create the partition; it will be 735 * formatted later with default parameters */ 736 // FIXME: Don't use the whole empty space, but a minimal size 737 // specified from the TXTSETUP.SIF or unattended setup. 738 CreatePartition(PartitionList, 739 SystemPartition, 740 0ULL, 741 0); 742 ASSERT(SystemPartition->IsPartitioned); 743 } 744 745 /* Set it as such */ 746 if (!SetActivePartition(PartitionList, SystemPartition, OldActivePart)) 747 { 748 DPRINT1("SetActivePartition(0x%p) failed?!\n", SystemPartition); 749 ASSERT(FALSE); 750 } 751 752 /* 753 * In all cases, whether or not we are going to perform a formatting, 754 * we must perform a filesystem check of the system partition. 755 */ 756 if (SystemPartition->Volume) 757 SystemPartition->Volume->NeedsCheck = TRUE; 758 759 return TRUE; 760 } 761 762 763 #define IS_PATH_SEPARATOR(c) ((c) == L'\\' || (c) == L'/') 764 765 /** 766 * @brief 767 * Verify whether the given directory is suitable for ReactOS installation. 768 * Each path component must be a valid 8.3 name. 769 **/ 770 BOOLEAN 771 IsValidInstallDirectory( 772 _In_ PCWSTR InstallDir) 773 { 774 PCWCH p; 775 776 /* As with the NT installer, fail if the path is empty or "\\" */ 777 p = InstallDir; 778 if (!*p || (IS_PATH_SEPARATOR(*p) && !*(p + 1))) 779 return FALSE; 780 781 /* The path must contain only valid characters */ 782 for (p = InstallDir; *p; ++p) 783 { 784 if (!IS_VALID_INSTALL_PATH_CHAR(*p)) 785 return FALSE; 786 } 787 788 /* 789 * Loop over each path component and verify that each is a valid 8.3 name. 790 */ 791 for (p = InstallDir; *p;) 792 { 793 PCWSTR Path; 794 SIZE_T Length; 795 UNICODE_STRING Name; 796 BOOLEAN IsNameLegal, SpacesInName; 797 798 /* Skip any first separator */ 799 if (IS_PATH_SEPARATOR(*p)) 800 ++p; 801 802 /* Now skip past the path component until we reach the next separator */ 803 Path = p; 804 while (*p && !IS_PATH_SEPARATOR(*p)) 805 ++p; 806 if (p == Path) 807 { 808 /* Succeed if nothing else follows this separator; otherwise 809 * it's a separator and consecutive ones are not supported */ 810 return (!*p); 811 } 812 813 /* Calculate the path component length */ 814 Length = p - Path; 815 816 /* As with the NT installer, fail for '.' and '..'; 817 * RtlIsNameLegalDOS8Dot3() would succeed otherwise */ 818 if ((Length == 1 && *Path == '.') || (Length == 2 && *Path == '.' && *(Path + 1) == '.')) 819 return FALSE; 820 821 /* As with the NT installer, allow _only ONE trailing_ dot in 822 * the path component (but not 2 or more), by reducing Length 823 * in that case; RtlIsNameLegalDOS8Dot3() would fail otherwise */ 824 if (Length > 1 && *(p - 2) != L'.' && *(p - 1) == L'.') 825 --Length; 826 827 if (Length == 0) 828 return FALSE; 829 830 /* Verify that the path component is a valid 8.3 name */ 831 // if (Length > 8+1+3) 832 // return FALSE; 833 Name.Length = Name.MaximumLength = (USHORT)(Length * sizeof(WCHAR)); 834 Name.Buffer = (PWCHAR)Path; 835 SpacesInName = FALSE; 836 IsNameLegal = RtlIsNameLegalDOS8Dot3(&Name, NULL, &SpacesInName); 837 838 /* If it isn't legal or contain spaces, fail */ 839 if (!IsNameLegal || SpacesInName) 840 { 841 DPRINT("'%wZ' is %s 8.3 filename %s spaces\n", 842 &Name, 843 (IsNameLegal ? "a valid" : "an invalid"), 844 (SpacesInName ? "with" : "without")); 845 return FALSE; 846 } 847 /* Go to the next path component */ 848 } 849 850 return TRUE; 851 } 852 853 854 NTSTATUS 855 InitDestinationPaths( 856 _Inout_ PUSETUP_DATA pSetupData, 857 _In_ PCWSTR InstallationDir, 858 _In_ PVOLENTRY Volume) 859 { 860 NTSTATUS Status; 861 PPARTENTRY PartEntry = Volume->PartEntry; 862 PDISKENTRY DiskEntry = PartEntry->DiskEntry; 863 WCHAR PathBuffer[RTL_NUMBER_OF_FIELD(VOLINFO, DeviceName) + 1]; 864 865 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0); 866 867 /* Create 'pSetupData->DestinationRootPath' string */ 868 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 869 Status = RtlStringCchPrintfW(PathBuffer, _countof(PathBuffer), 870 L"%s\\", Volume->Info.DeviceName); 871 if (!NT_SUCCESS(Status)) 872 { 873 DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status); 874 return Status; 875 } 876 877 Status = RtlCreateUnicodeString(&pSetupData->DestinationRootPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY; 878 879 if (!NT_SUCCESS(Status)) 880 { 881 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status); 882 return Status; 883 } 884 885 DPRINT("DestinationRootPath: %wZ\n", &pSetupData->DestinationRootPath); 886 887 // FIXME! Which variable to choose? 888 if (!InstallationDir) 889 InstallationDir = pSetupData->InstallationDirectory; 890 891 /** Equivalent of 'NTOS_INSTALLATION::SystemArcPath' **/ 892 /* Create 'pSetupData->DestinationArcPath' */ 893 RtlFreeUnicodeString(&pSetupData->DestinationArcPath); 894 895 if (DiskEntry->MediaType == FixedMedia) 896 { 897 if (DiskEntry->BiosFound) 898 { 899 #if 1 900 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 901 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\", 902 DiskEntry->HwFixedDiskNumber, 903 PartEntry->OnDiskPartitionNumber); 904 #else 905 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 906 L"multi(%lu)disk(%lu)rdisk(%lu)partition(%lu)\\", 907 DiskEntry->HwAdapterNumber, 908 DiskEntry->HwControllerNumber, 909 DiskEntry->HwFixedDiskNumber, 910 PartEntry->OnDiskPartitionNumber); 911 #endif 912 DPRINT1("Fixed disk found by BIOS, using MULTI ARC path '%S'\n", PathBuffer); 913 } 914 else 915 { 916 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 917 L"scsi(%u)disk(%u)rdisk(%u)partition(%lu)\\", 918 DiskEntry->Port, 919 DiskEntry->Bus, 920 DiskEntry->Id, 921 PartEntry->OnDiskPartitionNumber); 922 DPRINT1("Fixed disk not found by BIOS, using SCSI ARC path '%S'\n", PathBuffer); 923 } 924 } 925 else // if (DiskEntry->MediaType == RemovableMedia) 926 { 927 #if 1 928 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 929 L"multi(0)disk(0)rdisk(%lu)partition(%lu)\\", 930 0, 1); 931 DPRINT1("Removable disk, using MULTI ARC path '%S'\n", PathBuffer); 932 #else 933 Status = RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), 934 L"signature(%08x)disk(%u)rdisk(%u)partition(%lu)\\", 935 DiskEntry->LayoutBuffer->Signature, 936 DiskEntry->Bus, 937 DiskEntry->Id, 938 PartEntry->OnDiskPartitionNumber); 939 DPRINT1("Removable disk, using SIGNATURE ARC path '%S'\n", PathBuffer); 940 #endif 941 } 942 943 if (!NT_SUCCESS(Status)) 944 { 945 DPRINT1("RtlStringCchPrintfW() failed with status 0x%08lx\n", Status); 946 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 947 return Status; 948 } 949 950 Status = ConcatPaths(PathBuffer, ARRAYSIZE(PathBuffer), 1, InstallationDir); 951 952 if (!NT_SUCCESS(Status)) 953 { 954 DPRINT1("ConcatPaths() failed with status 0x%08lx\n", Status); 955 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 956 return Status; 957 } 958 959 Status = RtlCreateUnicodeString(&pSetupData->DestinationArcPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY; 960 961 if (!NT_SUCCESS(Status)) 962 { 963 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status); 964 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 965 return Status; 966 } 967 968 /** Equivalent of 'NTOS_INSTALLATION::SystemNtPath' **/ 969 /* Create 'pSetupData->DestinationPath' string */ 970 RtlFreeUnicodeString(&pSetupData->DestinationPath); 971 Status = CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2, 972 pSetupData->DestinationRootPath.Buffer, InstallationDir); 973 974 if (!NT_SUCCESS(Status)) 975 { 976 DPRINT1("CombinePaths() failed with status 0x%08lx\n", Status); 977 RtlFreeUnicodeString(&pSetupData->DestinationArcPath); 978 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 979 return Status; 980 } 981 982 Status = RtlCreateUnicodeString(&pSetupData->DestinationPath, PathBuffer) ? STATUS_SUCCESS : STATUS_NO_MEMORY; 983 984 if (!NT_SUCCESS(Status)) 985 { 986 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status); 987 RtlFreeUnicodeString(&pSetupData->DestinationArcPath); 988 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 989 return Status; 990 } 991 992 /** Equivalent of 'NTOS_INSTALLATION::PathComponent' **/ 993 // FIXME: This is only temporary!! Must be removed later! 994 Status = RtlCreateUnicodeString(&pSetupData->InstallPath, InstallationDir) ? STATUS_SUCCESS : STATUS_NO_MEMORY; 995 996 if (!NT_SUCCESS(Status)) 997 { 998 DPRINT1("RtlCreateUnicodeString() failed with status 0x%08lx\n", Status); 999 RtlFreeUnicodeString(&pSetupData->DestinationPath); 1000 RtlFreeUnicodeString(&pSetupData->DestinationArcPath); 1001 RtlFreeUnicodeString(&pSetupData->DestinationRootPath); 1002 return Status; 1003 } 1004 1005 return STATUS_SUCCESS; 1006 } 1007 1008 // NTSTATUS 1009 ERROR_NUMBER 1010 InitializeSetup( 1011 IN OUT PUSETUP_DATA pSetupData, 1012 IN ULONG InitPhase) 1013 { 1014 if (InitPhase == 0) 1015 { 1016 RtlZeroMemory(pSetupData, sizeof(*pSetupData)); 1017 1018 /* Initialize error handling */ 1019 pSetupData->LastErrorNumber = ERROR_SUCCESS; 1020 pSetupData->ErrorRoutine = NULL; 1021 1022 /* Initialize global unicode strings */ 1023 RtlInitUnicodeString(&pSetupData->SourcePath, NULL); 1024 RtlInitUnicodeString(&pSetupData->SourceRootPath, NULL); 1025 RtlInitUnicodeString(&pSetupData->SourceRootDir, NULL); 1026 RtlInitUnicodeString(&pSetupData->DestinationArcPath, NULL); 1027 RtlInitUnicodeString(&pSetupData->DestinationPath, NULL); 1028 RtlInitUnicodeString(&pSetupData->DestinationRootPath, NULL); 1029 RtlInitUnicodeString(&pSetupData->SystemRootPath, NULL); 1030 1031 // FIXME: This is only temporary!! Must be removed later! 1032 /***/RtlInitUnicodeString(&pSetupData->InstallPath, NULL);/***/ 1033 1034 // 1035 // TODO: Load and start SetupDD, and ask it for the information 1036 // 1037 1038 return ERROR_SUCCESS; 1039 } 1040 else 1041 if (InitPhase == 1) 1042 { 1043 ERROR_NUMBER Error; 1044 NTSTATUS Status; 1045 1046 /* Get the source path and source root path */ 1047 Status = GetSourcePaths(&pSetupData->SourcePath, 1048 &pSetupData->SourceRootPath, 1049 &pSetupData->SourceRootDir); 1050 if (!NT_SUCCESS(Status)) 1051 { 1052 DPRINT1("GetSourcePaths() failed (Status 0x%08lx)\n", Status); 1053 return ERROR_NO_SOURCE_DRIVE; 1054 } 1055 DPRINT1("SourcePath (1): '%wZ'\n", &pSetupData->SourcePath); 1056 DPRINT1("SourceRootPath (1): '%wZ'\n", &pSetupData->SourceRootPath); 1057 DPRINT1("SourceRootDir (1): '%wZ'\n", &pSetupData->SourceRootDir); 1058 1059 /* Set up default values */ 1060 pSetupData->DestinationDiskNumber = 0; 1061 pSetupData->DestinationPartitionNumber = 1; 1062 pSetupData->BootLoaderLocation = 2; // Default to "System partition" 1063 pSetupData->FormatPartition = 0; 1064 pSetupData->AutoPartition = 0; 1065 pSetupData->FsType = 0; 1066 1067 /* Load 'txtsetup.sif' from the installation media */ 1068 Error = LoadSetupInf(pSetupData); 1069 if (Error != ERROR_SUCCESS) 1070 { 1071 DPRINT1("LoadSetupInf() failed (Error 0x%lx)\n", Error); 1072 return Error; 1073 } 1074 DPRINT1("SourcePath (2): '%wZ'\n", &pSetupData->SourcePath); 1075 DPRINT1("SourceRootPath (2): '%wZ'\n", &pSetupData->SourceRootPath); 1076 DPRINT1("SourceRootDir (2): '%wZ'\n", &pSetupData->SourceRootDir); 1077 1078 /* Retrieve the target machine architecture type */ 1079 // FIXME: This should be determined at runtime!! 1080 // FIXME: Allow for (pre-)installing on an architecture 1081 // different from the current one? 1082 #if defined(SARCH_XBOX) 1083 pSetupData->ArchType = ARCH_Xbox; 1084 // #elif defined(SARCH_PC98) 1085 #else // TODO: Arc, UEFI 1086 pSetupData->ArchType = (IsNEC_98 ? ARCH_NEC98x86 : ARCH_PcAT); 1087 #endif 1088 1089 return ERROR_SUCCESS; 1090 } 1091 1092 return ERROR_SUCCESS; 1093 } 1094 1095 VOID 1096 FinishSetup( 1097 IN OUT PUSETUP_DATA pSetupData) 1098 { 1099 /* Destroy the computer settings list */ 1100 if (pSetupData->ComputerList != NULL) 1101 { 1102 DestroyGenericList(pSetupData->ComputerList, TRUE); 1103 pSetupData->ComputerList = NULL; 1104 } 1105 1106 /* Destroy the display settings list */ 1107 if (pSetupData->DisplayList != NULL) 1108 { 1109 DestroyGenericList(pSetupData->DisplayList, TRUE); 1110 pSetupData->DisplayList = NULL; 1111 } 1112 1113 /* Destroy the keyboard settings list */ 1114 if (pSetupData->KeyboardList != NULL) 1115 { 1116 DestroyGenericList(pSetupData->KeyboardList, TRUE); 1117 pSetupData->KeyboardList = NULL; 1118 } 1119 1120 /* Destroy the keyboard layout list */ 1121 if (pSetupData->LayoutList != NULL) 1122 { 1123 DestroyGenericList(pSetupData->LayoutList, TRUE); 1124 pSetupData->LayoutList = NULL; 1125 } 1126 1127 /* Destroy the languages list */ 1128 if (pSetupData->LanguageList != NULL) 1129 { 1130 DestroyGenericList(pSetupData->LanguageList, FALSE); 1131 pSetupData->LanguageList = NULL; 1132 } 1133 1134 /* Close the Setup INF */ 1135 SpInfCloseInfFile(pSetupData->SetupInf); 1136 } 1137 1138 /* 1139 * SIDEEFFECTS 1140 * Calls RegInitializeRegistry 1141 * Calls ImportRegistryFile 1142 * Calls SetDefaultPagefile 1143 * Calls SetMountedDeviceValues 1144 */ 1145 ERROR_NUMBER 1146 UpdateRegistry( 1147 IN OUT PUSETUP_DATA pSetupData, 1148 /**/IN BOOLEAN RepairUpdateFlag, /* HACK HACK! */ 1149 /**/IN PPARTLIST PartitionList, /* HACK HACK! */ 1150 /**/IN WCHAR DestinationDriveLetter, /* HACK HACK! */ 1151 /**/IN PCWSTR SelectedLanguageId, /* HACK HACK! */ 1152 IN PREGISTRY_STATUS_ROUTINE StatusRoutine OPTIONAL, 1153 IN PFONTSUBSTSETTINGS SubstSettings OPTIONAL) 1154 { 1155 ERROR_NUMBER ErrorNumber; 1156 NTSTATUS Status; 1157 INFCONTEXT InfContext; 1158 PCWSTR Action; 1159 PCWSTR File; 1160 PCWSTR Section; 1161 BOOLEAN Success; 1162 BOOLEAN ShouldRepairRegistry = FALSE; 1163 BOOLEAN Delete; 1164 1165 if (RepairUpdateFlag) 1166 { 1167 DPRINT1("TODO: Updating / repairing the registry is not completely implemented yet!\n"); 1168 1169 /* Verify the registry hives and check whether we need to update or repair any of them */ 1170 Status = VerifyRegistryHives(&pSetupData->DestinationPath, &ShouldRepairRegistry); 1171 if (!NT_SUCCESS(Status)) 1172 { 1173 DPRINT1("VerifyRegistryHives failed, Status 0x%08lx\n", Status); 1174 ShouldRepairRegistry = FALSE; 1175 } 1176 if (!ShouldRepairRegistry) 1177 DPRINT1("No need to repair the registry\n"); 1178 } 1179 1180 DoUpdate: 1181 ErrorNumber = ERROR_SUCCESS; 1182 1183 /* Update the registry */ 1184 if (StatusRoutine) StatusRoutine(RegHiveUpdate); 1185 1186 /* Initialize the registry and setup the registry hives */ 1187 Status = RegInitializeRegistry(&pSetupData->DestinationPath); 1188 if (!NT_SUCCESS(Status)) 1189 { 1190 DPRINT1("RegInitializeRegistry() failed\n"); 1191 /********** HACK!!!!!!!!!!! **********/ 1192 if (Status == STATUS_NOT_IMPLEMENTED) 1193 { 1194 /* The hack was called, return its corresponding error */ 1195 return ERROR_INITIALIZE_REGISTRY; 1196 } 1197 else 1198 /*************************************/ 1199 { 1200 /* Something else failed */ 1201 return ERROR_CREATE_HIVE; 1202 } 1203 } 1204 1205 if (!RepairUpdateFlag || ShouldRepairRegistry) 1206 { 1207 /* 1208 * We fully setup the hives, in case we are doing a fresh installation 1209 * (RepairUpdateFlag == FALSE), or in case we are doing an update 1210 * (RepairUpdateFlag == TRUE) BUT we have some registry hives to 1211 * "repair" (aka. recreate: ShouldRepairRegistry == TRUE). 1212 */ 1213 1214 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Fresh", NULL, &InfContext); // Windows-compatible 1215 if (!Success) 1216 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Install", NULL, &InfContext); // ReactOS-specific 1217 1218 if (!Success) 1219 { 1220 DPRINT1("SpInfFindFirstLine() failed\n"); 1221 ErrorNumber = ERROR_FIND_REGISTRY; 1222 goto Cleanup; 1223 } 1224 } 1225 else // if (RepairUpdateFlag && !ShouldRepairRegistry) 1226 { 1227 /* 1228 * In case we are doing an update (RepairUpdateFlag == TRUE) and 1229 * NO registry hives need a repair (ShouldRepairRegistry == FALSE), 1230 * we only update the hives. 1231 */ 1232 1233 Success = SpInfFindFirstLine(pSetupData->SetupInf, L"HiveInfs.Upgrade", NULL, &InfContext); 1234 if (!Success) 1235 { 1236 /* Nothing to do for update! */ 1237 DPRINT1("No update needed for the registry!\n"); 1238 goto Cleanup; 1239 } 1240 } 1241 1242 do 1243 { 1244 INF_GetDataField(&InfContext, 0, &Action); 1245 INF_GetDataField(&InfContext, 1, &File); 1246 INF_GetDataField(&InfContext, 2, &Section); 1247 1248 DPRINT("Action: %S File: %S Section %S\n", Action, File, Section); 1249 1250 if (Action == NULL) 1251 { 1252 INF_FreeData(Action); 1253 INF_FreeData(File); 1254 INF_FreeData(Section); 1255 break; // Hackfix 1256 } 1257 1258 if (!_wcsicmp(Action, L"AddReg")) 1259 Delete = FALSE; 1260 else if (!_wcsicmp(Action, L"DelReg")) 1261 Delete = TRUE; 1262 else 1263 { 1264 DPRINT1("Unrecognized registry INF action '%S'\n", Action); 1265 INF_FreeData(Action); 1266 INF_FreeData(File); 1267 INF_FreeData(Section); 1268 continue; 1269 } 1270 1271 INF_FreeData(Action); 1272 1273 if (StatusRoutine) StatusRoutine(ImportRegHive, File); 1274 1275 if (!ImportRegistryFile(pSetupData->SourcePath.Buffer, 1276 File, Section, 1277 pSetupData->LanguageId, Delete)) 1278 { 1279 DPRINT1("Importing %S failed\n", File); 1280 INF_FreeData(File); 1281 INF_FreeData(Section); 1282 ErrorNumber = ERROR_IMPORT_HIVE; 1283 goto Cleanup; 1284 } 1285 } while (SpInfFindNextLine(&InfContext, &InfContext)); 1286 1287 if (!RepairUpdateFlag || ShouldRepairRegistry) 1288 { 1289 /* See the explanation for this test above */ 1290 1291 PGENERIC_LIST_ENTRY Entry; 1292 PCWSTR LanguageId; // LocaleID; 1293 1294 Entry = GetCurrentListEntry(pSetupData->DisplayList); 1295 ASSERT(Entry); 1296 pSetupData->DisplayType = ((PGENENTRY)GetListEntryData(Entry))->Id; 1297 ASSERT(pSetupData->DisplayType); 1298 1299 /* Update display registry settings */ 1300 if (StatusRoutine) StatusRoutine(DisplaySettingsUpdate); 1301 if (!ProcessDisplayRegistry(pSetupData->SetupInf, pSetupData->DisplayType)) 1302 { 1303 ErrorNumber = ERROR_UPDATE_DISPLAY_SETTINGS; 1304 goto Cleanup; 1305 } 1306 1307 Entry = GetCurrentListEntry(pSetupData->LanguageList); 1308 ASSERT(Entry); 1309 LanguageId = ((PGENENTRY)GetListEntryData(Entry))->Id; 1310 ASSERT(LanguageId); 1311 1312 /* Set the locale */ 1313 if (StatusRoutine) StatusRoutine(LocaleSettingsUpdate); 1314 if (!ProcessLocaleRegistry(/*pSetupData->*/LanguageId)) 1315 { 1316 ErrorNumber = ERROR_UPDATE_LOCALESETTINGS; 1317 goto Cleanup; 1318 } 1319 1320 /* Add the keyboard layouts for the given language (without user override) */ 1321 if (StatusRoutine) StatusRoutine(KeybLayouts); 1322 if (!AddKeyboardLayouts(SelectedLanguageId)) 1323 { 1324 ErrorNumber = ERROR_ADDING_KBLAYOUTS; 1325 goto Cleanup; 1326 } 1327 1328 if (!IsUnattendedSetup) 1329 { 1330 Entry = GetCurrentListEntry(pSetupData->LayoutList); 1331 ASSERT(Entry); 1332 pSetupData->LayoutId = ((PGENENTRY)GetListEntryData(Entry))->Id; 1333 ASSERT(pSetupData->LayoutId); 1334 1335 /* Update keyboard layout settings with user-overridden values */ 1336 // FIXME: Wouldn't it be better to do it all at once 1337 // with the AddKeyboardLayouts() step? 1338 if (StatusRoutine) StatusRoutine(KeybSettingsUpdate); 1339 if (!ProcessKeyboardLayoutRegistry(pSetupData->LayoutId, SelectedLanguageId)) 1340 { 1341 ErrorNumber = ERROR_UPDATE_KBSETTINGS; 1342 goto Cleanup; 1343 } 1344 } 1345 1346 /* Set GeoID */ 1347 if (!SetGeoID(MUIGetGeoID(SelectedLanguageId))) 1348 { 1349 ErrorNumber = ERROR_UPDATE_GEOID; 1350 goto Cleanup; 1351 } 1352 1353 /* Add codepage information to registry */ 1354 if (StatusRoutine) StatusRoutine(CodePageInfoUpdate); 1355 if (!AddCodePage(SelectedLanguageId)) 1356 { 1357 ErrorNumber = ERROR_ADDING_CODEPAGE; 1358 goto Cleanup; 1359 } 1360 1361 /* Set the default pagefile entry */ 1362 SetDefaultPagefile(DestinationDriveLetter); 1363 1364 /* Update the mounted devices list */ 1365 // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)! 1366 SetMountedDeviceValues(PartitionList); 1367 } 1368 1369 #ifdef __REACTOS__ 1370 if (SubstSettings) 1371 { 1372 /* HACK */ 1373 DoRegistryFontFixup(SubstSettings, wcstoul(SelectedLanguageId, NULL, 16)); 1374 } 1375 #endif 1376 1377 Cleanup: 1378 // 1379 // TODO: Unload all the registry stuff, perform cleanup, 1380 // and copy the created hive files into .sav files. 1381 // 1382 RegCleanupRegistry(&pSetupData->DestinationPath); 1383 1384 /* 1385 * Check whether we were in update/repair mode but we were actually 1386 * repairing the registry hives. If so, we have finished repairing them, 1387 * and we now reset the flag and run the proper registry update. 1388 * Otherwise we have finished the registry update! 1389 */ 1390 if (RepairUpdateFlag && ShouldRepairRegistry) 1391 { 1392 ShouldRepairRegistry = FALSE; 1393 goto DoUpdate; 1394 } 1395 1396 return ErrorNumber; 1397 } 1398 1399 /* EOF */ 1400