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 20 #include <AutoDeleter.h> 21 #include <FdIO.h> 22 #include <package/hpkg/PackageFileHeapReader.h> 23 #include <package/hpkg/PackageReaderImpl.h> 24 #include <util/AutoLock.h> 25 26 #include "CachedDataReader.h" 27 #include "DebugSupport.h" 28 #include "PackageDirectory.h" 29 #include "PackageFile.h" 30 #include "PackagesDirectory.h" 31 #include "PackageSettings.h" 32 #include "PackageSymlink.h" 33 #include "Version.h" 34 #include "Volume.h" 35 36 37 using namespace BPackageKit; 38 39 using BPackageKit::BHPKG::BErrorOutput; 40 using BPackageKit::BHPKG::BFDDataReader; 41 using BPackageKit::BHPKG::BPackageInfoAttributeValue; 42 using BPackageKit::BHPKG::BPackageVersionData; 43 using BPackageKit::BHPKG::BPrivate::PackageFileHeapReader; 44 45 // current format version types 46 typedef BPackageKit::BHPKG::BPackageContentHandler BPackageContentHandler; 47 typedef BPackageKit::BHPKG::BPackageEntry BPackageEntry; 48 typedef BPackageKit::BHPKG::BPackageEntryAttribute BPackageEntryAttribute; 49 typedef BPackageKit::BHPKG::BPrivate::PackageReaderImpl PackageReaderImpl; 50 51 52 const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = { 53 "any", 54 "x86", 55 "x86_gcc2", 56 "source", 57 "x86_64", 58 "ppc", 59 "arm", 60 "m68k", 61 "sparc", 62 "arm64", 63 "riscv64" 64 }; 65 66 67 // #pragma mark - LoaderErrorOutput 68 69 70 struct Package::LoaderErrorOutput : BErrorOutput { 71 LoaderErrorOutput(Package* package) 72 : 73 fPackage(package) 74 { 75 } 76 77 virtual void PrintErrorVarArgs(const char* format, va_list args) 78 { 79 ERRORV(format, args); 80 } 81 82 private: 83 Package* fPackage; 84 }; 85 86 87 // #pragma mark - LoaderContentHandler 88 89 90 struct Package::LoaderContentHandler : BPackageContentHandler { 91 LoaderContentHandler(Package* package, const PackageSettings& settings) 92 : 93 fPackage(package), 94 fSettings(settings), 95 fSettingsItem(NULL), 96 fLastSettingsEntry(NULL), 97 fLastSettingsEntryEntry(NULL), 98 fErrorOccurred(false) 99 { 100 } 101 102 status_t Init() 103 { 104 return B_OK; 105 } 106 107 virtual status_t HandleEntry(BPackageEntry* entry) 108 { 109 if (fErrorOccurred 110 || (fLastSettingsEntry != NULL 111 && fLastSettingsEntry->IsBlackListed())) { 112 return B_OK; 113 } 114 115 PackageDirectory* parentDir = NULL; 116 if (entry->Parent() != NULL) { 117 parentDir = dynamic_cast<PackageDirectory*>( 118 (PackageNode*)entry->Parent()->UserToken()); 119 if (parentDir == NULL) 120 RETURN_ERROR(B_BAD_DATA); 121 } 122 123 if (fSettingsItem != NULL 124 && (parentDir == NULL 125 || entry->Parent() == fLastSettingsEntryEntry)) { 126 PackageSettingsItem::Entry* settingsEntry 127 = fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name()); 128 if (settingsEntry != NULL) { 129 fLastSettingsEntry = settingsEntry; 130 fLastSettingsEntryEntry = entry; 131 if (fLastSettingsEntry->IsBlackListed()) 132 return B_OK; 133 } 134 } 135 136 // get the file mode -- filter out write permissions 137 mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); 138 139 // create the package node 140 PackageNode* node; 141 if (S_ISREG(mode)) { 142 // file 143 node = new PackageFile(fPackage, mode, 144 PackageData(entry->Data())); 145 } else if (S_ISLNK(mode)) { 146 // symlink 147 String path; 148 if (!path.SetTo(entry->SymlinkPath())) 149 RETURN_ERROR(B_NO_MEMORY); 150 151 PackageSymlink* symlink = new(std::nothrow) PackageSymlink( 152 fPackage, mode); 153 if (symlink == NULL) 154 RETURN_ERROR(B_NO_MEMORY); 155 156 symlink->SetSymlinkPath(path); 157 node = symlink; 158 } else if (S_ISDIR(mode)) { 159 // directory 160 node = new PackageDirectory(fPackage, mode); 161 } else 162 RETURN_ERROR(B_BAD_DATA); 163 164 if (node == NULL) 165 RETURN_ERROR(B_NO_MEMORY); 166 BReference<PackageNode> nodeReference(node, true); 167 168 String entryName; 169 if (!entryName.SetTo(entry->Name())) 170 RETURN_ERROR(B_NO_MEMORY); 171 172 status_t error = node->Init(parentDir, entryName); 173 if (error != B_OK) 174 RETURN_ERROR(error); 175 176 node->SetModifiedTime(entry->ModifiedTime()); 177 178 // add it to the parent directory 179 if (parentDir != NULL) 180 parentDir->AddChild(node); 181 else 182 fPackage->AddNode(node); 183 184 entry->SetUserToken(node); 185 186 return B_OK; 187 } 188 189 virtual status_t HandleEntryAttribute(BPackageEntry* entry, 190 BPackageEntryAttribute* attribute) 191 { 192 if (fErrorOccurred 193 || (fLastSettingsEntry != NULL 194 && fLastSettingsEntry->IsBlackListed())) { 195 return B_OK; 196 } 197 198 PackageNode* node = (PackageNode*)entry->UserToken(); 199 200 String name; 201 if (!name.SetTo(attribute->Name())) 202 RETURN_ERROR(B_NO_MEMORY); 203 204 PackageNodeAttribute* nodeAttribute = new 205 PackageNodeAttribute(attribute->Type(), 206 PackageData(attribute->Data())); 207 if (nodeAttribute == NULL) 208 RETURN_ERROR(B_NO_MEMORY) 209 210 nodeAttribute->Init(name); 211 node->AddAttribute(nodeAttribute); 212 213 return B_OK; 214 } 215 216 virtual status_t HandleEntryDone(BPackageEntry* entry) 217 { 218 if (entry == fLastSettingsEntryEntry) { 219 fLastSettingsEntryEntry = entry->Parent(); 220 fLastSettingsEntry = fLastSettingsEntry->Parent(); 221 } 222 223 return B_OK; 224 } 225 226 virtual status_t HandlePackageAttribute( 227 const BPackageInfoAttributeValue& value) 228 { 229 switch (value.attributeID) { 230 case B_PACKAGE_INFO_NAME: 231 { 232 String name; 233 if (!name.SetTo(value.string)) 234 return B_NO_MEMORY; 235 fPackage->SetName(name); 236 237 fSettingsItem = fSettings.PackageItemFor(fPackage->Name()); 238 239 return B_OK; 240 } 241 242 case B_PACKAGE_INFO_INSTALL_PATH: 243 { 244 String path; 245 if (!path.SetTo(value.string)) 246 return B_NO_MEMORY; 247 fPackage->SetInstallPath(path); 248 return B_OK; 249 } 250 251 case B_PACKAGE_INFO_VERSION: 252 { 253 ::Version* version; 254 status_t error = Version::Create(value.version.major, 255 value.version.minor, value.version.micro, 256 value.version.preRelease, value.version.revision, version); 257 if (error != B_OK) 258 RETURN_ERROR(error); 259 260 fPackage->SetVersion(version); 261 break; 262 } 263 264 case B_PACKAGE_INFO_FLAGS: 265 fPackage->SetFlags(value.unsignedInt); 266 break; 267 268 case B_PACKAGE_INFO_ARCHITECTURE: 269 if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) 270 RETURN_ERROR(B_BAD_VALUE); 271 272 fPackage->SetArchitecture( 273 (BPackageArchitecture)value.unsignedInt); 274 break; 275 276 case B_PACKAGE_INFO_PROVIDES: 277 { 278 // create a version object, if a version is specified 279 ::Version* version = NULL; 280 if (value.resolvable.haveVersion) { 281 const BPackageVersionData& versionInfo 282 = value.resolvable.version; 283 status_t error = Version::Create(versionInfo.major, 284 versionInfo.minor, versionInfo.micro, 285 versionInfo.preRelease, versionInfo.revision, version); 286 if (error != B_OK) 287 RETURN_ERROR(error); 288 } 289 ObjectDeleter< ::Version> versionDeleter(version); 290 291 // create a version object, if a compatible version is specified 292 ::Version* compatibleVersion = NULL; 293 if (value.resolvable.haveCompatibleVersion) { 294 const BPackageVersionData& versionInfo 295 = value.resolvable.compatibleVersion; 296 status_t error = Version::Create(versionInfo.major, 297 versionInfo.minor, versionInfo.micro, 298 versionInfo.preRelease, versionInfo.revision, 299 compatibleVersion); 300 if (error != B_OK) 301 RETURN_ERROR(error); 302 } 303 ObjectDeleter< ::Version> compatibleVersionDeleter( 304 compatibleVersion); 305 306 // create the resolvable 307 Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage); 308 if (resolvable == NULL) 309 RETURN_ERROR(B_NO_MEMORY); 310 ObjectDeleter<Resolvable> resolvableDeleter(resolvable); 311 312 status_t error = resolvable->Init(value.resolvable.name, 313 versionDeleter.Detach(), compatibleVersionDeleter.Detach()); 314 if (error != B_OK) 315 RETURN_ERROR(error); 316 317 fPackage->AddResolvable(resolvableDeleter.Detach()); 318 319 break; 320 } 321 322 case B_PACKAGE_INFO_REQUIRES: 323 { 324 // create the dependency 325 Dependency* dependency = new(std::nothrow) Dependency(fPackage); 326 if (dependency == NULL) 327 RETURN_ERROR(B_NO_MEMORY); 328 ObjectDeleter<Dependency> dependencyDeleter(dependency); 329 330 status_t error = dependency->Init( 331 value.resolvableExpression.name); 332 if (error != B_OK) 333 RETURN_ERROR(error); 334 335 // create a version object, if a version is specified 336 ::Version* version = NULL; 337 if (value.resolvableExpression.haveOpAndVersion) { 338 const BPackageVersionData& versionInfo 339 = value.resolvableExpression.version; 340 status_t error = Version::Create(versionInfo.major, 341 versionInfo.minor, versionInfo.micro, 342 versionInfo.preRelease, versionInfo.revision, version); 343 if (error != B_OK) 344 RETURN_ERROR(error); 345 346 dependency->SetVersionRequirement( 347 value.resolvableExpression.op, version); 348 } 349 350 fPackage->AddDependency(dependencyDeleter.Detach()); 351 352 break; 353 } 354 355 default: 356 break; 357 } 358 359 return B_OK; 360 } 361 362 virtual void HandleErrorOccurred() 363 { 364 fErrorOccurred = true; 365 } 366 367 private: 368 Package* fPackage; 369 const PackageSettings& fSettings; 370 const PackageSettingsItem* fSettingsItem; 371 PackageSettingsItem::Entry* fLastSettingsEntry; 372 const BPackageEntry* fLastSettingsEntryEntry; 373 bool fErrorOccurred; 374 }; 375 376 377 // #pragma mark - HeapReader 378 379 380 struct Package::HeapReader { 381 virtual ~HeapReader() 382 { 383 } 384 385 virtual void UpdateFD(int fd) = 0; 386 387 virtual status_t CreateDataReader(const PackageData& data, 388 BAbstractBufferedDataReader*& _reader) = 0; 389 }; 390 391 392 // #pragma mark - HeapReaderV2 393 394 395 struct Package::HeapReaderV2 : public HeapReader, public CachedDataReader, 396 private BErrorOutput, private BFdIO { 397 public: 398 HeapReaderV2() 399 : 400 fHeapReader(NULL) 401 { 402 } 403 404 ~HeapReaderV2() 405 { 406 delete fHeapReader; 407 } 408 409 status_t Init(const PackageFileHeapReader* heapReader, int fd) 410 { 411 fHeapReader = heapReader->Clone(); 412 if (fHeapReader == NULL) 413 return B_NO_MEMORY; 414 415 BFdIO::SetTo(fd, false); 416 417 fHeapReader->SetErrorOutput(this); 418 fHeapReader->SetFile(this); 419 420 status_t error = CachedDataReader::Init(fHeapReader, 421 fHeapReader->UncompressedHeapSize()); 422 if (error != B_OK) 423 return error; 424 425 return B_OK; 426 } 427 428 virtual void UpdateFD(int fd) 429 { 430 BFdIO::SetTo(fd, false); 431 } 432 433 virtual status_t CreateDataReader(const PackageData& data, 434 BAbstractBufferedDataReader*& _reader) 435 { 436 return BPackageKit::BHPKG::BPackageDataReaderFactory() 437 .CreatePackageDataReader(this, data.DataV2(), _reader); 438 } 439 440 private: 441 // BErrorOutput 442 443 virtual void PrintErrorVarArgs(const char* format, va_list args) 444 { 445 ERRORV(format, args); 446 } 447 448 private: 449 PackageFileHeapReader* fHeapReader; 450 }; 451 452 453 // #pragma mark - Package 454 455 456 struct Package::CachingPackageReader : public PackageReaderImpl { 457 CachingPackageReader(BErrorOutput* errorOutput) 458 : 459 PackageReaderImpl(errorOutput), 460 fCachedHeapReader(NULL), 461 fFD(-1) 462 { 463 } 464 465 ~CachingPackageReader() 466 { 467 } 468 469 status_t Init(int fd, bool keepFD, uint32 flags) 470 { 471 fFD = fd; 472 return PackageReaderImpl::Init(fd, keepFD, flags); 473 } 474 475 virtual status_t CreateCachedHeapReader( 476 PackageFileHeapReader* rawHeapReader, 477 BAbstractBufferedDataReader*& _cachedReader) 478 { 479 fCachedHeapReader = new(std::nothrow) HeapReaderV2; 480 if (fCachedHeapReader == NULL) 481 RETURN_ERROR(B_NO_MEMORY); 482 483 status_t error = fCachedHeapReader->Init(rawHeapReader, fFD); 484 if (error != B_OK) 485 RETURN_ERROR(error); 486 487 _cachedReader = fCachedHeapReader; 488 return B_OK; 489 } 490 491 HeapReaderV2* DetachCachedHeapReader() 492 { 493 PackageFileHeapReader* rawHeapReader; 494 DetachHeapReader(rawHeapReader); 495 496 // We don't need the raw heap reader anymore, since the cached reader 497 // is not a wrapper around it, but completely independent from it. 498 delete rawHeapReader; 499 500 HeapReaderV2* cachedHeapReader = fCachedHeapReader; 501 fCachedHeapReader = NULL; 502 return cachedHeapReader; 503 } 504 505 private: 506 HeapReaderV2* fCachedHeapReader; 507 int fFD; 508 }; 509 510 511 // #pragma mark - Package 512 513 514 Package::Package(::Volume* volume, PackagesDirectory* directory, dev_t deviceID, 515 ino_t nodeID) 516 : 517 fVolume(volume), 518 fPackagesDirectory(directory), 519 fFileName(), 520 fName(), 521 fInstallPath(), 522 fVersionedName(), 523 fVersion(NULL), 524 fFlags(0), 525 fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT), 526 fLinkDirectory(NULL), 527 fFD(-1), 528 fOpenCount(0), 529 fHeapReader(NULL), 530 fNodeID(nodeID), 531 fDeviceID(deviceID) 532 { 533 mutex_init(&fLock, "packagefs package"); 534 535 fPackagesDirectory->AcquireReference(); 536 } 537 538 539 Package::~Package() 540 { 541 delete fHeapReader; 542 543 while (PackageNode* node = fNodes.RemoveHead()) 544 node->ReleaseReference(); 545 546 while (Resolvable* resolvable = fResolvables.RemoveHead()) 547 delete resolvable; 548 549 while (Dependency* dependency = fDependencies.RemoveHead()) 550 delete dependency; 551 552 delete fVersion; 553 554 fPackagesDirectory->ReleaseReference(); 555 556 mutex_destroy(&fLock); 557 } 558 559 560 status_t 561 Package::Init(const char* fileName) 562 { 563 if (!fFileName.SetTo(fileName)) 564 RETURN_ERROR(B_NO_MEMORY); 565 566 return B_OK; 567 } 568 569 570 status_t 571 Package::Load(const PackageSettings& settings) 572 { 573 status_t error = _Load(settings); 574 if (error != B_OK) 575 return error; 576 577 if (!_InitVersionedName()) 578 RETURN_ERROR(B_NO_MEMORY); 579 580 return B_OK; 581 } 582 583 584 void 585 Package::SetName(const String& name) 586 { 587 fName = name; 588 } 589 590 591 void 592 Package::SetInstallPath(const String& installPath) 593 { 594 fInstallPath = installPath; 595 } 596 597 598 void 599 Package::SetVersion(::Version* version) 600 { 601 if (fVersion != NULL) 602 delete fVersion; 603 604 fVersion = version; 605 } 606 607 608 const char* 609 Package::ArchitectureName() const 610 { 611 if (fArchitecture < 0 612 || fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) { 613 return NULL; 614 } 615 616 return kArchitectureNames[fArchitecture]; 617 } 618 619 620 void 621 Package::AddNode(PackageNode* node) 622 { 623 fNodes.Add(node); 624 node->AcquireReference(); 625 } 626 627 628 void 629 Package::AddResolvable(Resolvable* resolvable) 630 { 631 fResolvables.Add(resolvable); 632 } 633 634 635 void 636 Package::AddDependency(Dependency* dependency) 637 { 638 fDependencies.Add(dependency); 639 } 640 641 642 int 643 Package::Open() 644 { 645 MutexLocker locker(fLock); 646 if (fOpenCount > 0) { 647 fOpenCount++; 648 return fFD; 649 } 650 651 // open the file 652 fFD = openat(fPackagesDirectory->DirectoryFD(), fFileName, 653 O_RDONLY | O_NOCACHE); 654 if (fFD < 0) { 655 ERROR("Failed to open package file \"%s\": %s\n", fFileName.Data(), 656 strerror(errno)); 657 return errno; 658 } 659 660 // stat it to verify that it's still the same file 661 struct stat st; 662 if (fstat(fFD, &st) < 0) { 663 ERROR("Failed to stat package file \"%s\": %s\n", fFileName.Data(), 664 strerror(errno)); 665 close(fFD); 666 fFD = -1; 667 return errno; 668 } 669 670 if (st.st_dev != fDeviceID || st.st_ino != fNodeID) { 671 close(fFD); 672 fFD = -1; 673 RETURN_ERROR(B_ENTRY_NOT_FOUND); 674 } 675 676 fOpenCount = 1; 677 678 if (fHeapReader != NULL) 679 fHeapReader->UpdateFD(fFD); 680 681 return fFD; 682 } 683 684 685 void 686 Package::Close() 687 { 688 MutexLocker locker(fLock); 689 if (fOpenCount == 0) { 690 ERROR("Package open count already 0!\n"); 691 return; 692 } 693 694 if (--fOpenCount == 0) { 695 close(fFD); 696 fFD = -1; 697 698 if (fHeapReader != NULL) 699 fHeapReader->UpdateFD(fFD); 700 } 701 } 702 703 704 status_t 705 Package::CreateDataReader(const PackageData& data, 706 BAbstractBufferedDataReader*& _reader) 707 { 708 if (fHeapReader == NULL) 709 return B_BAD_VALUE; 710 711 return fHeapReader->CreateDataReader(data, _reader); 712 } 713 714 715 status_t 716 Package::_Load(const PackageSettings& settings) 717 { 718 // open package file 719 int fd = Open(); 720 if (fd < 0) 721 RETURN_ERROR(fd); 722 PackageCloser packageCloser(this); 723 724 // initialize package reader 725 LoaderErrorOutput errorOutput(this); 726 727 // try current package file format version 728 { 729 CachingPackageReader packageReader(&errorOutput); 730 status_t error = packageReader.Init(fd, false, 731 BHPKG::B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE); 732 if (error == B_OK) { 733 // parse content 734 LoaderContentHandler handler(this, settings); 735 error = handler.Init(); 736 if (error != B_OK) 737 RETURN_ERROR(error); 738 739 error = packageReader.ParseContent(&handler); 740 if (error != B_OK) 741 RETURN_ERROR(error); 742 743 // get the heap reader 744 fHeapReader = packageReader.DetachCachedHeapReader(); 745 return B_OK; 746 } 747 748 if (error != B_MISMATCHED_VALUES) 749 RETURN_ERROR(error); 750 } 751 752 // we don't support this package file format 753 RETURN_ERROR(B_BAD_DATA); 754 } 755 756 757 bool 758 Package::_InitVersionedName() 759 { 760 // compute the allocation size needed for the versioned name 761 size_t nameLength = strlen(fName); 762 size_t size = nameLength + 1; 763 764 if (fVersion != NULL) { 765 size += 1 + fVersion->ToString(NULL, 0); 766 // + 1 for the '-' 767 } 768 769 // allocate the name and compose it 770 char* name = (char*)malloc(size); 771 if (name == NULL) 772 return false; 773 MemoryDeleter nameDeleter(name); 774 775 memcpy(name, fName, nameLength + 1); 776 if (fVersion != NULL) { 777 name[nameLength] = '-'; 778 fVersion->ToString(name + nameLength + 1, size - nameLength - 1); 779 } 780 781 return fVersionedName.SetTo(name); 782 } 783