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