1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Setup Library 4 * FILE: base/setup/lib/install.c 5 * PURPOSE: Installation functions 6 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) 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 16 #include "setuplib.h" // HAXX for USETUP_DATA!! 17 18 #include "install.h" 19 20 #define NDEBUG 21 #include <debug.h> 22 23 24 /* FUNCTIONS ****************************************************************/ 25 26 static BOOL 27 LookupDirectoryById( 28 IN HINF InfHandle, 29 IN OUT PINFCONTEXT InfContext, 30 IN PCWSTR DirId, 31 OUT PCWSTR* pDirectory) 32 { 33 BOOL Success; 34 35 // ReactOS-specific 36 Success = SpInfFindFirstLine(InfHandle, L"Directories", DirId, InfContext); 37 if (!Success) 38 { 39 // Windows-compatible 40 Success = SpInfFindFirstLine(InfHandle, L"WinntDirectories", DirId, InfContext); 41 if (!Success) 42 DPRINT1("SpInfFindFirstLine() failed\n"); 43 } 44 if (Success) 45 { 46 Success = INF_GetData(InfContext, NULL, pDirectory); 47 if (!Success) 48 DPRINT1("INF_GetData() failed\n"); 49 } 50 51 if (!Success) 52 DPRINT1("LookupDirectoryById(%S) - directory not found!\n", DirId); 53 54 return Success; 55 } 56 57 /* 58 * Note: Modeled after SetupGetSourceFileLocation(), SetupGetSourceInfo() 59 * and SetupGetTargetPath() APIs. 60 * Technically the target path is the same for a given file section, 61 * but here we try to remove this constraint. 62 * 63 * TXTSETUP.SIF entries syntax explained at: 64 * http://www.msfn.org/board/topic/125480-txtsetupsif-syntax/ 65 */ 66 static NTSTATUS 67 GetSourceFileAndTargetLocation( 68 IN HINF InfHandle, 69 IN PINFCONTEXT InfContext OPTIONAL, 70 IN PCWSTR SourceFileName OPTIONAL, 71 OUT PCWSTR* pSourceRootPath, 72 OUT PCWSTR* pSourcePath, 73 OUT PCWSTR* pTargetDirectory, 74 OUT PCWSTR* pTargetFileName) 75 { 76 BOOL Success; 77 INFCONTEXT FileContext; 78 INFCONTEXT DirContext; 79 PCWSTR SourceRootDirId; 80 PCWSTR SourceRootDir; 81 PCWSTR SourceRelativePath; 82 PCWSTR TargetDirId; 83 PCWSTR TargetDir; 84 PCWSTR TargetFileName; 85 86 /* Either InfContext or SourceFileName must be specified */ 87 if (!InfContext && !SourceFileName) 88 return STATUS_INVALID_PARAMETER; 89 90 /* InfContext to a file was not given, retrieve one corresponding to SourceFileName */ 91 if (!InfContext) 92 { 93 /* Search for the SourceDisksFiles section */ 94 95 /* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */ 96 Success = SpInfFindFirstLine(InfHandle, L"SourceDisksFiles." INF_ARCH, SourceFileName, &FileContext); 97 if (!Success) 98 { 99 /* Search in the global section */ 100 Success = SpInfFindFirstLine(InfHandle, L"SourceDisksFiles", SourceFileName, &FileContext); 101 } 102 if (!Success) 103 { 104 // pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION; 105 // if (pSetupData->ErrorRoutine) 106 // pSetupData->ErrorRoutine(pSetupData, SectionName); 107 return STATUS_NOT_FOUND; 108 } 109 InfContext = &FileContext; 110 } 111 // else, InfContext != NULL and ignore SourceFileName (that may or may not be == NULL). 112 113 /* 114 * Getting Source File Location -- SetupGetSourceFileLocation() 115 */ 116 117 /* Get source root directory id */ 118 if (!INF_GetDataField(InfContext, 1, &SourceRootDirId)) 119 { 120 /* FIXME: Handle error! */ 121 DPRINT1("INF_GetData() failed\n"); 122 return STATUS_NOT_FOUND; 123 } 124 125 /* Lookup source root directory -- SetupGetSourceInfo() */ 126 /* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */ 127 Success = SpInfFindFirstLine(InfHandle, L"SourceDisksNames." INF_ARCH, SourceRootDirId, &DirContext); 128 if (!Success) 129 { 130 /* Search in the global section */ 131 Success = SpInfFindFirstLine(InfHandle, L"SourceDisksNames", SourceRootDirId, &DirContext); 132 if (!Success) 133 DPRINT1("SpInfFindFirstLine(\"SourceDisksNames\", \"%S\") failed\n", SourceRootDirId); 134 } 135 INF_FreeData(SourceRootDirId); 136 if (!Success) 137 { 138 /* FIXME: Handle error! */ 139 // pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION; 140 // if (pSetupData->ErrorRoutine) 141 // pSetupData->ErrorRoutine(pSetupData, SectionName); 142 return STATUS_NOT_FOUND; 143 } 144 if (!INF_GetDataField(&DirContext, 4, &SourceRootDir)) 145 { 146 /* FIXME: Handle error! */ 147 DPRINT1("INF_GetData() failed\n"); 148 return STATUS_NOT_FOUND; 149 } 150 151 /* Get optional source relative directory */ 152 if (!INF_GetDataField(InfContext, 2, &SourceRelativePath)) 153 { 154 SourceRelativePath = NULL; 155 } 156 else if (!*SourceRelativePath) 157 { 158 INF_FreeData(SourceRelativePath); 159 SourceRelativePath = NULL; 160 } 161 if (!SourceRelativePath) 162 { 163 /* Use WinPE directory instead */ 164 if (INF_GetDataField(InfContext, 13, &TargetDirId)) 165 { 166 /* Lookup directory */ 167 Success = LookupDirectoryById(InfHandle, &DirContext, TargetDirId, &SourceRelativePath); 168 INF_FreeData(TargetDirId); 169 if (!Success) 170 { 171 SourceRelativePath = NULL; 172 } 173 else if (!*SourceRelativePath) 174 { 175 INF_FreeData(SourceRelativePath); 176 SourceRelativePath = NULL; 177 } 178 } 179 } 180 181 /* 182 * Getting Target File Location -- SetupGetTargetPath() 183 */ 184 185 /* Get target directory id */ 186 if (!INF_GetDataField(InfContext, 8, &TargetDirId)) 187 { 188 /* FIXME: Handle error! */ 189 DPRINT1("INF_GetData() failed\n"); 190 INF_FreeData(SourceRelativePath); 191 INF_FreeData(SourceRootDir); 192 return STATUS_NOT_FOUND; 193 } 194 195 /* Lookup target directory */ 196 Success = LookupDirectoryById(InfHandle, &DirContext, TargetDirId, &TargetDir); 197 INF_FreeData(TargetDirId); 198 if (!Success) 199 { 200 /* FIXME: Handle error! */ 201 INF_FreeData(SourceRelativePath); 202 INF_FreeData(SourceRootDir); 203 return STATUS_NOT_FOUND; 204 } 205 206 /* Get optional target file name */ 207 if (!INF_GetDataField(InfContext, 11, &TargetFileName)) 208 TargetFileName = NULL; 209 else if (!*TargetFileName) 210 TargetFileName = NULL; 211 212 DPRINT("GetSourceFileAndTargetLocation(%S) = " 213 "SrcRootDir: '%S', SrcRelPath: '%S' --> TargetDir: '%S', TargetFileName: '%S'\n", 214 SourceFileName, SourceRootDir, SourceRelativePath, TargetDir, TargetFileName); 215 216 #if 0 217 INF_FreeData(TargetDir); 218 INF_FreeData(TargetFileName); 219 INF_FreeData(SourceRelativePath); 220 INF_FreeData(SourceRootDir); 221 #endif 222 223 *pSourceRootPath = SourceRootDir; 224 *pSourcePath = SourceRelativePath; 225 *pTargetDirectory = TargetDir; 226 *pTargetFileName = TargetFileName; 227 228 return STATUS_SUCCESS; 229 } 230 231 static NTSTATUS 232 BuildFullDirectoryPath( 233 IN PCWSTR RootPath, 234 IN PCWSTR BasePath, 235 IN PCWSTR RelativePath, 236 OUT PWSTR FullPath, 237 IN SIZE_T cchFullPathSize) 238 { 239 NTSTATUS Status; 240 241 if ((RelativePath[0] == UNICODE_NULL) || (RelativePath[0] == L'\\' && RelativePath[1] == UNICODE_NULL)) 242 { 243 /* Installation path */ 244 DPRINT("InstallationPath: '%S'\n", RelativePath); 245 246 Status = CombinePaths(FullPath, cchFullPathSize, 2, 247 RootPath, BasePath); 248 249 DPRINT("InstallationPath(2): '%S'\n", FullPath); 250 } 251 else if (RelativePath[0] == L'\\') 252 { 253 /* Absolute path */ 254 DPRINT("AbsolutePath: '%S'\n", RelativePath); 255 256 Status = CombinePaths(FullPath, cchFullPathSize, 2, 257 RootPath, RelativePath); 258 259 DPRINT("AbsolutePath(2): '%S'\n", FullPath); 260 } 261 else // if (RelativePath[0] != L'\\') 262 { 263 /* Path relative to the installation path */ 264 DPRINT("RelativePath: '%S'\n", RelativePath); 265 266 Status = CombinePaths(FullPath, cchFullPathSize, 3, 267 RootPath, BasePath, RelativePath); 268 269 DPRINT("RelativePath(2): '%S'\n", FullPath); 270 } 271 272 return Status; 273 } 274 275 276 /* 277 * This code enumerates the list of files in reactos.dff / reactos.inf 278 * that need to be extracted from reactos.cab and be installed in their 279 * respective directories. 280 */ 281 /* 282 * IMPORTANT NOTE: The INF file specification used for the .CAB in ReactOS 283 * is not compliant with respect to TXTSETUP.SIF syntax or the standard syntax. 284 */ 285 static BOOLEAN 286 AddSectionToCopyQueueCab( 287 IN PUSETUP_DATA pSetupData, 288 IN HINF InfFile, 289 IN PCWSTR SectionName, 290 IN PCWSTR SourceCabinet, 291 IN PCUNICODE_STRING DestinationPath) 292 { 293 BOOLEAN Success; 294 NTSTATUS Status; 295 INFCONTEXT FilesContext; 296 INFCONTEXT DirContext; 297 PCWSTR SourceFileName; 298 PCWSTR TargetDirId; 299 PCWSTR TargetDir; 300 PCWSTR TargetFileName; 301 WCHAR FileDstPath[MAX_PATH]; 302 303 /* Search for the SectionName section */ 304 if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext)) 305 { 306 DPRINT1("AddSectionToCopyQueueCab(): Unable to find section '%S' in cabinet file\n", SectionName); 307 return FALSE; 308 } 309 310 /* 311 * Enumerate the files in the section and add them to the file queue. 312 */ 313 do 314 { 315 /* Get source file name and target directory id */ 316 if (!INF_GetData(&FilesContext, &SourceFileName, &TargetDirId)) 317 { 318 /* FIXME: Handle error! */ 319 DPRINT1("INF_GetData() failed\n"); 320 break; 321 } 322 323 /* Get optional target file name */ 324 if (!INF_GetDataField(&FilesContext, 2, &TargetFileName)) 325 { 326 TargetFileName = NULL; 327 } 328 else if (!*TargetFileName) 329 { 330 INF_FreeData(TargetFileName); 331 TargetFileName = NULL; 332 } 333 334 /* Lookup target directory */ 335 Success = LookupDirectoryById(InfFile, &DirContext, TargetDirId, &TargetDir); 336 INF_FreeData(TargetDirId); 337 if (!Success) 338 { 339 /* FIXME: Handle error! */ 340 INF_FreeData(TargetFileName); 341 INF_FreeData(SourceFileName); 342 break; 343 } 344 345 DPRINT("GetSourceTargetFromCab(%S) = " 346 "SrcRootDir: '%S', SrcRelPath: '%S' --> TargetDir: '%S', TargetFileName: '%S'\n", 347 SourceFileName, 348 pSetupData->SourcePath.Buffer, 349 pSetupData->SourceRootDir.Buffer, 350 TargetDir, TargetFileName); 351 352 Status = CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2, 353 pSetupData->DestinationPath.Buffer, 354 TargetDir); 355 UNREFERENCED_PARAMETER(Status); 356 DPRINT(" --> FileDstPath = '%S'\n", FileDstPath); 357 358 INF_FreeData(TargetDir); 359 360 if (!SpFileQueueCopy((HSPFILEQ)pSetupData->SetupFileQueue, 361 pSetupData->SourcePath.Buffer, // SourcePath == SourceRootPath ++ SourceRootDir 362 NULL, 363 SourceFileName, 364 NULL, 365 SourceCabinet, 366 NULL, 367 FileDstPath, 368 TargetFileName, 369 0 /* FIXME */)) 370 { 371 /* FIXME: Handle error! */ 372 DPRINT1("SpFileQueueCopy() failed\n"); 373 } 374 375 INF_FreeData(TargetFileName); 376 INF_FreeData(SourceFileName); 377 378 } while (SpInfFindNextLine(&FilesContext, &FilesContext)); 379 380 return TRUE; 381 } 382 383 // Note: Modeled after the SetupQueueCopySection() API 384 /* 385 BOOL SetupQueueCopySection( 386 _In_ HSPFILEQ QueueHandle, 387 _In_ PCTSTR SourceRootPath, 388 _In_ HINF InfHandle, 389 _In_ HINF ListInfHandle, 390 _In_ PCTSTR Section, 391 _In_ DWORD CopyStyle 392 ); 393 */ 394 static BOOLEAN 395 AddSectionToCopyQueue( 396 IN PUSETUP_DATA pSetupData, 397 IN HINF InfFile, 398 IN PCWSTR SectionName, 399 IN PCUNICODE_STRING DestinationPath) 400 { 401 NTSTATUS Status; 402 INFCONTEXT FilesContext; 403 PCWSTR SourceFileName; 404 PCWSTR SourceRootPath; 405 PCWSTR SourcePath; 406 PCWSTR TargetDirectory; 407 PCWSTR TargetFileName; 408 WCHAR FileSrcRootPath[MAX_PATH]; 409 WCHAR FileDstPath[MAX_PATH]; 410 411 /* 412 * This code enumerates the list of files in txtsetup.sif 413 * that need to be installed in their respective directories. 414 */ 415 416 /* Search for the SectionName section */ 417 if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext)) 418 { 419 DPRINT1("AddSectionToCopyQueue(): Unable to find section '%S' in TXTSETUP.SIF\n", SectionName); 420 return FALSE; 421 } 422 423 /* 424 * Enumerate the files in the section and add them to the file queue. 425 */ 426 do 427 { 428 /* Get source file name */ 429 if (!INF_GetDataField(&FilesContext, 0, &SourceFileName)) 430 { 431 /* FIXME: Handle error! */ 432 DPRINT1("INF_GetData() failed\n"); 433 break; 434 } 435 436 Status = GetSourceFileAndTargetLocation(InfFile, 437 &FilesContext, 438 SourceFileName, 439 &SourceRootPath, // SourceRootDir 440 &SourcePath, 441 &TargetDirectory, 442 &TargetFileName); 443 if (!NT_SUCCESS(Status)) 444 { 445 DPRINT1("Could not find source and target location for file '%S'\n", SourceFileName); 446 INF_FreeData(SourceFileName); 447 448 // FIXME: Another error? 449 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION; 450 if (pSetupData->ErrorRoutine) 451 pSetupData->ErrorRoutine(pSetupData, SectionName); 452 return FALSE; 453 // break; 454 } 455 /* 456 * SourcePath: '\Device\CdRom0\I386' 457 * SourceRootPath: '\Device\CdRom0' 458 * SourceRootDir: '\I386' 459 */ 460 461 Status = CombinePaths(FileSrcRootPath, ARRAYSIZE(FileSrcRootPath), 2, 462 pSetupData->SourceRootPath.Buffer, 463 SourceRootPath); 464 UNREFERENCED_PARAMETER(Status); 465 // DPRINT1("Could not build the full path for '%S', skipping...\n", SourceRootPath); 466 DPRINT(" --> FileSrcRootPath = '%S'\n", FileSrcRootPath); 467 468 INF_FreeData(SourceRootPath); 469 470 Status = CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2, 471 pSetupData->DestinationPath.Buffer, 472 TargetDirectory); 473 UNREFERENCED_PARAMETER(Status); 474 // DPRINT1("Could not build the full path for '%S', skipping...\n", TargetDirectory); 475 DPRINT(" --> FileDstPath = '%S'\n", FileDstPath); 476 477 INF_FreeData(TargetDirectory); 478 479 if (!SpFileQueueCopy((HSPFILEQ)pSetupData->SetupFileQueue, 480 FileSrcRootPath, 481 SourcePath, 482 SourceFileName, 483 NULL, 484 NULL, // No SourceCabinet 485 NULL, 486 FileDstPath, 487 TargetFileName, 488 0 /* FIXME */)) 489 { 490 /* FIXME: Handle error! */ 491 DPRINT1("SpFileQueueCopy() failed\n"); 492 } 493 494 INF_FreeData(TargetFileName); 495 INF_FreeData(SourcePath); 496 INF_FreeData(SourceFileName); 497 498 } while (SpInfFindNextLine(&FilesContext, &FilesContext)); 499 500 return TRUE; 501 } 502 503 BOOLEAN // ERROR_NUMBER 504 PrepareCopyInfFile( 505 IN OUT PUSETUP_DATA pSetupData, 506 IN HINF InfFile, 507 IN PCWSTR SourceCabinet OPTIONAL) 508 { 509 BOOLEAN Success; 510 NTSTATUS Status; 511 INFCONTEXT DirContext; 512 PWCHAR AdditionalSectionName = NULL; 513 PCWSTR DirKeyValue; 514 WCHAR PathBuffer[MAX_PATH]; 515 516 if (SourceCabinet == NULL) 517 { 518 /* Add common files -- Search for the SourceDisksFiles section */ 519 /* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */ 520 Success = AddSectionToCopyQueue(pSetupData, InfFile, 521 L"SourceDisksFiles." INF_ARCH, 522 &pSetupData->DestinationPath); 523 if (!Success) 524 { 525 DPRINT1("AddSectionToCopyQueue(%S) failed!\n", L"SourceDisksFiles." INF_ARCH); 526 } 527 /* Search in the global section */ 528 Success = AddSectionToCopyQueue(pSetupData, InfFile, 529 L"SourceDisksFiles", 530 &pSetupData->DestinationPath); 531 if (!Success) 532 { 533 DPRINT1("AddSectionToCopyQueue(%S) failed!\n", L"SourceDisksFiles"); 534 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION; 535 if (pSetupData->ErrorRoutine) 536 pSetupData->ErrorRoutine(pSetupData, L"SourceDisksFiles"); 537 return FALSE; 538 } 539 540 /* Add specific files depending of computer type */ 541 if (!ProcessComputerFiles(InfFile, pSetupData->ComputerList, &AdditionalSectionName)) 542 return FALSE; 543 544 if (AdditionalSectionName && 545 !AddSectionToCopyQueue(pSetupData, InfFile, 546 AdditionalSectionName, 547 &pSetupData->DestinationPath)) 548 { 549 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION; 550 if (pSetupData->ErrorRoutine) 551 pSetupData->ErrorRoutine(pSetupData, AdditionalSectionName); 552 return FALSE; 553 } 554 } 555 else 556 { 557 /* Process a cabinet INF */ 558 Success = AddSectionToCopyQueueCab(pSetupData, InfFile, 559 L"SourceFiles", 560 SourceCabinet, 561 &pSetupData->DestinationPath); 562 if (!Success) 563 { 564 DPRINT1("AddSectionToCopyQueueCab(%S) failed!\n", SourceCabinet); 565 pSetupData->LastErrorNumber = ERROR_CABINET_SECTION; 566 if (pSetupData->ErrorRoutine) 567 pSetupData->ErrorRoutine(pSetupData, L"SourceFiles"); 568 return FALSE; 569 } 570 } 571 572 /* Create directories */ 573 574 /* 575 * NOTE: This is technically optional since SpFileQueueCommit() 576 * does that. This is however needed if one wants to create 577 * empty directories. 578 */ 579 580 /* 581 * FIXME: 582 * Copying files to pSetupData->DestinationRootPath should be done from within 583 * the SystemPartitionFiles section. 584 * At the moment we check whether we specify paths like '\foo' or '\\' for that. 585 * For installing to pSetupData->DestinationPath specify just '\' . 586 */ 587 588 /* Get destination path */ 589 RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), 590 pSetupData->DestinationPath.Buffer); 591 592 DPRINT("FullPath(1): '%S'\n", PathBuffer); 593 594 /* Create the install directory */ 595 Status = SetupCreateDirectory(PathBuffer); 596 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION) 597 { 598 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status); 599 pSetupData->LastErrorNumber = ERROR_CREATE_INSTALL_DIR; 600 if (pSetupData->ErrorRoutine) 601 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 602 return FALSE; 603 } 604 605 /* Search for the 'Directories' section */ 606 // ReactOS-specific 607 if (!SpInfFindFirstLine(InfFile, L"Directories", NULL, &DirContext)) 608 { 609 // Windows-compatible 610 if (!SpInfFindFirstLine(InfFile, L"WinntDirectories", NULL, &DirContext)) 611 { 612 if (SourceCabinet) 613 pSetupData->LastErrorNumber = ERROR_CABINET_SECTION; 614 else 615 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION; 616 617 if (pSetupData->ErrorRoutine) 618 pSetupData->ErrorRoutine(pSetupData, L"Directories"); 619 return FALSE; 620 } 621 } 622 623 /* Enumerate the directory values and create the subdirectories */ 624 do 625 { 626 if (!INF_GetData(&DirContext, NULL, &DirKeyValue)) 627 { 628 DPRINT1("break\n"); 629 break; 630 } 631 632 Status = BuildFullDirectoryPath(pSetupData->DestinationRootPath.Buffer, 633 pSetupData->InstallPath.Buffer, 634 DirKeyValue, 635 PathBuffer, 636 ARRAYSIZE(PathBuffer)); 637 if (!NT_SUCCESS(Status)) 638 { 639 DPRINT1("Could not build the full path for '%S', skipping...\n", DirKeyValue); 640 INF_FreeData(DirKeyValue); 641 continue; 642 } 643 644 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL)) 645 { 646 /* 647 * Installation path -- No need to create it 648 * because it has been already created above. 649 */ 650 } 651 else 652 { 653 /* Arbitrary path -- Create it */ 654 Status = SetupCreateDirectory(PathBuffer); 655 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION) 656 { 657 INF_FreeData(DirKeyValue); 658 DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status); 659 pSetupData->LastErrorNumber = ERROR_CREATE_DIR; 660 if (pSetupData->ErrorRoutine) 661 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 662 return FALSE; 663 } 664 } 665 666 INF_FreeData(DirKeyValue); 667 } while (SpInfFindNextLine(&DirContext, &DirContext)); 668 669 return TRUE; 670 } 671 672 673 // #define USE_CABINET_INF 674 675 BOOLEAN // ERROR_NUMBER 676 PrepareFileCopy( 677 IN OUT PUSETUP_DATA pSetupData, 678 IN PFILE_COPY_STATUS_ROUTINE StatusRoutine OPTIONAL) 679 { 680 HINF InfHandle; 681 INFCONTEXT CabinetsContext; 682 PCWSTR CabinetName; 683 UINT ErrorLine; 684 #if defined(__REACTOS__) && defined(USE_CABINET_INF) 685 ULONG InfFileSize; 686 PVOID InfFileData; 687 CABINET_CONTEXT CabinetContext; 688 #endif 689 WCHAR PathBuffer[MAX_PATH]; 690 691 /* Create the file queue */ 692 pSetupData->SetupFileQueue = (PVOID)SpFileQueueOpen(); 693 if (pSetupData->SetupFileQueue == NULL) 694 { 695 pSetupData->LastErrorNumber = ERROR_COPY_QUEUE; 696 if (pSetupData->ErrorRoutine) 697 pSetupData->ErrorRoutine(pSetupData); 698 return FALSE; 699 } 700 701 /* Prepare the copy of the common files that are not in installation cabinets */ 702 if (!PrepareCopyInfFile(pSetupData, pSetupData->SetupInf, NULL)) 703 { 704 /* FIXME: show an error dialog */ 705 return FALSE; 706 } 707 708 /* Search for the 'Cabinets' section */ 709 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"Cabinets", NULL, &CabinetsContext)) 710 { 711 /* Skip this step and return success if no cabinet file is listed */ 712 return TRUE; 713 } 714 715 /* 716 * Enumerate the installation cabinets listed in the 717 * 'Cabinets' section and parse their inf files. 718 */ 719 do 720 { 721 if (!INF_GetData(&CabinetsContext, NULL, &CabinetName)) 722 break; 723 724 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2, 725 pSetupData->SourcePath.Buffer, CabinetName); 726 727 #if defined(__REACTOS__) && defined(USE_CABINET_INF) 728 INF_FreeData(CabinetName); 729 730 CabinetInitialize(&CabinetContext); 731 CabinetSetEventHandlers(&CabinetContext, NULL, NULL, NULL); 732 CabinetSetCabinetName(&CabinetContext, PathBuffer); 733 734 if (CabinetOpen(&CabinetContext) == CAB_STATUS_SUCCESS) 735 { 736 DPRINT("Cabinet %S\n", PathBuffer); 737 738 InfFileData = CabinetGetCabinetReservedArea(&CabinetContext, &InfFileSize); 739 if (InfFileData == NULL) 740 { 741 CabinetCleanup(&CabinetContext); 742 743 pSetupData->LastErrorNumber = ERROR_CABINET_SCRIPT; 744 if (pSetupData->ErrorRoutine) 745 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 746 return FALSE; 747 } 748 } 749 else 750 { 751 DPRINT("Cannot open cabinet: %S.\n", PathBuffer); 752 CabinetCleanup(&CabinetContext); 753 754 pSetupData->LastErrorNumber = ERROR_CABINET_MISSING; 755 if (pSetupData->ErrorRoutine) 756 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 757 return FALSE; 758 } 759 760 InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData, 761 InfFileSize, 762 NULL, 763 INF_STYLE_WIN4, 764 pSetupData->LanguageId, 765 &ErrorLine); 766 767 CabinetCleanup(&CabinetContext); 768 #else 769 { 770 PWCHAR ptr; 771 772 /* First find the filename */ 773 ptr = wcsrchr(PathBuffer, L'\\'); 774 if (!ptr) ptr = PathBuffer; 775 776 /* Then find its extension */ 777 ptr = wcsrchr(ptr, L'.'); 778 if (!ptr) 779 ptr = PathBuffer + wcslen(PathBuffer); 780 781 /* Replace it by '.inf' */ 782 wcscpy(ptr, L".inf"); 783 784 InfHandle = SpInfOpenInfFile(PathBuffer, 785 NULL, 786 INF_STYLE_WIN4, 787 pSetupData->LanguageId, 788 &ErrorLine); 789 } 790 #endif 791 792 if (InfHandle == INVALID_HANDLE_VALUE) 793 { 794 pSetupData->LastErrorNumber = ERROR_INVALID_CABINET_INF; 795 if (pSetupData->ErrorRoutine) 796 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 797 return FALSE; 798 } 799 800 if (!PrepareCopyInfFile(pSetupData, InfHandle, CabinetName)) 801 { 802 #if !(defined(__REACTOS__) && defined(USE_CABINET_INF)) 803 SpInfCloseInfFile(InfHandle); 804 #endif 805 /* FIXME: show an error dialog */ 806 return FALSE; 807 } 808 809 #if !(defined(__REACTOS__) && defined(USE_CABINET_INF)) 810 SpInfCloseInfFile(InfHandle); 811 #endif 812 } while (SpInfFindNextLine(&CabinetsContext, &CabinetsContext)); 813 814 return TRUE; 815 } 816 817 BOOLEAN 818 DoFileCopy( 819 IN OUT PUSETUP_DATA pSetupData, 820 IN PSP_FILE_CALLBACK_W MsgHandler, 821 IN PVOID Context OPTIONAL) 822 { 823 BOOLEAN Success; 824 825 Success = SpFileQueueCommit(NULL, 826 (HSPFILEQ)pSetupData->SetupFileQueue, 827 MsgHandler, 828 Context); 829 830 SpFileQueueClose((HSPFILEQ)pSetupData->SetupFileQueue); 831 pSetupData->SetupFileQueue = NULL; 832 833 return Success; 834 } 835 836 /* EOF */ 837