xref: /haiku/src/add-ons/kernel/file_systems/packagefs/package/Package.cpp (revision 548149fe48f59cf27f6071e9629b8bbe2ad32c1f)
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_ARCHITECTURE:
272 				if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
273 					RETURN_ERROR(B_BAD_VALUE);
274 
275 				fPackage->SetArchitecture(
276 					(BPackageArchitecture)value.unsignedInt);
277 				break;
278 
279 			case B_PACKAGE_INFO_PROVIDES:
280 			{
281 				// create a version object, if a version is specified
282 				::Version* version = NULL;
283 				if (value.resolvable.haveVersion) {
284 					const BPackageVersionData& versionInfo
285 						= value.resolvable.version;
286 					status_t error = Version::Create(versionInfo.major,
287 						versionInfo.minor, versionInfo.micro,
288 						versionInfo.preRelease, versionInfo.revision, version);
289 					if (error != B_OK)
290 						RETURN_ERROR(error);
291 				}
292 				ObjectDeleter< ::Version> versionDeleter(version);
293 
294 				// create a version object, if a compatible version is specified
295 				::Version* compatibleVersion = NULL;
296 				if (value.resolvable.haveCompatibleVersion) {
297 					const BPackageVersionData& versionInfo
298 						= value.resolvable.compatibleVersion;
299 					status_t error = Version::Create(versionInfo.major,
300 						versionInfo.minor, versionInfo.micro,
301 						versionInfo.preRelease, versionInfo.revision,
302 						compatibleVersion);
303 					if (error != B_OK)
304 						RETURN_ERROR(error);
305 				}
306 				ObjectDeleter< ::Version> compatibleVersionDeleter(
307 					compatibleVersion);
308 
309 				// create the resolvable
310 				Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
311 				if (resolvable == NULL)
312 					RETURN_ERROR(B_NO_MEMORY);
313 				ObjectDeleter<Resolvable> resolvableDeleter(resolvable);
314 
315 				status_t error = resolvable->Init(value.resolvable.name,
316 					versionDeleter.Detach(), compatibleVersionDeleter.Detach());
317 				if (error != B_OK)
318 					RETURN_ERROR(error);
319 
320 				fPackage->AddResolvable(resolvableDeleter.Detach());
321 
322 				break;
323 			}
324 
325 			case B_PACKAGE_INFO_REQUIRES:
326 			{
327 				// create the dependency
328 				Dependency* dependency = new(std::nothrow) Dependency(fPackage);
329 				if (dependency == NULL)
330 					RETURN_ERROR(B_NO_MEMORY);
331 				ObjectDeleter<Dependency> dependencyDeleter(dependency);
332 
333 				status_t error = dependency->Init(
334 					value.resolvableExpression.name);
335 				if (error != B_OK)
336 					RETURN_ERROR(error);
337 
338 				// create a version object, if a version is specified
339 				::Version* version = NULL;
340 				if (value.resolvableExpression.haveOpAndVersion) {
341 					const BPackageVersionData& versionInfo
342 						= value.resolvableExpression.version;
343 					status_t error = Version::Create(versionInfo.major,
344 						versionInfo.minor, versionInfo.micro,
345 						versionInfo.preRelease, versionInfo.revision, version);
346 					if (error != B_OK)
347 						RETURN_ERROR(error);
348 
349 					dependency->SetVersionRequirement(
350 						value.resolvableExpression.op, version);
351 				}
352 
353 				fPackage->AddDependency(dependencyDeleter.Detach());
354 
355 				break;
356 			}
357 
358 			default:
359 				break;
360 		}
361 
362 		return B_OK;
363 	}
364 
365 	virtual void HandleErrorOccurred()
366 	{
367 		fErrorOccurred = true;
368 	}
369 
370 private:
371 	Package*					fPackage;
372 	const PackageSettings&		fSettings;
373 	const PackageSettingsItem*	fSettingsItem;
374 	PackageSettingsItem::Entry*	fLastSettingsEntry;
375 	const BPackageEntry*		fLastSettingsEntryEntry;
376 	bool						fErrorOccurred;
377 };
378 
379 
380 // #pragma mark - LoaderContentHandlerV1
381 
382 
383 struct Package::LoaderContentHandlerV1 : BPackageContentHandlerV1 {
384 	LoaderContentHandlerV1(Package* package)
385 		:
386 		fPackage(package),
387 		fErrorOccurred(false)
388 	{
389 	}
390 
391 	status_t Init()
392 	{
393 		return B_OK;
394 	}
395 
396 	virtual status_t HandleEntry(BPackageEntryV1* entry)
397 	{
398 		if (fErrorOccurred)
399 			return B_OK;
400 
401 		PackageDirectory* parentDir = NULL;
402 		if (entry->Parent() != NULL) {
403 			parentDir = dynamic_cast<PackageDirectory*>(
404 				(PackageNode*)entry->Parent()->UserToken());
405 			if (parentDir == NULL)
406 				RETURN_ERROR(B_BAD_DATA);
407 		}
408 
409 		// get the file mode -- filter out write permissions
410 		mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
411 
412 		// create the package node
413 		PackageNode* node;
414 		if (S_ISREG(mode)) {
415 			// file
416 			node = new(std::nothrow) PackageFile(fPackage, mode,
417 				PackageData(entry->Data()));
418 		} else if (S_ISLNK(mode)) {
419 			// symlink
420 			String path;
421 			if (!path.SetTo(entry->SymlinkPath()))
422 				RETURN_ERROR(B_NO_MEMORY);
423 
424 			PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
425 				fPackage, mode);
426 			if (symlink == NULL)
427 				RETURN_ERROR(B_NO_MEMORY);
428 
429 			symlink->SetSymlinkPath(path);
430 			node = symlink;
431 		} else if (S_ISDIR(mode)) {
432 			// directory
433 			node = new(std::nothrow) PackageDirectory(fPackage, mode);
434 		} else
435 			RETURN_ERROR(B_BAD_DATA);
436 
437 		if (node == NULL)
438 			RETURN_ERROR(B_NO_MEMORY);
439 		BReference<PackageNode> nodeReference(node, true);
440 
441 		String entryName;
442 		if (!entryName.SetTo(entry->Name()))
443 			RETURN_ERROR(B_NO_MEMORY);
444 
445 		status_t error = node->Init(parentDir, entryName);
446 		if (error != B_OK)
447 			RETURN_ERROR(error);
448 
449 		node->SetModifiedTime(entry->ModifiedTime());
450 
451 		// add it to the parent directory
452 		if (parentDir != NULL)
453 			parentDir->AddChild(node);
454 		else
455 			fPackage->AddNode(node);
456 
457 		entry->SetUserToken(node);
458 
459 		return B_OK;
460 	}
461 
462 	virtual status_t HandleEntryAttribute(BPackageEntryV1* entry,
463 		BPackageEntryAttributeV1* attribute)
464 	{
465 		if (fErrorOccurred)
466 			return B_OK;
467 
468 		PackageNode* node = (PackageNode*)entry->UserToken();
469 
470 		String name;
471 		if (!name.SetTo(attribute->Name()))
472 			RETURN_ERROR(B_NO_MEMORY);
473 
474 		PackageNodeAttribute* nodeAttribute = new(std::nothrow)
475 			PackageNodeAttribute(attribute->Type(),
476 			PackageData(attribute->Data()));
477 		if (nodeAttribute == NULL)
478 			RETURN_ERROR(B_NO_MEMORY)
479 
480 		nodeAttribute->Init(name);
481 		node->AddAttribute(nodeAttribute);
482 
483 		return B_OK;
484 	}
485 
486 	virtual status_t HandleEntryDone(BPackageEntryV1* entry)
487 	{
488 		return B_OK;
489 	}
490 
491 	virtual status_t HandlePackageAttribute(
492 		const BPackageInfoAttributeValue& value)
493 	{
494 		switch (value.attributeID) {
495 			case B_PACKAGE_INFO_NAME:
496 			{
497 				String name;
498 				if (!name.SetTo(value.string))
499 					return B_NO_MEMORY;
500 				fPackage->SetName(name);
501 				return B_OK;
502 			}
503 
504 			case B_PACKAGE_INFO_INSTALL_PATH:
505 			{
506 				String path;
507 				if (!path.SetTo(value.string))
508 					return B_NO_MEMORY;
509 				fPackage->SetInstallPath(path);
510 				return B_OK;
511 			}
512 
513 			case B_PACKAGE_INFO_VERSION:
514 			{
515 				::Version* version;
516 				status_t error = Version::Create(value.version.major,
517 					value.version.minor, value.version.micro,
518 					value.version.preRelease, value.version.revision, version);
519 				if (error != B_OK)
520 					RETURN_ERROR(error);
521 
522 				fPackage->SetVersion(version);
523 
524 				break;
525 			}
526 
527 			case B_PACKAGE_INFO_ARCHITECTURE:
528 				if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
529 					RETURN_ERROR(B_BAD_VALUE);
530 
531 				fPackage->SetArchitecture(
532 					(BPackageArchitecture)value.unsignedInt);
533 				break;
534 
535 			case B_PACKAGE_INFO_PROVIDES:
536 			{
537 				// create a version object, if a version is specified
538 				::Version* version = NULL;
539 				if (value.resolvable.haveVersion) {
540 					const BPackageVersionData& versionInfo
541 						= value.resolvable.version;
542 					status_t error = Version::Create(versionInfo.major,
543 						versionInfo.minor, versionInfo.micro,
544 						versionInfo.preRelease, versionInfo.revision, version);
545 					if (error != B_OK)
546 						RETURN_ERROR(error);
547 				}
548 				ObjectDeleter< ::Version> versionDeleter(version);
549 
550 				// create a version object, if a compatible version is specified
551 				::Version* compatibleVersion = NULL;
552 				if (value.resolvable.haveCompatibleVersion) {
553 					const BPackageVersionData& versionInfo
554 						= value.resolvable.compatibleVersion;
555 					status_t error = Version::Create(versionInfo.major,
556 						versionInfo.minor, versionInfo.micro,
557 						versionInfo.preRelease, versionInfo.revision,
558 						compatibleVersion);
559 					if (error != B_OK)
560 						RETURN_ERROR(error);
561 				}
562 				ObjectDeleter< ::Version> compatibleVersionDeleter(
563 					compatibleVersion);
564 
565 				// create the resolvable
566 				Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
567 				if (resolvable == NULL)
568 					RETURN_ERROR(B_NO_MEMORY);
569 				ObjectDeleter<Resolvable> resolvableDeleter(resolvable);
570 
571 				status_t error = resolvable->Init(value.resolvable.name,
572 					versionDeleter.Detach(), compatibleVersionDeleter.Detach());
573 				if (error != B_OK)
574 					RETURN_ERROR(error);
575 
576 				fPackage->AddResolvable(resolvableDeleter.Detach());
577 
578 				break;
579 			}
580 
581 			case B_PACKAGE_INFO_REQUIRES:
582 			{
583 				// create the dependency
584 				Dependency* dependency = new(std::nothrow) Dependency(fPackage);
585 				if (dependency == NULL)
586 					RETURN_ERROR(B_NO_MEMORY);
587 				ObjectDeleter<Dependency> dependencyDeleter(dependency);
588 
589 				status_t error = dependency->Init(
590 					value.resolvableExpression.name);
591 				if (error != B_OK)
592 					RETURN_ERROR(error);
593 
594 				// create a version object, if a version is specified
595 				::Version* version = NULL;
596 				if (value.resolvableExpression.haveOpAndVersion) {
597 					const BPackageVersionData& versionInfo
598 						= value.resolvableExpression.version;
599 					status_t error = Version::Create(versionInfo.major,
600 						versionInfo.minor, versionInfo.micro,
601 						versionInfo.preRelease, versionInfo.revision, version);
602 					if (error != B_OK)
603 						RETURN_ERROR(error);
604 
605 					dependency->SetVersionRequirement(
606 						value.resolvableExpression.op, version);
607 				}
608 
609 				fPackage->AddDependency(dependencyDeleter.Detach());
610 
611 				break;
612 			}
613 
614 			default:
615 				break;
616 		}
617 
618 		return B_OK;
619 	}
620 
621 	virtual void HandleErrorOccurred()
622 	{
623 		fErrorOccurred = true;
624 	}
625 
626 private:
627 	Package*	fPackage;
628 	bool		fErrorOccurred;
629 };
630 
631 
632 // #pragma mark - HeapReader
633 
634 
635 struct Package::HeapReader {
636 	virtual ~HeapReader()
637 	{
638 	}
639 
640 	virtual void UpdateFD(int fd) = 0;
641 
642 	virtual status_t CreateDataReader(const PackageData& data,
643 		BAbstractBufferedDataReader*& _reader) = 0;
644 };
645 
646 
647 // #pragma mark - HeapReaderV1
648 
649 
650 struct Package::HeapReaderV1 : public HeapReader, private BDataReader {
651 public:
652 	HeapReaderV1(int fd)
653 		:
654 		fFileReader(fd)
655 	{
656 	}
657 
658 	~HeapReaderV1()
659 	{
660 	}
661 
662 	virtual void UpdateFD(int fd)
663 	{
664 		fFileReader.SetFD(fd);
665 	}
666 
667 	virtual status_t CreateDataReader(const PackageData& data,
668 		BAbstractBufferedDataReader*& _reader)
669 	{
670 		return GlobalFactory::Default()->CreatePackageDataReader(this,
671 			data.DataV1(), _reader);
672 	}
673 
674 private:
675 	// BDataReader
676 
677 	virtual status_t ReadData(off_t offset, void* buffer, size_t size)
678 	{
679 		return fFileReader.ReadData(offset, buffer, size);
680 	}
681 
682 private:
683 	BFDDataReader	fFileReader;
684 };
685 
686 
687 // #pragma mark - HeapReaderV2
688 
689 
690 struct Package::HeapReaderV2 : public HeapReader, public CachedDataReader,
691 	private BErrorOutput, private BFdIO {
692 public:
693 	HeapReaderV2()
694 		:
695 		fHeapReader(NULL)
696 	{
697 	}
698 
699 	~HeapReaderV2()
700 	{
701 		delete fHeapReader;
702 	}
703 
704 	status_t Init(const PackageFileHeapReader* heapReader, int fd)
705 	{
706 		fHeapReader = heapReader->Clone();
707 		if (fHeapReader == NULL)
708 			return B_NO_MEMORY;
709 
710 		BFdIO::SetTo(fd, false);
711 
712 		fHeapReader->SetErrorOutput(this);
713 		fHeapReader->SetFile(this);
714 
715 		status_t error = CachedDataReader::Init(fHeapReader,
716 			fHeapReader->UncompressedHeapSize());
717 		if (error != B_OK)
718 			return error;
719 
720 		return B_OK;
721 	}
722 
723 	virtual void UpdateFD(int fd)
724 	{
725 		BFdIO::SetTo(fd, false);
726 	}
727 
728 	virtual status_t CreateDataReader(const PackageData& data,
729 		BAbstractBufferedDataReader*& _reader)
730 	{
731 		return BPackageKit::BHPKG::BPackageDataReaderFactory()
732 			.CreatePackageDataReader(this, data.DataV2(), _reader);
733 	}
734 
735 private:
736 	// BErrorOutput
737 
738 	virtual void PrintErrorVarArgs(const char* format, va_list args)
739 	{
740 		ERRORV(format, args);
741 	}
742 
743 private:
744 	PackageFileHeapReader*	fHeapReader;
745 };
746 
747 
748 // #pragma mark - Package
749 
750 
751 struct Package::CachingPackageReader : public PackageReaderImpl {
752 	CachingPackageReader(BErrorOutput* errorOutput)
753 		:
754 		PackageReaderImpl(errorOutput),
755 		fCachedHeapReader(NULL),
756 		fFD(-1)
757 	{
758 	}
759 
760 	~CachingPackageReader()
761 	{
762 	}
763 
764 	status_t Init(int fd, bool keepFD, uint32 flags)
765 	{
766 		fFD = fd;
767 		return PackageReaderImpl::Init(fd, keepFD, flags);
768 	}
769 
770 	virtual status_t CreateCachedHeapReader(
771 		PackageFileHeapReader* rawHeapReader,
772 		BAbstractBufferedDataReader*& _cachedReader)
773 	{
774 		fCachedHeapReader = new(std::nothrow) HeapReaderV2;
775 		if (fCachedHeapReader == NULL)
776 			RETURN_ERROR(B_NO_MEMORY);
777 
778 		status_t error = fCachedHeapReader->Init(rawHeapReader, fFD);
779 		if (error != B_OK)
780 			RETURN_ERROR(error);
781 
782 		_cachedReader = fCachedHeapReader;
783 		return B_OK;
784 	}
785 
786 	HeapReaderV2* DetachCachedHeapReader()
787 	{
788 		PackageFileHeapReader* rawHeapReader;
789 		DetachHeapReader(rawHeapReader);
790 
791 		// We don't need the raw heap reader anymore, since the cached reader
792 		// is not a wrapper around it, but completely independent from it.
793 		delete rawHeapReader;
794 
795 		HeapReaderV2* cachedHeapReader = fCachedHeapReader;
796 		fCachedHeapReader = NULL;
797 		return cachedHeapReader;
798 	}
799 
800 private:
801 	HeapReaderV2*	fCachedHeapReader;
802 	int				fFD;
803 };
804 
805 
806 // #pragma mark - Package
807 
808 
809 Package::Package(::Volume* volume, PackagesDirectory* directory, dev_t deviceID,
810 	ino_t nodeID)
811 	:
812 	fVolume(volume),
813 	fPackagesDirectory(directory),
814 	fFileName(),
815 	fName(),
816 	fInstallPath(),
817 	fVersionedName(),
818 	fVersion(NULL),
819 	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
820 	fLinkDirectory(NULL),
821 	fFD(-1),
822 	fOpenCount(0),
823 	fHeapReader(NULL),
824 	fNodeID(nodeID),
825 	fDeviceID(deviceID)
826 {
827 	mutex_init(&fLock, "packagefs package");
828 
829 	fPackagesDirectory->AcquireReference();
830 }
831 
832 
833 Package::~Package()
834 {
835 	delete fHeapReader;
836 
837 	while (PackageNode* node = fNodes.RemoveHead())
838 		node->ReleaseReference();
839 
840 	while (Resolvable* resolvable = fResolvables.RemoveHead())
841 		delete resolvable;
842 
843 	while (Dependency* dependency = fDependencies.RemoveHead())
844 		delete dependency;
845 
846 	delete fVersion;
847 
848 	fPackagesDirectory->ReleaseReference();
849 
850 	mutex_destroy(&fLock);
851 }
852 
853 
854 status_t
855 Package::Init(const char* fileName)
856 {
857 	if (!fFileName.SetTo(fileName))
858 		RETURN_ERROR(B_NO_MEMORY);
859 
860 	return B_OK;
861 }
862 
863 
864 status_t
865 Package::Load(const PackageSettings& settings)
866 {
867 	status_t error = _Load(settings);
868 	if (error != B_OK)
869 		return error;
870 
871 	if (!_InitVersionedName())
872 		RETURN_ERROR(B_NO_MEMORY);
873 
874 	return B_OK;
875 }
876 
877 
878 void
879 Package::SetName(const String& name)
880 {
881 	fName = name;
882 }
883 
884 
885 void
886 Package::SetInstallPath(const String& installPath)
887 {
888 	fInstallPath = installPath;
889 }
890 
891 
892 void
893 Package::SetVersion(::Version* version)
894 {
895 	if (fVersion != NULL)
896 		delete fVersion;
897 
898 	fVersion = version;
899 }
900 
901 
902 const char*
903 Package::ArchitectureName() const
904 {
905 	if (fArchitecture < 0
906 		|| fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
907 		return NULL;
908 	}
909 
910 	return kArchitectureNames[fArchitecture];
911 }
912 
913 
914 void
915 Package::AddNode(PackageNode* node)
916 {
917 	fNodes.Add(node);
918 	node->AcquireReference();
919 }
920 
921 
922 void
923 Package::AddResolvable(Resolvable* resolvable)
924 {
925 	fResolvables.Add(resolvable);
926 }
927 
928 
929 void
930 Package::AddDependency(Dependency* dependency)
931 {
932 	fDependencies.Add(dependency);
933 }
934 
935 
936 int
937 Package::Open()
938 {
939 	MutexLocker locker(fLock);
940 	if (fOpenCount > 0) {
941 		fOpenCount++;
942 		return fFD;
943 	}
944 
945 	// open the file
946 	fFD = openat(fPackagesDirectory->DirectoryFD(), fFileName, O_RDONLY);
947 	if (fFD < 0) {
948 		ERROR("Failed to open package file \"%s\"\n", fFileName.Data());
949 		return errno;
950 	}
951 
952 	// stat it to verify that it's still the same file
953 	struct stat st;
954 	if (fstat(fFD, &st) < 0) {
955 		ERROR("Failed to stat package file \"%s\"\n", fFileName.Data());
956 		close(fFD);
957 		fFD = -1;
958 		return errno;
959 	}
960 
961 	if (st.st_dev != fDeviceID || st.st_ino != fNodeID) {
962 		close(fFD);
963 		fFD = -1;
964 		RETURN_ERROR(B_ENTRY_NOT_FOUND);
965 	}
966 
967 	fOpenCount = 1;
968 
969 	if (fHeapReader != NULL)
970 		fHeapReader->UpdateFD(fFD);
971 
972 	return fFD;
973 }
974 
975 
976 void
977 Package::Close()
978 {
979 	MutexLocker locker(fLock);
980 	if (fOpenCount == 0) {
981 		ERROR("Package open count already 0!\n");
982 		return;
983 	}
984 
985 	if (--fOpenCount == 0) {
986 		close(fFD);
987 		fFD = -1;
988 
989 		if (fHeapReader != NULL)
990 			fHeapReader->UpdateFD(fFD);
991 	}
992 }
993 
994 
995 status_t
996 Package::CreateDataReader(const PackageData& data,
997 	BAbstractBufferedDataReader*& _reader)
998 {
999 	if (fHeapReader == NULL)
1000 		return B_BAD_VALUE;
1001 
1002 	return fHeapReader->CreateDataReader(data, _reader);
1003 }
1004 
1005 
1006 status_t
1007 Package::_Load(const PackageSettings& settings)
1008 {
1009 	// open package file
1010 	int fd = Open();
1011 	if (fd < 0)
1012 		RETURN_ERROR(fd);
1013 	PackageCloser packageCloser(this);
1014 
1015 	// initialize package reader
1016 	LoaderErrorOutput errorOutput(this);
1017 
1018 	// try current package file format version
1019 	{
1020 		CachingPackageReader packageReader(&errorOutput);
1021 		status_t error = packageReader.Init(fd, false,
1022 			BHPKG::B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE);
1023 		if (error == B_OK) {
1024 			// parse content
1025 			LoaderContentHandler handler(this, settings);
1026 			error = handler.Init();
1027 			if (error != B_OK)
1028 				RETURN_ERROR(error);
1029 
1030 			error = packageReader.ParseContent(&handler);
1031 			if (error != B_OK)
1032 				RETURN_ERROR(error);
1033 
1034 			// get the heap reader
1035 			fHeapReader = packageReader.DetachCachedHeapReader();
1036 			return B_OK;
1037 		}
1038 
1039 		if (error != B_MISMATCHED_VALUES)
1040 			RETURN_ERROR(error);
1041 	}
1042 
1043 	// try package file format version 1
1044 	PackageReaderImplV1 packageReader(&errorOutput);
1045 	status_t error = packageReader.Init(fd, false);
1046 	if (error != B_OK)
1047 		RETURN_ERROR(error);
1048 
1049 	// parse content
1050 	LoaderContentHandlerV1 handler(this);
1051 	error = handler.Init();
1052 	if (error != B_OK)
1053 		RETURN_ERROR(error);
1054 
1055 	error = packageReader.ParseContent(&handler);
1056 	if (error != B_OK)
1057 		RETURN_ERROR(error);
1058 
1059 	// create a heap reader
1060 	fHeapReader = new(std::nothrow) HeapReaderV1(fd);
1061 	if (fHeapReader == NULL)
1062 		RETURN_ERROR(B_NO_MEMORY);
1063 
1064 	return B_OK;
1065 }
1066 
1067 
1068 bool
1069 Package::_InitVersionedName()
1070 {
1071 	// compute the allocation size needed for the versioned name
1072 	size_t nameLength = strlen(fName);
1073 	size_t size = nameLength + 1;
1074 
1075 	if (fVersion != NULL) {
1076 		size += 1 + fVersion->ToString(NULL, 0);
1077 			// + 1 for the '-'
1078 	}
1079 
1080 	// allocate the name and compose it
1081 	char* name = (char*)malloc(size);
1082 	if (name == NULL)
1083 		return false;
1084 	MemoryDeleter nameDeleter(name);
1085 
1086 	memcpy(name, fName, nameLength + 1);
1087 	if (fVersion != NULL) {
1088 		name[nameLength] = '-';
1089 		fVersion->ToString(name + nameLength + 1, size - nameLength - 1);
1090 	}
1091 
1092 	return fVersionedName.SetTo(name);
1093 }
1094