xref: /haiku/src/add-ons/kernel/file_systems/packagefs/package/Package.cpp (revision a629567a9001547736cfe892cdf992be16868fed)
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 <package/hpkg/PackageFileHeapReader.h>
24 #include <package/hpkg/PackageReaderImpl.h>
25 #include <package/hpkg/v1/PackageReaderImpl.h>
26 #include <util/AutoLock.h>
27 
28 #include "CachedDataReader.h"
29 #include "DebugSupport.h"
30 #include "GlobalFactory.h"
31 #include "PackageDirectory.h"
32 #include "PackageFile.h"
33 #include "PackagesDirectory.h"
34 #include "PackageSettings.h"
35 #include "PackageSymlink.h"
36 #include "Version.h"
37 #include "Volume.h"
38 
39 
40 using namespace BPackageKit;
41 
42 using BPackageKit::BHPKG::BErrorOutput;
43 using BPackageKit::BHPKG::BFDDataReader;
44 using BPackageKit::BHPKG::BPackageInfoAttributeValue;
45 using BPackageKit::BHPKG::BPackageVersionData;
46 using BPackageKit::BHPKG::BPrivate::PackageFileHeapReader;
47 
48 // current format version types
49 typedef BPackageKit::BHPKG::BPackageContentHandler BPackageContentHandler;
50 typedef BPackageKit::BHPKG::BPackageEntry BPackageEntry;
51 typedef BPackageKit::BHPKG::BPackageEntryAttribute BPackageEntryAttribute;
52 typedef BPackageKit::BHPKG::BPrivate::PackageReaderImpl PackageReaderImpl;
53 
54 // format version V1 types
55 typedef BPackageKit::BHPKG::V1::BPackageContentHandler BPackageContentHandlerV1;
56 typedef BPackageKit::BHPKG::V1::BPackageEntry BPackageEntryV1;
57 typedef BPackageKit::BHPKG::V1::BPackageEntryAttribute BPackageEntryAttributeV1;
58 typedef BPackageKit::BHPKG::V1::BPrivate::PackageReaderImpl PackageReaderImplV1;
59 
60 
61 const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
62 	"any",
63 	"x86",
64 	"x86_gcc2",
65 	"source",
66 	"x86_64",
67 	"ppc",
68 	"arm",
69 	"m68k"
70 };
71 
72 
73 // #pragma mark - LoaderErrorOutput
74 
75 
76 struct Package::LoaderErrorOutput : BErrorOutput {
77 	LoaderErrorOutput(Package* package)
78 		:
79 		fPackage(package)
80 	{
81 	}
82 
83 	virtual void PrintErrorVarArgs(const char* format, va_list args)
84 	{
85 		ERRORV(format, args);
86 	}
87 
88 private:
89 	Package*	fPackage;
90 };
91 
92 
93 // #pragma mark - LoaderContentHandler
94 
95 
96 struct Package::LoaderContentHandler : BPackageContentHandler {
97 	LoaderContentHandler(Package* package, const PackageSettings& settings)
98 		:
99 		fPackage(package),
100 		fSettings(settings),
101 		fSettingsItem(NULL),
102 		fLastSettingsEntry(NULL),
103 		fLastSettingsEntryEntry(NULL),
104 		fErrorOccurred(false)
105 	{
106 	}
107 
108 	status_t Init()
109 	{
110 		return B_OK;
111 	}
112 
113 	virtual status_t HandleEntry(BPackageEntry* entry)
114 	{
115 		if (fErrorOccurred
116 			|| (fLastSettingsEntry != NULL
117 				&& fLastSettingsEntry->IsBlackListed())) {
118 			return B_OK;
119 		}
120 
121 		PackageDirectory* parentDir = NULL;
122 		if (entry->Parent() != NULL) {
123 			parentDir = dynamic_cast<PackageDirectory*>(
124 				(PackageNode*)entry->Parent()->UserToken());
125 			if (parentDir == NULL)
126 				RETURN_ERROR(B_BAD_DATA);
127 		}
128 
129 		if (fSettingsItem != NULL
130 			&& (parentDir == NULL
131 				|| entry->Parent() == fLastSettingsEntryEntry)) {
132 			PackageSettingsItem::Entry* settingsEntry
133 				= fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name());
134 			if (settingsEntry != NULL) {
135 				fLastSettingsEntry = settingsEntry;
136 				fLastSettingsEntryEntry = entry;
137 				if (fLastSettingsEntry->IsBlackListed())
138 					return B_OK;
139 			}
140 		}
141 
142 		// get the file mode -- filter out write permissions
143 		mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
144 
145 		// create the package node
146 		PackageNode* node;
147 		if (S_ISREG(mode)) {
148 			// file
149 			node = new(std::nothrow) PackageFile(fPackage, mode,
150 				PackageData(entry->Data()));
151 		} else if (S_ISLNK(mode)) {
152 			// symlink
153 			String path;
154 			if (!path.SetTo(entry->SymlinkPath()))
155 				RETURN_ERROR(B_NO_MEMORY);
156 
157 			PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
158 				fPackage, mode);
159 			if (symlink == NULL)
160 				RETURN_ERROR(B_NO_MEMORY);
161 
162 			symlink->SetSymlinkPath(path);
163 			node = symlink;
164 		} else if (S_ISDIR(mode)) {
165 			// directory
166 			node = new(std::nothrow) PackageDirectory(fPackage, mode);
167 		} else
168 			RETURN_ERROR(B_BAD_DATA);
169 
170 		if (node == NULL)
171 			RETURN_ERROR(B_NO_MEMORY);
172 		BReference<PackageNode> nodeReference(node, true);
173 
174 		String entryName;
175 		if (!entryName.SetTo(entry->Name()))
176 			RETURN_ERROR(B_NO_MEMORY);
177 
178 		status_t error = node->Init(parentDir, entryName);
179 		if (error != B_OK)
180 			RETURN_ERROR(error);
181 
182 		node->SetModifiedTime(entry->ModifiedTime());
183 
184 		// add it to the parent directory
185 		if (parentDir != NULL)
186 			parentDir->AddChild(node);
187 		else
188 			fPackage->AddNode(node);
189 
190 		entry->SetUserToken(node);
191 
192 		return B_OK;
193 	}
194 
195 	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
196 		BPackageEntryAttribute* attribute)
197 	{
198 		if (fErrorOccurred
199 			|| (fLastSettingsEntry != NULL
200 				&& fLastSettingsEntry->IsBlackListed())) {
201 			return B_OK;
202 		}
203 
204 		PackageNode* node = (PackageNode*)entry->UserToken();
205 
206 		String name;
207 		if (!name.SetTo(attribute->Name()))
208 			RETURN_ERROR(B_NO_MEMORY);
209 
210 		PackageNodeAttribute* nodeAttribute = new(std::nothrow)
211 			PackageNodeAttribute(attribute->Type(),
212 			PackageData(attribute->Data()));
213 		if (nodeAttribute == NULL)
214 			RETURN_ERROR(B_NO_MEMORY)
215 
216 		nodeAttribute->Init(name);
217 		node->AddAttribute(nodeAttribute);
218 
219 		return B_OK;
220 	}
221 
222 	virtual status_t HandleEntryDone(BPackageEntry* entry)
223 	{
224 		if (entry == fLastSettingsEntryEntry) {
225 			fLastSettingsEntryEntry = entry->Parent();
226 			fLastSettingsEntry = fLastSettingsEntry->Parent();
227 		}
228 
229 		return B_OK;
230 	}
231 
232 	virtual status_t HandlePackageAttribute(
233 		const BPackageInfoAttributeValue& value)
234 	{
235 		switch (value.attributeID) {
236 			case B_PACKAGE_INFO_NAME:
237 			{
238 				String name;
239 				if (!name.SetTo(value.string))
240 					return B_NO_MEMORY;
241 				fPackage->SetName(name);
242 
243 				fSettingsItem = fSettings.PackageItemFor(fPackage->Name());
244 
245 				return B_OK;
246 			}
247 
248 			case B_PACKAGE_INFO_INSTALL_PATH:
249 			{
250 				String path;
251 				if (!path.SetTo(value.string))
252 					return B_NO_MEMORY;
253 				fPackage->SetInstallPath(path);
254 				return B_OK;
255 			}
256 
257 			case B_PACKAGE_INFO_VERSION:
258 			{
259 				::Version* version;
260 				status_t error = Version::Create(value.version.major,
261 					value.version.minor, value.version.micro,
262 					value.version.preRelease, value.version.revision, version);
263 				if (error != B_OK)
264 					RETURN_ERROR(error);
265 
266 				fPackage->SetVersion(version);
267 				break;
268 			}
269 
270 			case B_PACKAGE_INFO_ARCHITECTURE:
271 				if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
272 					RETURN_ERROR(B_BAD_VALUE);
273 
274 				fPackage->SetArchitecture(
275 					(BPackageArchitecture)value.unsignedInt);
276 				break;
277 
278 			case B_PACKAGE_INFO_PROVIDES:
279 			{
280 				// create a version object, if a version is specified
281 				::Version* version = NULL;
282 				if (value.resolvable.haveVersion) {
283 					const BPackageVersionData& versionInfo
284 						= value.resolvable.version;
285 					status_t error = Version::Create(versionInfo.major,
286 						versionInfo.minor, versionInfo.micro,
287 						versionInfo.preRelease, versionInfo.revision, version);
288 					if (error != B_OK)
289 						RETURN_ERROR(error);
290 				}
291 				ObjectDeleter< ::Version> versionDeleter(version);
292 
293 				// create a version object, if a compatible version is specified
294 				::Version* compatibleVersion = NULL;
295 				if (value.resolvable.haveCompatibleVersion) {
296 					const BPackageVersionData& versionInfo
297 						= value.resolvable.compatibleVersion;
298 					status_t error = Version::Create(versionInfo.major,
299 						versionInfo.minor, versionInfo.micro,
300 						versionInfo.preRelease, versionInfo.revision,
301 						compatibleVersion);
302 					if (error != B_OK)
303 						RETURN_ERROR(error);
304 				}
305 				ObjectDeleter< ::Version> compatibleVersionDeleter(
306 					compatibleVersion);
307 
308 				// create the resolvable
309 				Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
310 				if (resolvable == NULL)
311 					RETURN_ERROR(B_NO_MEMORY);
312 				ObjectDeleter<Resolvable> resolvableDeleter(resolvable);
313 
314 				status_t error = resolvable->Init(value.resolvable.name,
315 					versionDeleter.Detach(), compatibleVersionDeleter.Detach());
316 				if (error != B_OK)
317 					RETURN_ERROR(error);
318 
319 				fPackage->AddResolvable(resolvableDeleter.Detach());
320 
321 				break;
322 			}
323 
324 			case B_PACKAGE_INFO_REQUIRES:
325 			{
326 				// create the dependency
327 				Dependency* dependency = new(std::nothrow) Dependency(fPackage);
328 				if (dependency == NULL)
329 					RETURN_ERROR(B_NO_MEMORY);
330 				ObjectDeleter<Dependency> dependencyDeleter(dependency);
331 
332 				status_t error = dependency->Init(
333 					value.resolvableExpression.name);
334 				if (error != B_OK)
335 					RETURN_ERROR(error);
336 
337 				// create a version object, if a version is specified
338 				::Version* version = NULL;
339 				if (value.resolvableExpression.haveOpAndVersion) {
340 					const BPackageVersionData& versionInfo
341 						= value.resolvableExpression.version;
342 					status_t error = Version::Create(versionInfo.major,
343 						versionInfo.minor, versionInfo.micro,
344 						versionInfo.preRelease, versionInfo.revision, version);
345 					if (error != B_OK)
346 						RETURN_ERROR(error);
347 
348 					dependency->SetVersionRequirement(
349 						value.resolvableExpression.op, version);
350 				}
351 
352 				fPackage->AddDependency(dependencyDeleter.Detach());
353 
354 				break;
355 			}
356 
357 			default:
358 				break;
359 		}
360 
361 		return B_OK;
362 	}
363 
364 	virtual void HandleErrorOccurred()
365 	{
366 		fErrorOccurred = true;
367 	}
368 
369 private:
370 	Package*					fPackage;
371 	const PackageSettings&		fSettings;
372 	const PackageSettingsItem*	fSettingsItem;
373 	PackageSettingsItem::Entry*	fLastSettingsEntry;
374 	const BPackageEntry*		fLastSettingsEntryEntry;
375 	bool						fErrorOccurred;
376 };
377 
378 
379 // #pragma mark - LoaderContentHandlerV1
380 
381 
382 struct Package::LoaderContentHandlerV1 : BPackageContentHandlerV1 {
383 	LoaderContentHandlerV1(Package* package)
384 		:
385 		fPackage(package),
386 		fErrorOccurred(false)
387 	{
388 	}
389 
390 	status_t Init()
391 	{
392 		return B_OK;
393 	}
394 
395 	virtual status_t HandleEntry(BPackageEntryV1* entry)
396 	{
397 		if (fErrorOccurred)
398 			return B_OK;
399 
400 		PackageDirectory* parentDir = NULL;
401 		if (entry->Parent() != NULL) {
402 			parentDir = dynamic_cast<PackageDirectory*>(
403 				(PackageNode*)entry->Parent()->UserToken());
404 			if (parentDir == NULL)
405 				RETURN_ERROR(B_BAD_DATA);
406 		}
407 
408 		// get the file mode -- filter out write permissions
409 		mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
410 
411 		// create the package node
412 		PackageNode* node;
413 		if (S_ISREG(mode)) {
414 			// file
415 			node = new(std::nothrow) PackageFile(fPackage, mode,
416 				PackageData(entry->Data()));
417 		} else if (S_ISLNK(mode)) {
418 			// symlink
419 			String path;
420 			if (!path.SetTo(entry->SymlinkPath()))
421 				RETURN_ERROR(B_NO_MEMORY);
422 
423 			PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
424 				fPackage, mode);
425 			if (symlink == NULL)
426 				RETURN_ERROR(B_NO_MEMORY);
427 
428 			symlink->SetSymlinkPath(path);
429 			node = symlink;
430 		} else if (S_ISDIR(mode)) {
431 			// directory
432 			node = new(std::nothrow) PackageDirectory(fPackage, mode);
433 		} else
434 			RETURN_ERROR(B_BAD_DATA);
435 
436 		if (node == NULL)
437 			RETURN_ERROR(B_NO_MEMORY);
438 		BReference<PackageNode> nodeReference(node, true);
439 
440 		String entryName;
441 		if (!entryName.SetTo(entry->Name()))
442 			RETURN_ERROR(B_NO_MEMORY);
443 
444 		status_t error = node->Init(parentDir, entryName);
445 		if (error != B_OK)
446 			RETURN_ERROR(error);
447 
448 		node->SetModifiedTime(entry->ModifiedTime());
449 
450 		// add it to the parent directory
451 		if (parentDir != NULL)
452 			parentDir->AddChild(node);
453 		else
454 			fPackage->AddNode(node);
455 
456 		entry->SetUserToken(node);
457 
458 		return B_OK;
459 	}
460 
461 	virtual status_t HandleEntryAttribute(BPackageEntryV1* entry,
462 		BPackageEntryAttributeV1* attribute)
463 	{
464 		if (fErrorOccurred)
465 			return B_OK;
466 
467 		PackageNode* node = (PackageNode*)entry->UserToken();
468 
469 		String name;
470 		if (!name.SetTo(attribute->Name()))
471 			RETURN_ERROR(B_NO_MEMORY);
472 
473 		PackageNodeAttribute* nodeAttribute = new(std::nothrow)
474 			PackageNodeAttribute(attribute->Type(),
475 			PackageData(attribute->Data()));
476 		if (nodeAttribute == NULL)
477 			RETURN_ERROR(B_NO_MEMORY)
478 
479 		nodeAttribute->Init(name);
480 		node->AddAttribute(nodeAttribute);
481 
482 		return B_OK;
483 	}
484 
485 	virtual status_t HandleEntryDone(BPackageEntryV1* entry)
486 	{
487 		return B_OK;
488 	}
489 
490 	virtual status_t HandlePackageAttribute(
491 		const BPackageInfoAttributeValue& value)
492 	{
493 		switch (value.attributeID) {
494 			case B_PACKAGE_INFO_NAME:
495 			{
496 				String name;
497 				if (!name.SetTo(value.string))
498 					return B_NO_MEMORY;
499 				fPackage->SetName(name);
500 				return B_OK;
501 			}
502 
503 			case B_PACKAGE_INFO_INSTALL_PATH:
504 			{
505 				String path;
506 				if (!path.SetTo(value.string))
507 					return B_NO_MEMORY;
508 				fPackage->SetInstallPath(path);
509 				return B_OK;
510 			}
511 
512 			case B_PACKAGE_INFO_VERSION:
513 			{
514 				::Version* version;
515 				status_t error = Version::Create(value.version.major,
516 					value.version.minor, value.version.micro,
517 					value.version.preRelease, value.version.revision, version);
518 				if (error != B_OK)
519 					RETURN_ERROR(error);
520 
521 				fPackage->SetVersion(version);
522 
523 				break;
524 			}
525 
526 			case B_PACKAGE_INFO_ARCHITECTURE:
527 				if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
528 					RETURN_ERROR(B_BAD_VALUE);
529 
530 				fPackage->SetArchitecture(
531 					(BPackageArchitecture)value.unsignedInt);
532 				break;
533 
534 			case B_PACKAGE_INFO_PROVIDES:
535 			{
536 				// create a version object, if a version is specified
537 				::Version* version = NULL;
538 				if (value.resolvable.haveVersion) {
539 					const BPackageVersionData& versionInfo
540 						= value.resolvable.version;
541 					status_t error = Version::Create(versionInfo.major,
542 						versionInfo.minor, versionInfo.micro,
543 						versionInfo.preRelease, versionInfo.revision, version);
544 					if (error != B_OK)
545 						RETURN_ERROR(error);
546 				}
547 				ObjectDeleter< ::Version> versionDeleter(version);
548 
549 				// create a version object, if a compatible version is specified
550 				::Version* compatibleVersion = NULL;
551 				if (value.resolvable.haveCompatibleVersion) {
552 					const BPackageVersionData& versionInfo
553 						= value.resolvable.compatibleVersion;
554 					status_t error = Version::Create(versionInfo.major,
555 						versionInfo.minor, versionInfo.micro,
556 						versionInfo.preRelease, versionInfo.revision,
557 						compatibleVersion);
558 					if (error != B_OK)
559 						RETURN_ERROR(error);
560 				}
561 				ObjectDeleter< ::Version> compatibleVersionDeleter(
562 					compatibleVersion);
563 
564 				// create the resolvable
565 				Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
566 				if (resolvable == NULL)
567 					RETURN_ERROR(B_NO_MEMORY);
568 				ObjectDeleter<Resolvable> resolvableDeleter(resolvable);
569 
570 				status_t error = resolvable->Init(value.resolvable.name,
571 					versionDeleter.Detach(), compatibleVersionDeleter.Detach());
572 				if (error != B_OK)
573 					RETURN_ERROR(error);
574 
575 				fPackage->AddResolvable(resolvableDeleter.Detach());
576 
577 				break;
578 			}
579 
580 			case B_PACKAGE_INFO_REQUIRES:
581 			{
582 				// create the dependency
583 				Dependency* dependency = new(std::nothrow) Dependency(fPackage);
584 				if (dependency == NULL)
585 					RETURN_ERROR(B_NO_MEMORY);
586 				ObjectDeleter<Dependency> dependencyDeleter(dependency);
587 
588 				status_t error = dependency->Init(
589 					value.resolvableExpression.name);
590 				if (error != B_OK)
591 					RETURN_ERROR(error);
592 
593 				// create a version object, if a version is specified
594 				::Version* version = NULL;
595 				if (value.resolvableExpression.haveOpAndVersion) {
596 					const BPackageVersionData& versionInfo
597 						= value.resolvableExpression.version;
598 					status_t error = Version::Create(versionInfo.major,
599 						versionInfo.minor, versionInfo.micro,
600 						versionInfo.preRelease, versionInfo.revision, version);
601 					if (error != B_OK)
602 						RETURN_ERROR(error);
603 
604 					dependency->SetVersionRequirement(
605 						value.resolvableExpression.op, version);
606 				}
607 
608 				fPackage->AddDependency(dependencyDeleter.Detach());
609 
610 				break;
611 			}
612 
613 			default:
614 				break;
615 		}
616 
617 		return B_OK;
618 	}
619 
620 	virtual void HandleErrorOccurred()
621 	{
622 		fErrorOccurred = true;
623 	}
624 
625 private:
626 	Package*	fPackage;
627 	bool		fErrorOccurred;
628 };
629 
630 
631 // #pragma mark - HeapReader
632 
633 
634 struct Package::HeapReader {
635 	virtual ~HeapReader()
636 	{
637 	}
638 
639 	virtual void UpdateFD(int fd) = 0;
640 
641 	virtual status_t CreateDataReader(const PackageData& data,
642 		BAbstractBufferedDataReader*& _reader) = 0;
643 };
644 
645 
646 // #pragma mark - HeapReaderV1
647 
648 
649 struct Package::HeapReaderV1 : public HeapReader, private BDataReader {
650 public:
651 	HeapReaderV1(int fd)
652 		:
653 		fFileReader(fd)
654 	{
655 	}
656 
657 	~HeapReaderV1()
658 	{
659 	}
660 
661 	virtual void UpdateFD(int fd)
662 	{
663 		fFileReader.SetFD(fd);
664 	}
665 
666 	virtual status_t CreateDataReader(const PackageData& data,
667 		BAbstractBufferedDataReader*& _reader)
668 	{
669 		return GlobalFactory::Default()->CreatePackageDataReader(this,
670 			data.DataV1(), _reader);
671 	}
672 
673 private:
674 	// BDataReader
675 
676 	virtual status_t ReadData(off_t offset, void* buffer, size_t size)
677 	{
678 		return fFileReader.ReadData(offset, buffer, size);
679 	}
680 
681 private:
682 	BFDDataReader	fFileReader;
683 };
684 
685 
686 // #pragma mark - HeapReaderV2
687 
688 
689 struct Package::HeapReaderV2 : public HeapReader, public CachedDataReader,
690 	private BErrorOutput {
691 public:
692 	HeapReaderV2()
693 		:
694 		fHeapReader(NULL)
695 	{
696 	}
697 
698 	~HeapReaderV2()
699 	{
700 		delete fHeapReader;
701 	}
702 
703 	status_t Init(const PackageFileHeapReader* heapReader, int fd)
704 	{
705 		fHeapReader = heapReader->Clone();
706 		if (fHeapReader == NULL)
707 			return B_NO_MEMORY;
708 
709 		fHeapReader->SetErrorOutput(this);
710 		fHeapReader->SetFD(fd);
711 
712 		status_t error = CachedDataReader::Init(fHeapReader,
713 			fHeapReader->UncompressedHeapSize());
714 		if (error != B_OK)
715 			return error;
716 
717 		return B_OK;
718 	}
719 
720 	virtual void UpdateFD(int fd)
721 	{
722 		fHeapReader->SetFD(fd);
723 	}
724 
725 	virtual status_t CreateDataReader(const PackageData& data,
726 		BAbstractBufferedDataReader*& _reader)
727 	{
728 		return BPackageKit::BHPKG::BPackageDataReaderFactory()
729 			.CreatePackageDataReader(this, data.DataV2(), _reader);
730 	}
731 
732 private:
733 	// BErrorOutput
734 
735 	virtual void PrintErrorVarArgs(const char* format, va_list args)
736 	{
737 		ERRORV(format, args);
738 	}
739 
740 private:
741 	PackageFileHeapReader*	fHeapReader;
742 };
743 
744 
745 // #pragma mark - Package
746 
747 
748 struct Package::CachingPackageReader : public PackageReaderImpl {
749 	CachingPackageReader(BErrorOutput* errorOutput)
750 		:
751 		PackageReaderImpl(errorOutput),
752 		fCachedHeapReader(NULL)
753 	{
754 	}
755 
756 	~CachingPackageReader()
757 	{
758 	}
759 
760 	virtual status_t CreateCachedHeapReader(
761 		PackageFileHeapReader* rawHeapReader,
762 		BAbstractBufferedDataReader*& _cachedReader)
763 	{
764 		fCachedHeapReader = new(std::nothrow) HeapReaderV2;
765 		if (fCachedHeapReader == NULL)
766 			RETURN_ERROR(B_NO_MEMORY);
767 
768 		status_t error = fCachedHeapReader->Init(rawHeapReader, FD());
769 		if (error != B_OK)
770 			RETURN_ERROR(error);
771 
772 		_cachedReader = fCachedHeapReader;
773 		return B_OK;
774 	}
775 
776 	HeapReaderV2* DetachCachedHeapReader()
777 	{
778 		DetachHeapReader();
779 
780 		HeapReaderV2* cachedHeapReader = fCachedHeapReader;
781 		fCachedHeapReader = NULL;
782 		return cachedHeapReader;
783 	}
784 
785 private:
786 	HeapReaderV2*	fCachedHeapReader;
787 };
788 
789 
790 // #pragma mark - Package
791 
792 
793 Package::Package(::Volume* volume, PackagesDirectory* directory, dev_t deviceID,
794 	ino_t nodeID)
795 	:
796 	fVolume(volume),
797 	fPackagesDirectory(directory),
798 	fFileName(),
799 	fName(),
800 	fInstallPath(),
801 	fVersionedName(),
802 	fVersion(NULL),
803 	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
804 	fLinkDirectory(NULL),
805 	fFD(-1),
806 	fOpenCount(0),
807 	fHeapReader(NULL),
808 	fNodeID(nodeID),
809 	fDeviceID(deviceID)
810 {
811 	mutex_init(&fLock, "packagefs package");
812 
813 	fPackagesDirectory->AcquireReference();
814 }
815 
816 
817 Package::~Package()
818 {
819 	delete fHeapReader;
820 
821 	while (PackageNode* node = fNodes.RemoveHead())
822 		node->ReleaseReference();
823 
824 	while (Resolvable* resolvable = fResolvables.RemoveHead())
825 		delete resolvable;
826 
827 	while (Dependency* dependency = fDependencies.RemoveHead())
828 		delete dependency;
829 
830 	delete fVersion;
831 
832 	fPackagesDirectory->ReleaseReference();
833 
834 	mutex_destroy(&fLock);
835 }
836 
837 
838 status_t
839 Package::Init(const char* fileName)
840 {
841 	if (!fFileName.SetTo(fileName))
842 		RETURN_ERROR(B_NO_MEMORY);
843 
844 	return B_OK;
845 }
846 
847 
848 status_t
849 Package::Load(const PackageSettings& settings)
850 {
851 	status_t error = _Load(settings);
852 	if (error != B_OK)
853 		return error;
854 
855 	if (!_InitVersionedName())
856 		RETURN_ERROR(B_NO_MEMORY);
857 
858 	return B_OK;
859 }
860 
861 
862 void
863 Package::SetName(const String& name)
864 {
865 	fName = name;
866 }
867 
868 
869 void
870 Package::SetInstallPath(const String& installPath)
871 {
872 	fInstallPath = installPath;
873 }
874 
875 
876 void
877 Package::SetVersion(::Version* version)
878 {
879 	if (fVersion != NULL)
880 		delete fVersion;
881 
882 	fVersion = version;
883 }
884 
885 
886 const char*
887 Package::ArchitectureName() const
888 {
889 	if (fArchitecture < 0
890 		|| fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
891 		return NULL;
892 	}
893 
894 	return kArchitectureNames[fArchitecture];
895 }
896 
897 
898 void
899 Package::AddNode(PackageNode* node)
900 {
901 	fNodes.Add(node);
902 	node->AcquireReference();
903 }
904 
905 
906 void
907 Package::AddResolvable(Resolvable* resolvable)
908 {
909 	fResolvables.Add(resolvable);
910 }
911 
912 
913 void
914 Package::AddDependency(Dependency* dependency)
915 {
916 	fDependencies.Add(dependency);
917 }
918 
919 
920 int
921 Package::Open()
922 {
923 	MutexLocker locker(fLock);
924 	if (fOpenCount > 0) {
925 		fOpenCount++;
926 		return fFD;
927 	}
928 
929 	// open the file
930 	fFD = openat(fPackagesDirectory->DirectoryFD(), fFileName, O_RDONLY);
931 	if (fFD < 0) {
932 		ERROR("Failed to open package file \"%s\"\n", fFileName.Data());
933 		return errno;
934 	}
935 
936 	// stat it to verify that it's still the same file
937 	struct stat st;
938 	if (fstat(fFD, &st) < 0) {
939 		ERROR("Failed to stat package file \"%s\"\n", fFileName.Data());
940 		close(fFD);
941 		fFD = -1;
942 		return errno;
943 	}
944 
945 	if (st.st_dev != fDeviceID || st.st_ino != fNodeID) {
946 		close(fFD);
947 		fFD = -1;
948 		RETURN_ERROR(B_ENTRY_NOT_FOUND);
949 	}
950 
951 	fOpenCount = 1;
952 
953 	if (fHeapReader != NULL)
954 		fHeapReader->UpdateFD(fFD);
955 
956 	return fFD;
957 }
958 
959 
960 void
961 Package::Close()
962 {
963 	MutexLocker locker(fLock);
964 	if (fOpenCount == 0) {
965 		ERROR("Package open count already 0!\n");
966 		return;
967 	}
968 
969 	if (--fOpenCount == 0) {
970 		close(fFD);
971 		fFD = -1;
972 
973 		if (fHeapReader != NULL)
974 			fHeapReader->UpdateFD(fFD);
975 	}
976 }
977 
978 
979 status_t
980 Package::CreateDataReader(const PackageData& data,
981 	BAbstractBufferedDataReader*& _reader)
982 {
983 	if (fHeapReader == NULL)
984 		return B_BAD_VALUE;
985 
986 	return fHeapReader->CreateDataReader(data, _reader);
987 }
988 
989 
990 status_t
991 Package::_Load(const PackageSettings& settings)
992 {
993 	// open package file
994 	int fd = Open();
995 	if (fd < 0)
996 		RETURN_ERROR(fd);
997 	PackageCloser packageCloser(this);
998 
999 	// initialize package reader
1000 	LoaderErrorOutput errorOutput(this);
1001 
1002 	// try current package file format version
1003 	{
1004 		CachingPackageReader packageReader(&errorOutput);
1005 		status_t error = packageReader.Init(fd, false,
1006 			BHPKG::B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE);
1007 		if (error == B_OK) {
1008 			// parse content
1009 			LoaderContentHandler handler(this, settings);
1010 			error = handler.Init();
1011 			if (error != B_OK)
1012 				RETURN_ERROR(error);
1013 
1014 			error = packageReader.ParseContent(&handler);
1015 			if (error != B_OK)
1016 				RETURN_ERROR(error);
1017 
1018 			// get the heap reader
1019 			fHeapReader = packageReader.DetachCachedHeapReader();
1020 			return B_OK;
1021 		}
1022 
1023 		if (error != B_MISMATCHED_VALUES)
1024 			RETURN_ERROR(error);
1025 	}
1026 
1027 	// try package file format version 1
1028 	PackageReaderImplV1 packageReader(&errorOutput);
1029 	status_t error = packageReader.Init(fd, false);
1030 	if (error != B_OK)
1031 		RETURN_ERROR(error);
1032 
1033 	// parse content
1034 	LoaderContentHandlerV1 handler(this);
1035 	error = handler.Init();
1036 	if (error != B_OK)
1037 		RETURN_ERROR(error);
1038 
1039 	error = packageReader.ParseContent(&handler);
1040 	if (error != B_OK)
1041 		RETURN_ERROR(error);
1042 
1043 	// create a heap reader
1044 	fHeapReader = new(std::nothrow) HeapReaderV1(fd);
1045 	if (fHeapReader == NULL)
1046 		RETURN_ERROR(B_NO_MEMORY);
1047 
1048 	return B_OK;
1049 }
1050 
1051 
1052 bool
1053 Package::_InitVersionedName()
1054 {
1055 	// compute the allocation size needed for the versioned name
1056 	size_t nameLength = strlen(fName);
1057 	size_t size = nameLength + 1;
1058 
1059 	if (fVersion != NULL) {
1060 		size += 1 + fVersion->ToString(NULL, 0);
1061 			// + 1 for the '-'
1062 	}
1063 
1064 	// allocate the name and compose it
1065 	char* name = (char*)malloc(size);
1066 	if (name == NULL)
1067 		return false;
1068 	MemoryDeleter nameDeleter(name);
1069 
1070 	memcpy(name, fName, nameLength + 1);
1071 	if (fVersion != NULL) {
1072 		name[nameLength] = '-';
1073 		fVersion->ToString(name + nameLength + 1, size - nameLength - 1);
1074 	}
1075 
1076 	return fVersionedName.SetTo(name);
1077 }
1078