1 /* 2 * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "Package.h" 8 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 15 #include <package/hpkg/ErrorOutput.h> 16 #include <package/hpkg/PackageDataReader.h> 17 #include <package/hpkg/PackageEntry.h> 18 #include <package/hpkg/PackageEntryAttribute.h> 19 #include <package/hpkg/v1/PackageEntry.h> 20 #include <package/hpkg/v1/PackageEntryAttribute.h> 21 22 #include <AutoDeleter.h> 23 #include <FdIO.h> 24 #include <package/hpkg/PackageFileHeapReader.h> 25 #include <package/hpkg/PackageReaderImpl.h> 26 #include <package/hpkg/v1/PackageReaderImpl.h> 27 #include <util/AutoLock.h> 28 29 #include "CachedDataReader.h" 30 #include "DebugSupport.h" 31 #include "GlobalFactory.h" 32 #include "PackageDirectory.h" 33 #include "PackageFile.h" 34 #include "PackagesDirectory.h" 35 #include "PackageSettings.h" 36 #include "PackageSymlink.h" 37 #include "Version.h" 38 #include "Volume.h" 39 40 41 using namespace BPackageKit; 42 43 using BPackageKit::BHPKG::BErrorOutput; 44 using BPackageKit::BHPKG::BFDDataReader; 45 using BPackageKit::BHPKG::BPackageInfoAttributeValue; 46 using BPackageKit::BHPKG::BPackageVersionData; 47 using BPackageKit::BHPKG::BPrivate::PackageFileHeapReader; 48 49 // current format version types 50 typedef BPackageKit::BHPKG::BPackageContentHandler BPackageContentHandler; 51 typedef BPackageKit::BHPKG::BPackageEntry BPackageEntry; 52 typedef BPackageKit::BHPKG::BPackageEntryAttribute BPackageEntryAttribute; 53 typedef BPackageKit::BHPKG::BPrivate::PackageReaderImpl PackageReaderImpl; 54 55 // format version V1 types 56 typedef BPackageKit::BHPKG::V1::BPackageContentHandler BPackageContentHandlerV1; 57 typedef BPackageKit::BHPKG::V1::BPackageEntry BPackageEntryV1; 58 typedef BPackageKit::BHPKG::V1::BPackageEntryAttribute BPackageEntryAttributeV1; 59 typedef BPackageKit::BHPKG::V1::BPrivate::PackageReaderImpl PackageReaderImplV1; 60 61 62 const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = { 63 "any", 64 "x86", 65 "x86_gcc2", 66 "source", 67 "x86_64", 68 "ppc", 69 "arm", 70 "m68k" 71 }; 72 73 74 // #pragma mark - LoaderErrorOutput 75 76 77 struct Package::LoaderErrorOutput : BErrorOutput { 78 LoaderErrorOutput(Package* package) 79 : 80 fPackage(package) 81 { 82 } 83 84 virtual void PrintErrorVarArgs(const char* format, va_list args) 85 { 86 ERRORV(format, args); 87 } 88 89 private: 90 Package* fPackage; 91 }; 92 93 94 // #pragma mark - LoaderContentHandler 95 96 97 struct Package::LoaderContentHandler : BPackageContentHandler { 98 LoaderContentHandler(Package* package, const PackageSettings& settings) 99 : 100 fPackage(package), 101 fSettings(settings), 102 fSettingsItem(NULL), 103 fLastSettingsEntry(NULL), 104 fLastSettingsEntryEntry(NULL), 105 fErrorOccurred(false) 106 { 107 } 108 109 status_t Init() 110 { 111 return B_OK; 112 } 113 114 virtual status_t HandleEntry(BPackageEntry* entry) 115 { 116 if (fErrorOccurred 117 || (fLastSettingsEntry != NULL 118 && fLastSettingsEntry->IsBlackListed())) { 119 return B_OK; 120 } 121 122 PackageDirectory* parentDir = NULL; 123 if (entry->Parent() != NULL) { 124 parentDir = dynamic_cast<PackageDirectory*>( 125 (PackageNode*)entry->Parent()->UserToken()); 126 if (parentDir == NULL) 127 RETURN_ERROR(B_BAD_DATA); 128 } 129 130 if (fSettingsItem != NULL 131 && (parentDir == NULL 132 || entry->Parent() == fLastSettingsEntryEntry)) { 133 PackageSettingsItem::Entry* settingsEntry 134 = fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name()); 135 if (settingsEntry != NULL) { 136 fLastSettingsEntry = settingsEntry; 137 fLastSettingsEntryEntry = entry; 138 if (fLastSettingsEntry->IsBlackListed()) 139 return B_OK; 140 } 141 } 142 143 // get the file mode -- filter out write permissions 144 mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); 145 146 // create the package node 147 PackageNode* node; 148 if (S_ISREG(mode)) { 149 // file 150 node = new(std::nothrow) PackageFile(fPackage, mode, 151 PackageData(entry->Data())); 152 } else if (S_ISLNK(mode)) { 153 // symlink 154 String path; 155 if (!path.SetTo(entry->SymlinkPath())) 156 RETURN_ERROR(B_NO_MEMORY); 157 158 PackageSymlink* symlink = new(std::nothrow) PackageSymlink( 159 fPackage, mode); 160 if (symlink == NULL) 161 RETURN_ERROR(B_NO_MEMORY); 162 163 symlink->SetSymlinkPath(path); 164 node = symlink; 165 } else if (S_ISDIR(mode)) { 166 // directory 167 node = new(std::nothrow) PackageDirectory(fPackage, mode); 168 } else 169 RETURN_ERROR(B_BAD_DATA); 170 171 if (node == NULL) 172 RETURN_ERROR(B_NO_MEMORY); 173 BReference<PackageNode> nodeReference(node, true); 174 175 String entryName; 176 if (!entryName.SetTo(entry->Name())) 177 RETURN_ERROR(B_NO_MEMORY); 178 179 status_t error = node->Init(parentDir, entryName); 180 if (error != B_OK) 181 RETURN_ERROR(error); 182 183 node->SetModifiedTime(entry->ModifiedTime()); 184 185 // add it to the parent directory 186 if (parentDir != NULL) 187 parentDir->AddChild(node); 188 else 189 fPackage->AddNode(node); 190 191 entry->SetUserToken(node); 192 193 return B_OK; 194 } 195 196 virtual status_t HandleEntryAttribute(BPackageEntry* entry, 197 BPackageEntryAttribute* attribute) 198 { 199 if (fErrorOccurred 200 || (fLastSettingsEntry != NULL 201 && fLastSettingsEntry->IsBlackListed())) { 202 return B_OK; 203 } 204 205 PackageNode* node = (PackageNode*)entry->UserToken(); 206 207 String name; 208 if (!name.SetTo(attribute->Name())) 209 RETURN_ERROR(B_NO_MEMORY); 210 211 PackageNodeAttribute* nodeAttribute = new(std::nothrow) 212 PackageNodeAttribute(attribute->Type(), 213 PackageData(attribute->Data())); 214 if (nodeAttribute == NULL) 215 RETURN_ERROR(B_NO_MEMORY) 216 217 nodeAttribute->Init(name); 218 node->AddAttribute(nodeAttribute); 219 220 return B_OK; 221 } 222 223 virtual status_t HandleEntryDone(BPackageEntry* entry) 224 { 225 if (entry == fLastSettingsEntryEntry) { 226 fLastSettingsEntryEntry = entry->Parent(); 227 fLastSettingsEntry = fLastSettingsEntry->Parent(); 228 } 229 230 return B_OK; 231 } 232 233 virtual status_t HandlePackageAttribute( 234 const BPackageInfoAttributeValue& value) 235 { 236 switch (value.attributeID) { 237 case B_PACKAGE_INFO_NAME: 238 { 239 String name; 240 if (!name.SetTo(value.string)) 241 return B_NO_MEMORY; 242 fPackage->SetName(name); 243 244 fSettingsItem = fSettings.PackageItemFor(fPackage->Name()); 245 246 return B_OK; 247 } 248 249 case B_PACKAGE_INFO_INSTALL_PATH: 250 { 251 String path; 252 if (!path.SetTo(value.string)) 253 return B_NO_MEMORY; 254 fPackage->SetInstallPath(path); 255 return B_OK; 256 } 257 258 case B_PACKAGE_INFO_VERSION: 259 { 260 ::Version* version; 261 status_t error = Version::Create(value.version.major, 262 value.version.minor, value.version.micro, 263 value.version.preRelease, value.version.revision, version); 264 if (error != B_OK) 265 RETURN_ERROR(error); 266 267 fPackage->SetVersion(version); 268 break; 269 } 270 271 case B_PACKAGE_INFO_FLAGS: 272 fPackage->SetFlags(value.unsignedInt); 273 break; 274 275 case B_PACKAGE_INFO_ARCHITECTURE: 276 if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) 277 RETURN_ERROR(B_BAD_VALUE); 278 279 fPackage->SetArchitecture( 280 (BPackageArchitecture)value.unsignedInt); 281 break; 282 283 case B_PACKAGE_INFO_PROVIDES: 284 { 285 // create a version object, if a version is specified 286 ::Version* version = NULL; 287 if (value.resolvable.haveVersion) { 288 const BPackageVersionData& versionInfo 289 = value.resolvable.version; 290 status_t error = Version::Create(versionInfo.major, 291 versionInfo.minor, versionInfo.micro, 292 versionInfo.preRelease, versionInfo.revision, version); 293 if (error != B_OK) 294 RETURN_ERROR(error); 295 } 296 ObjectDeleter< ::Version> versionDeleter(version); 297 298 // create a version object, if a compatible version is specified 299 ::Version* compatibleVersion = NULL; 300 if (value.resolvable.haveCompatibleVersion) { 301 const BPackageVersionData& versionInfo 302 = value.resolvable.compatibleVersion; 303 status_t error = Version::Create(versionInfo.major, 304 versionInfo.minor, versionInfo.micro, 305 versionInfo.preRelease, versionInfo.revision, 306 compatibleVersion); 307 if (error != B_OK) 308 RETURN_ERROR(error); 309 } 310 ObjectDeleter< ::Version> compatibleVersionDeleter( 311 compatibleVersion); 312 313 // create the resolvable 314 Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage); 315 if (resolvable == NULL) 316 RETURN_ERROR(B_NO_MEMORY); 317 ObjectDeleter<Resolvable> resolvableDeleter(resolvable); 318 319 status_t error = resolvable->Init(value.resolvable.name, 320 versionDeleter.Detach(), compatibleVersionDeleter.Detach()); 321 if (error != B_OK) 322 RETURN_ERROR(error); 323 324 fPackage->AddResolvable(resolvableDeleter.Detach()); 325 326 break; 327 } 328 329 case B_PACKAGE_INFO_REQUIRES: 330 { 331 // create the dependency 332 Dependency* dependency = new(std::nothrow) Dependency(fPackage); 333 if (dependency == NULL) 334 RETURN_ERROR(B_NO_MEMORY); 335 ObjectDeleter<Dependency> dependencyDeleter(dependency); 336 337 status_t error = dependency->Init( 338 value.resolvableExpression.name); 339 if (error != B_OK) 340 RETURN_ERROR(error); 341 342 // create a version object, if a version is specified 343 ::Version* version = NULL; 344 if (value.resolvableExpression.haveOpAndVersion) { 345 const BPackageVersionData& versionInfo 346 = value.resolvableExpression.version; 347 status_t error = Version::Create(versionInfo.major, 348 versionInfo.minor, versionInfo.micro, 349 versionInfo.preRelease, versionInfo.revision, version); 350 if (error != B_OK) 351 RETURN_ERROR(error); 352 353 dependency->SetVersionRequirement( 354 value.resolvableExpression.op, version); 355 } 356 357 fPackage->AddDependency(dependencyDeleter.Detach()); 358 359 break; 360 } 361 362 default: 363 break; 364 } 365 366 return B_OK; 367 } 368 369 virtual void HandleErrorOccurred() 370 { 371 fErrorOccurred = true; 372 } 373 374 private: 375 Package* fPackage; 376 const PackageSettings& fSettings; 377 const PackageSettingsItem* fSettingsItem; 378 PackageSettingsItem::Entry* fLastSettingsEntry; 379 const BPackageEntry* fLastSettingsEntryEntry; 380 bool fErrorOccurred; 381 }; 382 383 384 // #pragma mark - LoaderContentHandlerV1 385 386 387 struct Package::LoaderContentHandlerV1 : BPackageContentHandlerV1 { 388 LoaderContentHandlerV1(Package* package) 389 : 390 fPackage(package), 391 fErrorOccurred(false) 392 { 393 } 394 395 status_t Init() 396 { 397 return B_OK; 398 } 399 400 virtual status_t HandleEntry(BPackageEntryV1* entry) 401 { 402 if (fErrorOccurred) 403 return B_OK; 404 405 PackageDirectory* parentDir = NULL; 406 if (entry->Parent() != NULL) { 407 parentDir = dynamic_cast<PackageDirectory*>( 408 (PackageNode*)entry->Parent()->UserToken()); 409 if (parentDir == NULL) 410 RETURN_ERROR(B_BAD_DATA); 411 } 412 413 // get the file mode -- filter out write permissions 414 mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); 415 416 // create the package node 417 PackageNode* node; 418 if (S_ISREG(mode)) { 419 // file 420 node = new(std::nothrow) PackageFile(fPackage, mode, 421 PackageData(entry->Data())); 422 } else if (S_ISLNK(mode)) { 423 // symlink 424 String path; 425 if (!path.SetTo(entry->SymlinkPath())) 426 RETURN_ERROR(B_NO_MEMORY); 427 428 PackageSymlink* symlink = new(std::nothrow) PackageSymlink( 429 fPackage, mode); 430 if (symlink == NULL) 431 RETURN_ERROR(B_NO_MEMORY); 432 433 symlink->SetSymlinkPath(path); 434 node = symlink; 435 } else if (S_ISDIR(mode)) { 436 // directory 437 node = new(std::nothrow) PackageDirectory(fPackage, mode); 438 } else 439 RETURN_ERROR(B_BAD_DATA); 440 441 if (node == NULL) 442 RETURN_ERROR(B_NO_MEMORY); 443 BReference<PackageNode> nodeReference(node, true); 444 445 String entryName; 446 if (!entryName.SetTo(entry->Name())) 447 RETURN_ERROR(B_NO_MEMORY); 448 449 status_t error = node->Init(parentDir, entryName); 450 if (error != B_OK) 451 RETURN_ERROR(error); 452 453 node->SetModifiedTime(entry->ModifiedTime()); 454 455 // add it to the parent directory 456 if (parentDir != NULL) 457 parentDir->AddChild(node); 458 else 459 fPackage->AddNode(node); 460 461 entry->SetUserToken(node); 462 463 return B_OK; 464 } 465 466 virtual status_t HandleEntryAttribute(BPackageEntryV1* entry, 467 BPackageEntryAttributeV1* attribute) 468 { 469 if (fErrorOccurred) 470 return B_OK; 471 472 PackageNode* node = (PackageNode*)entry->UserToken(); 473 474 String name; 475 if (!name.SetTo(attribute->Name())) 476 RETURN_ERROR(B_NO_MEMORY); 477 478 PackageNodeAttribute* nodeAttribute = new(std::nothrow) 479 PackageNodeAttribute(attribute->Type(), 480 PackageData(attribute->Data())); 481 if (nodeAttribute == NULL) 482 RETURN_ERROR(B_NO_MEMORY) 483 484 nodeAttribute->Init(name); 485 node->AddAttribute(nodeAttribute); 486 487 return B_OK; 488 } 489 490 virtual status_t HandleEntryDone(BPackageEntryV1* entry) 491 { 492 return B_OK; 493 } 494 495 virtual status_t HandlePackageAttribute( 496 const BPackageInfoAttributeValue& value) 497 { 498 switch (value.attributeID) { 499 case B_PACKAGE_INFO_NAME: 500 { 501 String name; 502 if (!name.SetTo(value.string)) 503 return B_NO_MEMORY; 504 fPackage->SetName(name); 505 return B_OK; 506 } 507 508 case B_PACKAGE_INFO_INSTALL_PATH: 509 { 510 String path; 511 if (!path.SetTo(value.string)) 512 return B_NO_MEMORY; 513 fPackage->SetInstallPath(path); 514 return B_OK; 515 } 516 517 case B_PACKAGE_INFO_VERSION: 518 { 519 ::Version* version; 520 status_t error = Version::Create(value.version.major, 521 value.version.minor, value.version.micro, 522 value.version.preRelease, value.version.revision, version); 523 if (error != B_OK) 524 RETURN_ERROR(error); 525 526 fPackage->SetVersion(version); 527 528 break; 529 } 530 531 case B_PACKAGE_INFO_ARCHITECTURE: 532 if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) 533 RETURN_ERROR(B_BAD_VALUE); 534 535 fPackage->SetArchitecture( 536 (BPackageArchitecture)value.unsignedInt); 537 break; 538 539 case B_PACKAGE_INFO_PROVIDES: 540 { 541 // create a version object, if a version is specified 542 ::Version* version = NULL; 543 if (value.resolvable.haveVersion) { 544 const BPackageVersionData& versionInfo 545 = value.resolvable.version; 546 status_t error = Version::Create(versionInfo.major, 547 versionInfo.minor, versionInfo.micro, 548 versionInfo.preRelease, versionInfo.revision, version); 549 if (error != B_OK) 550 RETURN_ERROR(error); 551 } 552 ObjectDeleter< ::Version> versionDeleter(version); 553 554 // create a version object, if a compatible version is specified 555 ::Version* compatibleVersion = NULL; 556 if (value.resolvable.haveCompatibleVersion) { 557 const BPackageVersionData& versionInfo 558 = value.resolvable.compatibleVersion; 559 status_t error = Version::Create(versionInfo.major, 560 versionInfo.minor, versionInfo.micro, 561 versionInfo.preRelease, versionInfo.revision, 562 compatibleVersion); 563 if (error != B_OK) 564 RETURN_ERROR(error); 565 } 566 ObjectDeleter< ::Version> compatibleVersionDeleter( 567 compatibleVersion); 568 569 // create the resolvable 570 Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage); 571 if (resolvable == NULL) 572 RETURN_ERROR(B_NO_MEMORY); 573 ObjectDeleter<Resolvable> resolvableDeleter(resolvable); 574 575 status_t error = resolvable->Init(value.resolvable.name, 576 versionDeleter.Detach(), compatibleVersionDeleter.Detach()); 577 if (error != B_OK) 578 RETURN_ERROR(error); 579 580 fPackage->AddResolvable(resolvableDeleter.Detach()); 581 582 break; 583 } 584 585 case B_PACKAGE_INFO_REQUIRES: 586 { 587 // create the dependency 588 Dependency* dependency = new(std::nothrow) Dependency(fPackage); 589 if (dependency == NULL) 590 RETURN_ERROR(B_NO_MEMORY); 591 ObjectDeleter<Dependency> dependencyDeleter(dependency); 592 593 status_t error = dependency->Init( 594 value.resolvableExpression.name); 595 if (error != B_OK) 596 RETURN_ERROR(error); 597 598 // create a version object, if a version is specified 599 ::Version* version = NULL; 600 if (value.resolvableExpression.haveOpAndVersion) { 601 const BPackageVersionData& versionInfo 602 = value.resolvableExpression.version; 603 status_t error = Version::Create(versionInfo.major, 604 versionInfo.minor, versionInfo.micro, 605 versionInfo.preRelease, versionInfo.revision, version); 606 if (error != B_OK) 607 RETURN_ERROR(error); 608 609 dependency->SetVersionRequirement( 610 value.resolvableExpression.op, version); 611 } 612 613 fPackage->AddDependency(dependencyDeleter.Detach()); 614 615 break; 616 } 617 618 default: 619 break; 620 } 621 622 return B_OK; 623 } 624 625 virtual void HandleErrorOccurred() 626 { 627 fErrorOccurred = true; 628 } 629 630 private: 631 Package* fPackage; 632 bool fErrorOccurred; 633 }; 634 635 636 // #pragma mark - HeapReader 637 638 639 struct Package::HeapReader { 640 virtual ~HeapReader() 641 { 642 } 643 644 virtual void UpdateFD(int fd) = 0; 645 646 virtual status_t CreateDataReader(const PackageData& data, 647 BAbstractBufferedDataReader*& _reader) = 0; 648 }; 649 650 651 // #pragma mark - HeapReaderV1 652 653 654 struct Package::HeapReaderV1 : public HeapReader, private BDataReader { 655 public: 656 HeapReaderV1(int fd) 657 : 658 fFileReader(fd) 659 { 660 } 661 662 ~HeapReaderV1() 663 { 664 } 665 666 virtual void UpdateFD(int fd) 667 { 668 fFileReader.SetFD(fd); 669 } 670 671 virtual status_t CreateDataReader(const PackageData& data, 672 BAbstractBufferedDataReader*& _reader) 673 { 674 return GlobalFactory::Default()->CreatePackageDataReader(this, 675 data.DataV1(), _reader); 676 } 677 678 private: 679 // BDataReader 680 681 virtual status_t ReadData(off_t offset, void* buffer, size_t size) 682 { 683 return fFileReader.ReadData(offset, buffer, size); 684 } 685 686 private: 687 BFDDataReader fFileReader; 688 }; 689 690 691 // #pragma mark - HeapReaderV2 692 693 694 struct Package::HeapReaderV2 : public HeapReader, public CachedDataReader, 695 private BErrorOutput, private BFdIO { 696 public: 697 HeapReaderV2() 698 : 699 fHeapReader(NULL) 700 { 701 } 702 703 ~HeapReaderV2() 704 { 705 delete fHeapReader; 706 } 707 708 status_t Init(const PackageFileHeapReader* heapReader, int fd) 709 { 710 fHeapReader = heapReader->Clone(); 711 if (fHeapReader == NULL) 712 return B_NO_MEMORY; 713 714 BFdIO::SetTo(fd, false); 715 716 fHeapReader->SetErrorOutput(this); 717 fHeapReader->SetFile(this); 718 719 status_t error = CachedDataReader::Init(fHeapReader, 720 fHeapReader->UncompressedHeapSize()); 721 if (error != B_OK) 722 return error; 723 724 return B_OK; 725 } 726 727 virtual void UpdateFD(int fd) 728 { 729 BFdIO::SetTo(fd, false); 730 } 731 732 virtual status_t CreateDataReader(const PackageData& data, 733 BAbstractBufferedDataReader*& _reader) 734 { 735 return BPackageKit::BHPKG::BPackageDataReaderFactory() 736 .CreatePackageDataReader(this, data.DataV2(), _reader); 737 } 738 739 private: 740 // BErrorOutput 741 742 virtual void PrintErrorVarArgs(const char* format, va_list args) 743 { 744 ERRORV(format, args); 745 } 746 747 private: 748 PackageFileHeapReader* fHeapReader; 749 }; 750 751 752 // #pragma mark - Package 753 754 755 struct Package::CachingPackageReader : public PackageReaderImpl { 756 CachingPackageReader(BErrorOutput* errorOutput) 757 : 758 PackageReaderImpl(errorOutput), 759 fCachedHeapReader(NULL), 760 fFD(-1) 761 { 762 } 763 764 ~CachingPackageReader() 765 { 766 } 767 768 status_t Init(int fd, bool keepFD, uint32 flags) 769 { 770 fFD = fd; 771 return PackageReaderImpl::Init(fd, keepFD, flags); 772 } 773 774 virtual status_t CreateCachedHeapReader( 775 PackageFileHeapReader* rawHeapReader, 776 BAbstractBufferedDataReader*& _cachedReader) 777 { 778 fCachedHeapReader = new(std::nothrow) HeapReaderV2; 779 if (fCachedHeapReader == NULL) 780 RETURN_ERROR(B_NO_MEMORY); 781 782 status_t error = fCachedHeapReader->Init(rawHeapReader, fFD); 783 if (error != B_OK) 784 RETURN_ERROR(error); 785 786 _cachedReader = fCachedHeapReader; 787 return B_OK; 788 } 789 790 HeapReaderV2* DetachCachedHeapReader() 791 { 792 PackageFileHeapReader* rawHeapReader; 793 DetachHeapReader(rawHeapReader); 794 795 // We don't need the raw heap reader anymore, since the cached reader 796 // is not a wrapper around it, but completely independent from it. 797 delete rawHeapReader; 798 799 HeapReaderV2* cachedHeapReader = fCachedHeapReader; 800 fCachedHeapReader = NULL; 801 return cachedHeapReader; 802 } 803 804 private: 805 HeapReaderV2* fCachedHeapReader; 806 int fFD; 807 }; 808 809 810 // #pragma mark - Package 811 812 813 Package::Package(::Volume* volume, PackagesDirectory* directory, dev_t deviceID, 814 ino_t nodeID) 815 : 816 fVolume(volume), 817 fPackagesDirectory(directory), 818 fFileName(), 819 fName(), 820 fInstallPath(), 821 fVersionedName(), 822 fVersion(NULL), 823 fFlags(0), 824 fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT), 825 fLinkDirectory(NULL), 826 fFD(-1), 827 fOpenCount(0), 828 fHeapReader(NULL), 829 fNodeID(nodeID), 830 fDeviceID(deviceID) 831 { 832 mutex_init(&fLock, "packagefs package"); 833 834 fPackagesDirectory->AcquireReference(); 835 } 836 837 838 Package::~Package() 839 { 840 delete fHeapReader; 841 842 while (PackageNode* node = fNodes.RemoveHead()) 843 node->ReleaseReference(); 844 845 while (Resolvable* resolvable = fResolvables.RemoveHead()) 846 delete resolvable; 847 848 while (Dependency* dependency = fDependencies.RemoveHead()) 849 delete dependency; 850 851 delete fVersion; 852 853 fPackagesDirectory->ReleaseReference(); 854 855 mutex_destroy(&fLock); 856 } 857 858 859 status_t 860 Package::Init(const char* fileName) 861 { 862 if (!fFileName.SetTo(fileName)) 863 RETURN_ERROR(B_NO_MEMORY); 864 865 return B_OK; 866 } 867 868 869 status_t 870 Package::Load(const PackageSettings& settings) 871 { 872 status_t error = _Load(settings); 873 if (error != B_OK) 874 return error; 875 876 if (!_InitVersionedName()) 877 RETURN_ERROR(B_NO_MEMORY); 878 879 return B_OK; 880 } 881 882 883 void 884 Package::SetName(const String& name) 885 { 886 fName = name; 887 } 888 889 890 void 891 Package::SetInstallPath(const String& installPath) 892 { 893 fInstallPath = installPath; 894 } 895 896 897 void 898 Package::SetVersion(::Version* version) 899 { 900 if (fVersion != NULL) 901 delete fVersion; 902 903 fVersion = version; 904 } 905 906 907 const char* 908 Package::ArchitectureName() const 909 { 910 if (fArchitecture < 0 911 || fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) { 912 return NULL; 913 } 914 915 return kArchitectureNames[fArchitecture]; 916 } 917 918 919 void 920 Package::AddNode(PackageNode* node) 921 { 922 fNodes.Add(node); 923 node->AcquireReference(); 924 } 925 926 927 void 928 Package::AddResolvable(Resolvable* resolvable) 929 { 930 fResolvables.Add(resolvable); 931 } 932 933 934 void 935 Package::AddDependency(Dependency* dependency) 936 { 937 fDependencies.Add(dependency); 938 } 939 940 941 int 942 Package::Open() 943 { 944 MutexLocker locker(fLock); 945 if (fOpenCount > 0) { 946 fOpenCount++; 947 return fFD; 948 } 949 950 // open the file 951 fFD = openat(fPackagesDirectory->DirectoryFD(), fFileName, O_RDONLY); 952 if (fFD < 0) { 953 ERROR("Failed to open package file \"%s\": %s\n", fFileName.Data(), 954 strerror(errno)); 955 return errno; 956 } 957 958 // stat it to verify that it's still the same file 959 struct stat st; 960 if (fstat(fFD, &st) < 0) { 961 ERROR("Failed to stat package file \"%s\": %s\n", fFileName.Data(), 962 strerror(errno)); 963 close(fFD); 964 fFD = -1; 965 return errno; 966 } 967 968 if (st.st_dev != fDeviceID || st.st_ino != fNodeID) { 969 close(fFD); 970 fFD = -1; 971 RETURN_ERROR(B_ENTRY_NOT_FOUND); 972 } 973 974 fOpenCount = 1; 975 976 if (fHeapReader != NULL) 977 fHeapReader->UpdateFD(fFD); 978 979 return fFD; 980 } 981 982 983 void 984 Package::Close() 985 { 986 MutexLocker locker(fLock); 987 if (fOpenCount == 0) { 988 ERROR("Package open count already 0!\n"); 989 return; 990 } 991 992 if (--fOpenCount == 0) { 993 close(fFD); 994 fFD = -1; 995 996 if (fHeapReader != NULL) 997 fHeapReader->UpdateFD(fFD); 998 } 999 } 1000 1001 1002 status_t 1003 Package::CreateDataReader(const PackageData& data, 1004 BAbstractBufferedDataReader*& _reader) 1005 { 1006 if (fHeapReader == NULL) 1007 return B_BAD_VALUE; 1008 1009 return fHeapReader->CreateDataReader(data, _reader); 1010 } 1011 1012 1013 status_t 1014 Package::_Load(const PackageSettings& settings) 1015 { 1016 // open package file 1017 int fd = Open(); 1018 if (fd < 0) 1019 RETURN_ERROR(fd); 1020 PackageCloser packageCloser(this); 1021 1022 // initialize package reader 1023 LoaderErrorOutput errorOutput(this); 1024 1025 // try current package file format version 1026 { 1027 CachingPackageReader packageReader(&errorOutput); 1028 status_t error = packageReader.Init(fd, false, 1029 BHPKG::B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE); 1030 if (error == B_OK) { 1031 // parse content 1032 LoaderContentHandler handler(this, settings); 1033 error = handler.Init(); 1034 if (error != B_OK) 1035 RETURN_ERROR(error); 1036 1037 error = packageReader.ParseContent(&handler); 1038 if (error != B_OK) 1039 RETURN_ERROR(error); 1040 1041 // get the heap reader 1042 fHeapReader = packageReader.DetachCachedHeapReader(); 1043 return B_OK; 1044 } 1045 1046 if (error != B_MISMATCHED_VALUES) 1047 RETURN_ERROR(error); 1048 } 1049 1050 // try package file format version 1 1051 PackageReaderImplV1 packageReader(&errorOutput); 1052 status_t error = packageReader.Init(fd, false); 1053 if (error != B_OK) 1054 RETURN_ERROR(error); 1055 1056 // parse content 1057 LoaderContentHandlerV1 handler(this); 1058 error = handler.Init(); 1059 if (error != B_OK) 1060 RETURN_ERROR(error); 1061 1062 error = packageReader.ParseContent(&handler); 1063 if (error != B_OK) 1064 RETURN_ERROR(error); 1065 1066 // create a heap reader 1067 fHeapReader = new(std::nothrow) HeapReaderV1(fd); 1068 if (fHeapReader == NULL) 1069 RETURN_ERROR(B_NO_MEMORY); 1070 1071 return B_OK; 1072 } 1073 1074 1075 bool 1076 Package::_InitVersionedName() 1077 { 1078 // compute the allocation size needed for the versioned name 1079 size_t nameLength = strlen(fName); 1080 size_t size = nameLength + 1; 1081 1082 if (fVersion != NULL) { 1083 size += 1 + fVersion->ToString(NULL, 0); 1084 // + 1 for the '-' 1085 } 1086 1087 // allocate the name and compose it 1088 char* name = (char*)malloc(size); 1089 if (name == NULL) 1090 return false; 1091 MemoryDeleter nameDeleter(name); 1092 1093 memcpy(name, fName, nameLength + 1); 1094 if (fVersion != NULL) { 1095 name[nameLength] = '-'; 1096 fVersion->ToString(name + nameLength + 1, size - nameLength - 1); 1097 } 1098 1099 return fVersionedName.SetTo(name); 1100 } 1101