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 {
LoaderErrorOutputPackage::LoaderErrorOutput71 LoaderErrorOutput(Package* package)
72 :
73 fPackage(package)
74 {
75 }
76
PrintErrorVarArgsPackage::LoaderErrorOutput77 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 {
LoaderContentHandlerPackage::LoaderContentHandler91 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
InitPackage::LoaderContentHandler102 status_t Init()
103 {
104 return B_OK;
105 }
106
HandleEntryPackage::LoaderContentHandler107 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
HandleEntryAttributePackage::LoaderContentHandler188 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
HandleEntryDonePackage::LoaderContentHandler215 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
HandlePackageAttributePackage::LoaderContentHandler225 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
HandleErrorOccurredPackage::LoaderContentHandler361 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 {
~HeapReaderPackage::HeapReader380 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:
HeapReaderV2Package::HeapReaderV2397 HeapReaderV2()
398 :
399 fHeapReader(NULL)
400 {
401 }
402
~HeapReaderV2Package::HeapReaderV2403 ~HeapReaderV2()
404 {
405 delete fHeapReader;
406 }
407
InitPackage::HeapReaderV2408 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
UpdateFDPackage::HeapReaderV2427 virtual void UpdateFD(int fd)
428 {
429 BFdIO::SetTo(fd, false);
430 }
431
CreateDataReaderPackage::HeapReaderV2432 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
PrintErrorVarArgsPackage::HeapReaderV2442 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 {
CachingPackageReaderPackage::CachingPackageReader456 CachingPackageReader(BErrorOutput* errorOutput)
457 :
458 PackageReaderImpl(errorOutput),
459 fCachedHeapReader(NULL),
460 fFD(-1)
461 {
462 }
463
~CachingPackageReaderPackage::CachingPackageReader464 ~CachingPackageReader()
465 {
466 }
467
InitPackage::CachingPackageReader468 status_t Init(int fd, bool keepFD, uint32 flags)
469 {
470 fFD = fd;
471 return PackageReaderImpl::Init(fd, keepFD, flags);
472 }
473
CreateCachedHeapReaderPackage::CachingPackageReader474 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
DetachCachedHeapReaderPackage::CachingPackageReader490 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
Package(::Volume * volume,PackagesDirectory * directory,dev_t deviceID,ino_t nodeID)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
~Package()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
Init(const char * fileName)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
Load(const PackageSettings & settings)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
SetName(const String & name)584 Package::SetName(const String& name)
585 {
586 fName = name;
587 }
588
589
590 void
SetInstallPath(const String & installPath)591 Package::SetInstallPath(const String& installPath)
592 {
593 fInstallPath = installPath;
594 }
595
596
597 void
SetVersion(::Version * version)598 Package::SetVersion(::Version* version)
599 {
600 if (fVersion != NULL)
601 delete fVersion;
602
603 fVersion = version;
604 }
605
606
607 const char*
ArchitectureName() const608 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
AddNode(PackageNode * node)620 Package::AddNode(PackageNode* node)
621 {
622 fNodes.Add(node);
623 node->AcquireReference();
624 }
625
626
627 void
AddResolvable(Resolvable * resolvable)628 Package::AddResolvable(Resolvable* resolvable)
629 {
630 fResolvables.Add(resolvable);
631 }
632
633
634 void
AddDependency(Dependency * dependency)635 Package::AddDependency(Dependency* dependency)
636 {
637 fDependencies.Add(dependency);
638 }
639
640
641 int
Open()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
Close()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
CreateDataReader(const PackageData & data,BAbstractBufferedDataReader * & _reader)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
_Load(const PackageSettings & settings)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
_InitVersionedName()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