xref: /haiku/src/add-ons/kernel/file_systems/packagefs/package/Package.cpp (revision 9918c8295480d70f55fafb98008e23109b598871)
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(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->IsBlocked())) {
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