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" // HACK 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 { 542 PGENERIC_LIST_ENTRY Entry; 543 Entry = GetCurrentListEntry(pSetupData->ComputerList); 544 ASSERT(Entry); 545 pSetupData->ComputerType = ((PGENENTRY)GetListEntryData(Entry))->Id; 546 ASSERT(pSetupData->ComputerType); 547 548 if (!ProcessComputerFiles(InfFile, pSetupData->ComputerType, &AdditionalSectionName)) 549 return FALSE; 550 } 551 552 if (AdditionalSectionName && 553 !AddSectionToCopyQueue(pSetupData, InfFile, 554 AdditionalSectionName, 555 &pSetupData->DestinationPath)) 556 { 557 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION; 558 if (pSetupData->ErrorRoutine) 559 pSetupData->ErrorRoutine(pSetupData, AdditionalSectionName); 560 return FALSE; 561 } 562 } 563 else 564 { 565 /* Process a cabinet INF */ 566 Success = AddSectionToCopyQueueCab(pSetupData, InfFile, 567 L"SourceFiles", 568 SourceCabinet, 569 &pSetupData->DestinationPath); 570 if (!Success) 571 { 572 DPRINT1("AddSectionToCopyQueueCab(%S) failed!\n", SourceCabinet); 573 pSetupData->LastErrorNumber = ERROR_CABINET_SECTION; 574 if (pSetupData->ErrorRoutine) 575 pSetupData->ErrorRoutine(pSetupData, L"SourceFiles"); 576 return FALSE; 577 } 578 } 579 580 /* Create directories */ 581 582 /* 583 * NOTE: This is technically optional since SpFileQueueCommit() 584 * does that. This is however needed if one wants to create 585 * empty directories. 586 */ 587 588 /* 589 * FIXME: 590 * Copying files to pSetupData->DestinationRootPath should be done from within 591 * the SystemPartitionFiles section. 592 * At the moment we check whether we specify paths like '\foo' or '\\' for that. 593 * For installing to pSetupData->DestinationPath specify just '\' . 594 */ 595 596 /* Get destination path */ 597 RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), 598 pSetupData->DestinationPath.Buffer); 599 600 DPRINT("FullPath(1): '%S'\n", PathBuffer); 601 602 /* Create the install directory */ 603 Status = SetupCreateDirectory(PathBuffer); 604 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION) 605 { 606 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status); 607 pSetupData->LastErrorNumber = ERROR_CREATE_INSTALL_DIR; 608 if (pSetupData->ErrorRoutine) 609 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 610 return FALSE; 611 } 612 613 /* Search for the 'Directories' section */ 614 // ReactOS-specific 615 if (!SpInfFindFirstLine(InfFile, L"Directories", NULL, &DirContext)) 616 { 617 // Windows-compatible 618 if (!SpInfFindFirstLine(InfFile, L"WinntDirectories", NULL, &DirContext)) 619 { 620 if (SourceCabinet) 621 pSetupData->LastErrorNumber = ERROR_CABINET_SECTION; 622 else 623 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION; 624 625 if (pSetupData->ErrorRoutine) 626 pSetupData->ErrorRoutine(pSetupData, L"Directories"); 627 return FALSE; 628 } 629 } 630 631 /* Enumerate the directory values and create the subdirectories */ 632 do 633 { 634 if (!INF_GetData(&DirContext, NULL, &DirKeyValue)) 635 { 636 DPRINT1("break\n"); 637 break; 638 } 639 640 Status = BuildFullDirectoryPath(pSetupData->DestinationRootPath.Buffer, 641 pSetupData->InstallPath.Buffer, 642 DirKeyValue, 643 PathBuffer, 644 ARRAYSIZE(PathBuffer)); 645 if (!NT_SUCCESS(Status)) 646 { 647 DPRINT1("Could not build the full path for '%S', skipping...\n", DirKeyValue); 648 INF_FreeData(DirKeyValue); 649 continue; 650 } 651 652 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL)) 653 { 654 /* 655 * Installation path -- No need to create it 656 * because it has been already created above. 657 */ 658 } 659 else 660 { 661 /* Arbitrary path -- Create it */ 662 Status = SetupCreateDirectory(PathBuffer); 663 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION) 664 { 665 INF_FreeData(DirKeyValue); 666 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status); 667 pSetupData->LastErrorNumber = ERROR_CREATE_DIR; 668 if (pSetupData->ErrorRoutine) 669 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 670 return FALSE; 671 } 672 } 673 674 INF_FreeData(DirKeyValue); 675 } while (SpInfFindNextLine(&DirContext, &DirContext)); 676 677 return TRUE; 678 } 679 680 681 // #define USE_CABINET_INF 682 683 BOOLEAN // ERROR_NUMBER 684 NTAPI 685 PrepareFileCopy( 686 IN OUT PUSETUP_DATA pSetupData, 687 IN PFILE_COPY_STATUS_ROUTINE StatusRoutine OPTIONAL) 688 { 689 HINF InfHandle; 690 INFCONTEXT CabinetsContext; 691 PCWSTR CabinetName; 692 UINT ErrorLine; 693 #if defined(__REACTOS__) && defined(USE_CABINET_INF) 694 ULONG InfFileSize; 695 PVOID InfFileData; 696 CABINET_CONTEXT CabinetContext; 697 #endif 698 WCHAR PathBuffer[MAX_PATH]; 699 700 /* Create the file queue */ 701 pSetupData->SetupFileQueue = (PVOID)SpFileQueueOpen(); 702 if (pSetupData->SetupFileQueue == NULL) 703 { 704 pSetupData->LastErrorNumber = ERROR_COPY_QUEUE; 705 if (pSetupData->ErrorRoutine) 706 pSetupData->ErrorRoutine(pSetupData); 707 return FALSE; 708 } 709 710 /* Prepare the copy of the common files that are not in installation cabinets */ 711 if (!PrepareCopyInfFile(pSetupData, pSetupData->SetupInf, NULL)) 712 { 713 /* FIXME: show an error dialog */ 714 return FALSE; 715 } 716 717 /* Search for the 'Cabinets' section */ 718 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"Cabinets", NULL, &CabinetsContext)) 719 { 720 /* Skip this step and return success if no cabinet file is listed */ 721 return TRUE; 722 } 723 724 /* 725 * Enumerate the installation cabinets listed in the 726 * 'Cabinets' section and parse their inf files. 727 */ 728 do 729 { 730 if (!INF_GetData(&CabinetsContext, NULL, &CabinetName)) 731 break; 732 733 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2, 734 pSetupData->SourcePath.Buffer, CabinetName); 735 736 #if defined(__REACTOS__) && defined(USE_CABINET_INF) 737 INF_FreeData(CabinetName); 738 739 CabinetInitialize(&CabinetContext); 740 CabinetSetEventHandlers(&CabinetContext, NULL, NULL, NULL); 741 CabinetSetCabinetName(&CabinetContext, PathBuffer); 742 743 if (CabinetOpen(&CabinetContext) == CAB_STATUS_SUCCESS) 744 { 745 DPRINT("Cabinet %S\n", PathBuffer); 746 747 InfFileData = CabinetGetCabinetReservedArea(&CabinetContext, &InfFileSize); 748 if (InfFileData == NULL) 749 { 750 CabinetCleanup(&CabinetContext); 751 752 pSetupData->LastErrorNumber = ERROR_CABINET_SCRIPT; 753 if (pSetupData->ErrorRoutine) 754 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 755 return FALSE; 756 } 757 } 758 else 759 { 760 DPRINT("Cannot open cabinet: %S.\n", PathBuffer); 761 CabinetCleanup(&CabinetContext); 762 763 pSetupData->LastErrorNumber = ERROR_CABINET_MISSING; 764 if (pSetupData->ErrorRoutine) 765 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 766 return FALSE; 767 } 768 769 InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData, 770 InfFileSize, 771 NULL, 772 INF_STYLE_WIN4, 773 pSetupData->LanguageId, 774 &ErrorLine); 775 776 CabinetCleanup(&CabinetContext); 777 #else 778 { 779 PWCHAR ptr; 780 781 /* First find the filename */ 782 ptr = wcsrchr(PathBuffer, L'\\'); 783 if (!ptr) ptr = PathBuffer; 784 785 /* Then find its extension */ 786 ptr = wcsrchr(ptr, L'.'); 787 if (!ptr) 788 ptr = PathBuffer + wcslen(PathBuffer); 789 790 /* Replace it by '.inf' */ 791 wcscpy(ptr, L".inf"); 792 793 InfHandle = SpInfOpenInfFile(PathBuffer, 794 NULL, 795 INF_STYLE_WIN4, 796 pSetupData->LanguageId, 797 &ErrorLine); 798 } 799 #endif 800 801 if (InfHandle == INVALID_HANDLE_VALUE) 802 { 803 pSetupData->LastErrorNumber = ERROR_INVALID_CABINET_INF; 804 if (pSetupData->ErrorRoutine) 805 pSetupData->ErrorRoutine(pSetupData, PathBuffer); 806 return FALSE; 807 } 808 809 if (!PrepareCopyInfFile(pSetupData, InfHandle, CabinetName)) 810 { 811 #if !(defined(__REACTOS__) && defined(USE_CABINET_INF)) 812 SpInfCloseInfFile(InfHandle); 813 #endif 814 /* FIXME: show an error dialog */ 815 return FALSE; 816 } 817 818 #if !(defined(__REACTOS__) && defined(USE_CABINET_INF)) 819 SpInfCloseInfFile(InfHandle); 820 #endif 821 } while (SpInfFindNextLine(&CabinetsContext, &CabinetsContext)); 822 823 return TRUE; 824 } 825 826 BOOLEAN 827 NTAPI 828 DoFileCopy( 829 IN OUT PUSETUP_DATA pSetupData, 830 IN PSP_FILE_CALLBACK_W MsgHandler, 831 IN PVOID Context OPTIONAL) 832 { 833 BOOLEAN Success; 834 835 Success = SpFileQueueCommit(NULL, 836 (HSPFILEQ)pSetupData->SetupFileQueue, 837 MsgHandler, 838 Context); 839 840 SpFileQueueClose((HSPFILEQ)pSetupData->SetupFileQueue); 841 pSetupData->SetupFileQueue = NULL; 842 843 return Success; 844 } 845 846 /* EOF */ 847