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