1cc32c484SIngo Weinhold/*
232832cbeSIngo Weinhold * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3cc32c484SIngo Weinhold * Distributed under the terms of the MIT License.
4cc32c484SIngo Weinhold */
5cc32c484SIngo Weinhold
6cc32c484SIngo Weinhold
7cc32c484SIngo Weinhold#include "Package.h"
8cc32c484SIngo Weinhold
9744a460cSIngo Weinhold#include <errno.h>
10744a460cSIngo Weinhold#include <fcntl.h>
11cc32c484SIngo Weinhold#include <stdlib.h>
12cc32c484SIngo Weinhold#include <string.h>
13744a460cSIngo Weinhold#include <unistd.h>
14744a460cSIngo Weinhold
15e85e9dadSIngo Weinhold#include <package/hpkg/ErrorOutput.h>
161f633814SIngo Weinhold#include <package/hpkg/PackageDataReader.h>
17e85e9dadSIngo Weinhold#include <package/hpkg/PackageEntry.h>
18e85e9dadSIngo Weinhold#include <package/hpkg/PackageEntryAttribute.h>
191f633814SIngo Weinhold
201f633814SIngo Weinhold#include <AutoDeleter.h>
21e527b796SIngo Weinhold#include <FdIO.h>
221f633814SIngo Weinhold#include <package/hpkg/PackageFileHeapReader.h>
231f633814SIngo Weinhold#include <package/hpkg/PackageReaderImpl.h>
24744a460cSIngo Weinhold#include <util/AutoLock.h>
25cc32c484SIngo Weinhold
2646122852SIngo Weinhold#include "CachedDataReader.h"
27cc32c484SIngo Weinhold#include "DebugSupport.h"
28e85e9dadSIngo Weinhold#include "PackageDirectory.h"
29e85e9dadSIngo Weinhold#include "PackageFile.h"
30dff8d2eaSIngo Weinhold#include "PackagesDirectory.h"
313a7e0b00SIngo Weinhold#include "PackageSettings.h"
32e85e9dadSIngo Weinhold#include "PackageSymlink.h"
3301102ee5SIngo Weinhold#include "Version.h"
346978941aSIngo Weinhold#include "Volume.h"
35cc32c484SIngo Weinhold
36cc32c484SIngo Weinhold
37e85e9dadSIngo Weinholdusing namespace BPackageKit;
3811cecf98SIngo Weinhold
391f633814SIngo Weinholdusing BPackageKit::BHPKG::BErrorOutput;
401f633814SIngo Weinholdusing BPackageKit::BHPKG::BFDDataReader;
411f633814SIngo Weinholdusing BPackageKit::BHPKG::BPackageInfoAttributeValue;
421f633814SIngo Weinholdusing BPackageKit::BHPKG::BPackageVersionData;
431f633814SIngo Weinholdusing BPackageKit::BHPKG::BPrivate::PackageFileHeapReader;
4411cecf98SIngo Weinhold
4511cecf98SIngo Weinhold// current format version types
4611cecf98SIngo Weinholdtypedef BPackageKit::BHPKG::BPackageContentHandler BPackageContentHandler;
4711cecf98SIngo Weinholdtypedef BPackageKit::BHPKG::BPackageEntry BPackageEntry;
4811cecf98SIngo Weinholdtypedef BPackageKit::BHPKG::BPackageEntryAttribute BPackageEntryAttribute;
4911cecf98SIngo Weinholdtypedef BPackageKit::BHPKG::BPrivate::PackageReaderImpl PackageReaderImpl;
5011cecf98SIngo Weinhold
51e85e9dadSIngo Weinhold
52eadc3c84SIngo Weinholdconst char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
53eadc3c84SIngo Weinhold	"any",
54eadc3c84SIngo Weinhold	"x86",
55eadc3c84SIngo Weinhold	"x86_gcc2",
565dae1541SIngo Weinhold	"source",
57624ba548SFrançois Revol	"x86_64",
58624ba548SFrançois Revol	"ppc",
59624ba548SFrançois Revol	"arm",
60a6a6e3a8SAdrien Destugues	"m68k",
61a6a6e3a8SAdrien Destugues	"sparc",
62a6a6e3a8SAdrien Destugues	"arm64",
63a6a6e3a8SAdrien Destugues	"riscv64"
64eadc3c84SIngo Weinhold};
65eadc3c84SIngo Weinhold
66eadc3c84SIngo Weinhold
67e85e9dadSIngo Weinhold// #pragma mark - LoaderErrorOutput
68e85e9dadSIngo Weinhold
69e85e9dadSIngo Weinhold
70e85e9dadSIngo Weinholdstruct Package::LoaderErrorOutput : BErrorOutput {
71e85e9dadSIngo Weinhold	LoaderErrorOutput(Package* package)
72e85e9dadSIngo Weinhold		:
73e85e9dadSIngo Weinhold		fPackage(package)
74e85e9dadSIngo Weinhold	{
75e85e9dadSIngo Weinhold	}
76e85e9dadSIngo Weinhold
77e85e9dadSIngo Weinhold	virtual void PrintErrorVarArgs(const char* format, va_list args)
78e85e9dadSIngo Weinhold	{
792a6f1725SIngo Weinhold		ERRORV(format, args);
80e85e9dadSIngo Weinhold	}
81e85e9dadSIngo Weinhold
82e85e9dadSIngo Weinholdprivate:
83e85e9dadSIngo Weinhold	Package*	fPackage;
84e85e9dadSIngo Weinhold};
85e85e9dadSIngo Weinhold
86e85e9dadSIngo Weinhold
87e85e9dadSIngo Weinhold// #pragma mark - LoaderContentHandler
88e85e9dadSIngo Weinhold
89e85e9dadSIngo Weinhold
90e85e9dadSIngo Weinholdstruct Package::LoaderContentHandler : BPackageContentHandler {
913a7e0b00SIngo Weinhold	LoaderContentHandler(Package* package, const PackageSettings& settings)
92e85e9dadSIngo Weinhold		:
93e85e9dadSIngo Weinhold		fPackage(package),
943a7e0b00SIngo Weinhold		fSettings(settings),
953a7e0b00SIngo Weinhold		fSettingsItem(NULL),
963a7e0b00SIngo Weinhold		fLastSettingsEntry(NULL),
973a7e0b00SIngo Weinhold		fLastSettingsEntryEntry(NULL),
98e85e9dadSIngo Weinhold		fErrorOccurred(false)
99e85e9dadSIngo Weinhold	{
100e85e9dadSIngo Weinhold	}
101e85e9dadSIngo Weinhold
102e85e9dadSIngo Weinhold	status_t Init()
103e85e9dadSIngo Weinhold	{
104e85e9dadSIngo Weinhold		return B_OK;
105e85e9dadSIngo Weinhold	}
106e85e9dadSIngo Weinhold
107e85e9dadSIngo Weinhold	virtual status_t HandleEntry(BPackageEntry* entry)
108e85e9dadSIngo Weinhold	{
1093a7e0b00SIngo Weinhold		if (fErrorOccurred
1103a7e0b00SIngo Weinhold			|| (fLastSettingsEntry != NULL
1113a7e0b00SIngo Weinhold				&& fLastSettingsEntry->IsBlackListed())) {
112e85e9dadSIngo Weinhold			return B_OK;
1133a7e0b00SIngo Weinhold		}
114e85e9dadSIngo Weinhold
115e85e9dadSIngo Weinhold		PackageDirectory* parentDir = NULL;
116e85e9dadSIngo Weinhold		if (entry->Parent() != NULL) {
117e85e9dadSIngo Weinhold			parentDir = dynamic_cast<PackageDirectory*>(
118e85e9dadSIngo Weinhold				(PackageNode*)entry->Parent()->UserToken());
119e85e9dadSIngo Weinhold			if (parentDir == NULL)
120e85e9dadSIngo Weinhold				RETURN_ERROR(B_BAD_DATA);
121e85e9dadSIngo Weinhold		}
122e85e9dadSIngo Weinhold
1233a7e0b00SIngo Weinhold		if (fSettingsItem != NULL
1243a7e0b00SIngo Weinhold			&& (parentDir == NULL
1253a7e0b00SIngo Weinhold				|| entry->Parent() == fLastSettingsEntryEntry)) {
1263a7e0b00SIngo Weinhold			PackageSettingsItem::Entry* settingsEntry
1273a7e0b00SIngo Weinhold				= fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name());
1283a7e0b00SIngo Weinhold			if (settingsEntry != NULL) {
1293a7e0b00SIngo Weinhold				fLastSettingsEntry = settingsEntry;
1303a7e0b00SIngo Weinhold				fLastSettingsEntryEntry = entry;
1313a7e0b00SIngo Weinhold				if (fLastSettingsEntry->IsBlackListed())
1323a7e0b00SIngo Weinhold					return B_OK;
1333a7e0b00SIngo Weinhold			}
1343a7e0b00SIngo Weinhold		}
1353a7e0b00SIngo Weinhold
136e85e9dadSIngo Weinhold		// get the file mode -- filter out write permissions
137e85e9dadSIngo Weinhold		mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
138e85e9dadSIngo Weinhold
139e85e9dadSIngo Weinhold		// create the package node
140e85e9dadSIngo Weinhold		PackageNode* node;
141e85e9dadSIngo Weinhold		if (S_ISREG(mode)) {
142e85e9dadSIngo Weinhold			// file
143d230b5fdSAugustin Cavalier			node = new PackageFile(fPackage, mode,
14411cecf98SIngo Weinhold				PackageData(entry->Data()));
145e85e9dadSIngo Weinhold		} else if (S_ISLNK(mode)) {
146e85e9dadSIngo Weinhold			// symlink
147d07c930cSIngo Weinhold			String path;
148d07c930cSIngo Weinhold			if (!path.SetTo(entry->SymlinkPath()))
149d07c930cSIngo Weinhold				RETURN_ERROR(B_NO_MEMORY);
150d07c930cSIngo Weinhold
151e85e9dadSIngo Weinhold			PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
152e85e9dadSIngo Weinhold				fPackage, mode);
153e85e9dadSIngo Weinhold			if (symlink == NULL)
154e85e9dadSIngo Weinhold				RETURN_ERROR(B_NO_MEMORY);
155e85e9dadSIngo Weinhold
156d07c930cSIngo Weinhold			symlink->SetSymlinkPath(path);
157e85e9dadSIngo Weinhold			node = symlink;
158e85e9dadSIngo Weinhold		} else if (S_ISDIR(mode)) {
159e85e9dadSIngo Weinhold			// directory
160d230b5fdSAugustin Cavalier			node = new PackageDirectory(fPackage, mode);
161e85e9dadSIngo Weinhold		} else
162e85e9dadSIngo Weinhold			RETURN_ERROR(B_BAD_DATA);
163e85e9dadSIngo Weinhold
164e85e9dadSIngo Weinhold		if (node == NULL)
165e85e9dadSIngo Weinhold			RETURN_ERROR(B_NO_MEMORY);
166e85e9dadSIngo Weinhold		BReference<PackageNode> nodeReference(node, true);
167e85e9dadSIngo Weinhold
168d07c930cSIngo Weinhold		String entryName;
169d07c930cSIngo Weinhold		if (!entryName.SetTo(entry->Name()))
170d07c930cSIngo Weinhold			RETURN_ERROR(B_NO_MEMORY);
171d07c930cSIngo Weinhold
172d07c930cSIngo Weinhold		status_t error = node->Init(parentDir, entryName);
173e85e9dadSIngo Weinhold		if (error != B_OK)
174e85e9dadSIngo Weinhold			RETURN_ERROR(error);
175e85e9dadSIngo Weinhold
176e85e9dadSIngo Weinhold		node->SetModifiedTime(entry->ModifiedTime());
177e85e9dadSIngo Weinhold
178e85e9dadSIngo Weinhold		// add it to the parent directory
179e85e9dadSIngo Weinhold		if (parentDir != NULL)
180e85e9dadSIngo Weinhold			parentDir->AddChild(node);
181e85e9dadSIngo Weinhold		else
182e85e9dadSIngo Weinhold			fPackage->AddNode(node);
183e85e9dadSIngo Weinhold
184e85e9dadSIngo Weinhold		entry->SetUserToken(node);
185e85e9dadSIngo Weinhold
186e85e9dadSIngo Weinhold		return B_OK;
187e85e9dadSIngo Weinhold	}
188e85e9dadSIngo Weinhold
189e85e9dadSIngo Weinhold	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
190e85e9dadSIngo Weinhold		BPackageEntryAttribute* attribute)
191e85e9dadSIngo Weinhold	{
1923a7e0b00SIngo Weinhold		if (fErrorOccurred
1933a7e0b00SIngo Weinhold			|| (fLastSettingsEntry != NULL
1943a7e0b00SIngo Weinhold				&& fLastSettingsEntry->IsBlackListed())) {
195e85e9dadSIngo Weinhold			return B_OK;
1963a7e0b00SIngo Weinhold		}
197e85e9dadSIngo Weinhold
198e85e9dadSIngo Weinhold		PackageNode* node = (PackageNode*)entry->UserToken();
199e85e9dadSIngo Weinhold
200d07c930cSIngo Weinhold		String name;
201d07c930cSIngo Weinhold		if (!name.SetTo(attribute->Name()))
202d07c930cSIngo Weinhold			RETURN_ERROR(B_NO_MEMORY);
203d07c930cSIngo Weinhold
204d230b5fdSAugustin Cavalier		PackageNodeAttribute* nodeAttribute = new
20511cecf98SIngo Weinhold			PackageNodeAttribute(attribute->Type(),
20611cecf98SIngo Weinhold			PackageData(attribute->Data()));
207e85e9dadSIngo Weinhold		if (nodeAttribute == NULL)
208e85e9dadSIngo Weinhold			RETURN_ERROR(B_NO_MEMORY)
209e85e9dadSIngo Weinhold
210d07c930cSIngo Weinhold		nodeAttribute->Init(name);
211e85e9dadSIngo Weinhold		node->AddAttribute(nodeAttribute);
212e85e9dadSIngo Weinhold
213e85e9dadSIngo Weinhold		return B_OK;
214e85e9dadSIngo Weinhold	}
215e85e9dadSIngo Weinhold
216e85e9dadSIngo Weinhold	virtual status_t HandleEntryDone(BPackageEntry* entry)
217e85e9dadSIngo Weinhold	{
2183a7e0b00SIngo Weinhold		if (entry == fLastSettingsEntryEntry) {
2193a7e0b00SIngo Weinhold			fLastSettingsEntryEntry = entry->Parent();
2203a7e0b00SIngo Weinhold			fLastSettingsEntry = fLastSettingsEntry->Parent();
2213a7e0b00SIngo Weinhold		}
2223a7e0b00SIngo Weinhold
223e85e9dadSIngo Weinhold		return B_OK;
224e85e9dadSIngo Weinhold	}
225e85e9dadSIngo Weinhold
226e85e9dadSIngo Weinhold	virtual status_t HandlePackageAttribute(
227e85e9dadSIngo Weinhold		const BPackageInfoAttributeValue& value)
228e85e9dadSIngo Weinhold	{
229e85e9dadSIngo Weinhold		switch (value.attributeID) {
230e85e9dadSIngo Weinhold			case B_PACKAGE_INFO_NAME:
231d07c930cSIngo Weinhold			{
232d07c930cSIngo Weinhold				String name;
233d07c930cSIngo Weinhold				if (!name.SetTo(value.string))
234d07c930cSIngo Weinhold					return B_NO_MEMORY;
235d07c930cSIngo Weinhold				fPackage->SetName(name);
2363a7e0b00SIngo Weinhold
2373a7e0b00SIngo Weinhold				fSettingsItem = fSettings.PackageItemFor(fPackage->Name());
2383a7e0b00SIngo Weinhold
239d07c930cSIngo Weinhold				return B_OK;
240d07c930cSIngo Weinhold			}
241e85e9dadSIngo Weinhold
242e85e9dadSIngo Weinhold			case B_PACKAGE_INFO_INSTALL_PATH:
243d07c930cSIngo Weinhold			{
244d07c930cSIngo Weinhold				String path;
245d07c930cSIngo Weinhold				if (!path.SetTo(value.string))
246d07c930cSIngo Weinhold					return B_NO_MEMORY;
247d07c930cSIngo Weinhold				fPackage->SetInstallPath(path);
248d07c930cSIngo Weinhold				return B_OK;
249d07c930cSIngo Weinhold			}
250e85e9dadSIngo Weinhold
251e85e9dadSIngo Weinhold			case B_PACKAGE_INFO_VERSION:
252e85e9dadSIngo Weinhold			{
253e85e9dadSIngo Weinhold				::Version* version;
254e85e9dadSIngo Weinhold				status_t error = Version::Create(value.version.major,
255e85e9dadSIngo Weinhold					value.version.minor, value.version.micro,
256202c1daaSIngo Weinhold					value.version.preRelease, value.version.revision, version);
257e85e9dadSIngo Weinhold				if (error != B_OK)
258e85e9dadSIngo Weinhold					RETURN_ERROR(error);
259e85e9dadSIngo Weinhold
260e85e9dadSIngo Weinhold				fPackage->SetVersion(version);
261e85e9dadSIngo Weinhold				break;
262e85e9dadSIngo Weinhold			}
263e85e9dadSIngo Weinhold
264abf0c287SAugustin Cavalier			case B_PACKAGE_INFO_FLAGS:
265abf0c287SAugustin Cavalier				fPackage->SetFlags(value.unsignedInt);
266abf0c287SAugustin Cavalier				break;
267abf0c287SAugustin Cavalier
268e85e9dadSIngo Weinhold			case B_PACKAGE_INFO_ARCHITECTURE:
269e85e9dadSIngo Weinhold				if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
270e85e9dadSIngo Weinhold					RETURN_ERROR(B_BAD_VALUE);
271e85e9dadSIngo Weinhold
272e85e9dadSIngo Weinhold				fPackage->SetArchitecture(
273e85e9dadSIngo Weinhold					(BPackageArchitecture)value.unsignedInt);
274e85e9dadSIngo Weinhold				break;
275e85e9dadSIngo Weinhold
276e85e9dadSIngo Weinhold			case B_PACKAGE_INFO_PROVIDES:
277e85e9dadSIngo Weinhold			{
278e85e9dadSIngo Weinhold				// create a version object, if a version is specified
279e85e9dadSIngo Weinhold				::Version* version = NULL;
280e85e9dadSIngo Weinhold				if (value.resolvable.haveVersion) {
281e85e9dadSIngo Weinhold					const BPackageVersionData& versionInfo
282e85e9dadSIngo Weinhold						= value.resolvable.version;
283e85e9dadSIngo Weinhold					status_t error = Version::Create(versionInfo.major,
284e85e9dadSIngo Weinhold						versionInfo.minor, versionInfo.micro,
285202c1daaSIngo Weinhold						versionInfo.preRelease, versionInfo.revision, version);
286e85e9dadSIngo Weinhold					if (error != B_OK)
287e85e9dadSIngo Weinhold						RETURN_ERROR(error);
288e85e9dadSIngo Weinhold				}
289e85e9dadSIngo Weinhold				ObjectDeleter< ::Version> versionDeleter(version);
290e85e9dadSIngo Weinhold
291e85e9dadSIngo Weinhold				// create a version object, if a compatible version is specified
292e85e9dadSIngo Weinhold				::Version* compatibleVersion = NULL;
293e85e9dadSIngo Weinhold				if (value.resolvable.haveCompatibleVersion) {
294e85e9dadSIngo Weinhold					const BPackageVersionData& versionInfo
295e85e9dadSIngo Weinhold						= value.resolvable.compatibleVersion;
296e85e9dadSIngo Weinhold					status_t error = Version::Create(versionInfo.major,
297e85e9dadSIngo Weinhold						versionInfo.minor, versionInfo.micro,
298202c1daaSIngo Weinhold						versionInfo.preRelease, versionInfo.revision,
299e85e9dadSIngo Weinhold						compatibleVersion);
300e85e9dadSIngo Weinhold					if (error != B_OK)
301e85e9dadSIngo Weinhold						RETURN_ERROR(error);
302e85e9dadSIngo Weinhold				}
303e85e9dadSIngo Weinhold				ObjectDeleter< ::Version> compatibleVersionDeleter(
304e85e9dadSIngo Weinhold					compatibleVersion);
305e85e9dadSIngo Weinhold
306e85e9dadSIngo Weinhold				// create the resolvable
307e85e9dadSIngo Weinhold				Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
308e85e9dadSIngo Weinhold				if (resolvable == NULL)
309e85e9dadSIngo Weinhold					RETURN_ERROR(B_NO_MEMORY);
310e85e9dadSIngo Weinhold				ObjectDeleter<Resolvable> resolvableDeleter(resolvable);
311e85e9dadSIngo Weinhold
312e85e9dadSIngo Weinhold				status_t error = resolvable->Init(value.resolvable.name,
313e85e9dadSIngo Weinhold					versionDeleter.Detach(), compatibleVersionDeleter.Detach());
314e85e9dadSIngo Weinhold				if (error != B_OK)
315e85e9dadSIngo Weinhold					RETURN_ERROR(error);
316e85e9dadSIngo Weinhold
317e85e9dadSIngo Weinhold				fPackage->AddResolvable(resolvableDeleter.Detach());
318e85e9dadSIngo Weinhold
319e85e9dadSIngo Weinhold				break;
320e85e9dadSIngo Weinhold			}
321e85e9dadSIngo Weinhold
322e85e9dadSIngo Weinhold			case B_PACKAGE_INFO_REQUIRES:
323e85e9dadSIngo Weinhold			{
324e85e9dadSIngo Weinhold				// create the dependency
325e85e9dadSIngo Weinhold				Dependency* dependency = new(std::nothrow) Dependency(fPackage);
326e85e9dadSIngo Weinhold				if (dependency == NULL)
327e85e9dadSIngo Weinhold					RETURN_ERROR(B_NO_MEMORY);
328e85e9dadSIngo Weinhold				ObjectDeleter<Dependency> dependencyDeleter(dependency);
329e85e9dadSIngo Weinhold
330e85e9dadSIngo Weinhold				status_t error = dependency->Init(
331e85e9dadSIngo Weinhold					value.resolvableExpression.name);
332e85e9dadSIngo Weinhold				if (error != B_OK)
333e85e9dadSIngo Weinhold					RETURN_ERROR(error);
334e85e9dadSIngo Weinhold
335e85e9dadSIngo Weinhold				// create a version object, if a version is specified
336e85e9dadSIngo Weinhold				::Version* version = NULL;
337e85e9dadSIngo Weinhold				if (value.resolvableExpression.haveOpAndVersion) {
338e85e9dadSIngo Weinhold					const BPackageVersionData& versionInfo
339e85e9dadSIngo Weinhold						= value.resolvableExpression.version;
340e85e9dadSIngo Weinhold					status_t error = Version::Create(versionInfo.major,
341e85e9dadSIngo Weinhold						versionInfo.minor, versionInfo.micro,
342202c1daaSIngo Weinhold						versionInfo.preRelease, versionInfo.revision, version);
343e85e9dadSIngo Weinhold					if (error != B_OK)
344e85e9dadSIngo Weinhold						RETURN_ERROR(error);
345e85e9dadSIngo Weinhold
346e85e9dadSIngo Weinhold					dependency->SetVersionRequirement(
347e85e9dadSIngo Weinhold						value.resolvableExpression.op, version);
348e85e9dadSIngo Weinhold				}
349e85e9dadSIngo Weinhold
350e85e9dadSIngo Weinhold				fPackage->AddDependency(dependencyDeleter.Detach());
351e85e9dadSIngo Weinhold
352e85e9dadSIngo Weinhold				break;
353e85e9dadSIngo Weinhold			}
354e85e9dadSIngo Weinhold
355e85e9dadSIngo Weinhold			default:
356e85e9dadSIngo Weinhold				break;
357e85e9dadSIngo Weinhold		}
358e85e9dadSIngo Weinhold
359e85e9dadSIngo Weinhold		return B_OK;
360e85e9dadSIngo Weinhold	}
361e85e9dadSIngo Weinhold
362e85e9dadSIngo Weinhold	virtual void HandleErrorOccurred()
363e85e9dadSIngo Weinhold	{
364e85e9dadSIngo Weinhold		fErrorOccurred = true;
365e85e9dadSIngo Weinhold	}
366e85e9dadSIngo Weinhold
367e85e9dadSIngo Weinholdprivate:
3683a7e0b00SIngo Weinhold	Package*					fPackage;
3693a7e0b00SIngo Weinhold	const PackageSettings&		fSettings;
3703a7e0b00SIngo Weinhold	const PackageSettingsItem*	fSettingsItem;
3713a7e0b00SIngo Weinhold	PackageSettingsItem::Entry*	fLastSettingsEntry;
3723a7e0b00SIngo Weinhold	const BPackageEntry*		fLastSettingsEntryEntry;
3733a7e0b00SIngo Weinhold	bool						fErrorOccurred;
374e85e9dadSIngo Weinhold};
375e85e9dadSIngo Weinhold
376e85e9dadSIngo Weinhold
3771f633814SIngo Weinhold// #pragma mark - HeapReader
3781f633814SIngo Weinhold
3791f633814SIngo Weinhold
3801f633814SIngo Weinholdstruct Package::HeapReader {
3811f633814SIngo Weinhold	virtual ~HeapReader()
3821f633814SIngo Weinhold	{
3831f633814SIngo Weinhold	}
3841f633814SIngo Weinhold
3851f633814SIngo Weinhold	virtual void UpdateFD(int fd) = 0;
3861f633814SIngo Weinhold
3871f633814SIngo Weinhold	virtual status_t CreateDataReader(const PackageData& data,
3881f633814SIngo Weinhold		BAbstractBufferedDataReader*& _reader) = 0;
3891f633814SIngo Weinhold};
3901f633814SIngo Weinhold
3911f633814SIngo Weinhold
3921f633814SIngo Weinhold// #pragma mark - HeapReaderV2
3931f633814SIngo Weinhold
3941f633814SIngo Weinhold
39546122852SIngo Weinholdstruct Package::HeapReaderV2 : public HeapReader, public CachedDataReader,
396e527b796SIngo Weinhold	private BErrorOutput, private BFdIO {
3971f633814SIngo Weinholdpublic:
3981f633814SIngo Weinhold	HeapReaderV2()
3991f633814SIngo Weinhold		:
4001f633814SIngo Weinhold		fHeapReader(NULL)
4011f633814SIngo Weinhold	{
4021f633814SIngo Weinhold	}
4031f633814SIngo Weinhold
4041f633814SIngo Weinhold	~HeapReaderV2()
4051f633814SIngo Weinhold	{
4061f633814SIngo Weinhold		delete fHeapReader;
4071f633814SIngo Weinhold	}
4081f633814SIngo Weinhold
4091f633814SIngo Weinhold	status_t Init(const PackageFileHeapReader* heapReader, int fd)
4101f633814SIngo Weinhold	{
4111f633814SIngo Weinhold		fHeapReader = heapReader->Clone();
4121f633814SIngo Weinhold		if (fHeapReader == NULL)
4131f633814SIngo Weinhold			return B_NO_MEMORY;
4141f633814SIngo Weinhold
415e527b796SIngo Weinhold		BFdIO::SetTo(fd, false);
416e527b796SIngo Weinhold
4171f633814SIngo Weinhold		fHeapReader->SetErrorOutput(this);
418e527b796SIngo Weinhold		fHeapReader->SetFile(this);
4191f633814SIngo Weinhold
42046122852SIngo Weinhold		status_t error = CachedDataReader::Init(fHeapReader,
42146122852SIngo Weinhold			fHeapReader->UncompressedHeapSize());
42246122852SIngo Weinhold		if (error != B_OK)
42346122852SIngo Weinhold			return error;
42446122852SIngo Weinhold
4251f633814SIngo Weinhold		return B_OK;
4261f633814SIngo Weinhold	}
4271f633814SIngo Weinhold
4281f633814SIngo Weinhold	virtual void UpdateFD(int fd)
4291f633814SIngo Weinhold	{
430e527b796SIngo Weinhold		BFdIO::SetTo(fd, false);
4311f633814SIngo Weinhold	}
4321f633814SIngo Weinhold
4331f633814SIngo Weinhold	virtual status_t CreateDataReader(const PackageData& data,
4341f633814SIngo Weinhold		BAbstractBufferedDataReader*& _reader)
4351f633814SIngo Weinhold	{
4361f633814SIngo Weinhold		return BPackageKit::BHPKG::BPackageDataReaderFactory()
4371f633814SIngo Weinhold			.CreatePackageDataReader(this, data.DataV2(), _reader);
4381f633814SIngo Weinhold	}
4391f633814SIngo Weinhold
4401f633814SIngo Weinholdprivate:
44146122852SIngo Weinhold	// BErrorOutput
4421f633814SIngo Weinhold
44346122852SIngo Weinhold	virtual void PrintErrorVarArgs(const char* format, va_list args)
4441f633814SIngo Weinhold	{
44546122852SIngo Weinhold		ERRORV(format, args);
4461f633814SIngo Weinhold	}
4471f633814SIngo Weinhold
44846122852SIngo Weinholdprivate:
44946122852SIngo Weinhold	PackageFileHeapReader*	fHeapReader;
45046122852SIngo Weinhold};
45146122852SIngo Weinhold
45246122852SIngo Weinhold
45346122852SIngo Weinhold// #pragma mark - Package
45446122852SIngo Weinhold
45546122852SIngo Weinhold
45646122852SIngo Weinholdstruct Package::CachingPackageReader : public PackageReaderImpl {
45746122852SIngo Weinhold	CachingPackageReader(BErrorOutput* errorOutput)
45846122852SIngo Weinhold		:
45946122852SIngo Weinhold		PackageReaderImpl(errorOutput),
460e527b796SIngo Weinhold		fCachedHeapReader(NULL),
461e527b796SIngo Weinhold		fFD(-1)
4621f633814SIngo Weinhold	{
4631f633814SIngo Weinhold	}
4641f633814SIngo Weinhold
46546122852SIngo Weinhold	~CachingPackageReader()
46646122852SIngo Weinhold	{
46746122852SIngo Weinhold	}
4681f633814SIngo Weinhold
469e527b796SIngo Weinhold	status_t Init(int fd, bool keepFD, uint32 flags)
470e527b796SIngo Weinhold	{
471e527b796SIngo Weinhold		fFD = fd;
472e527b796SIngo Weinhold		return PackageReaderImpl::Init(fd, keepFD, flags);
473e527b796SIngo Weinhold	}
474e527b796SIngo Weinhold
47546122852SIngo Weinhold	virtual status_t CreateCachedHeapReader(
47646122852SIngo Weinhold		PackageFileHeapReader* rawHeapReader,
47746122852SIngo Weinhold		BAbstractBufferedDataReader*& _cachedReader)
4781f633814SIngo Weinhold	{
47946122852SIngo Weinhold		fCachedHeapReader = new(std::nothrow) HeapReaderV2;
48046122852SIngo Weinhold		if (fCachedHeapReader == NULL)
48146122852SIngo Weinhold			RETURN_ERROR(B_NO_MEMORY);
48246122852SIngo Weinhold
483e527b796SIngo Weinhold		status_t error = fCachedHeapReader->Init(rawHeapReader, fFD);
48446122852SIngo Weinhold		if (error != B_OK)
48546122852SIngo Weinhold			RETURN_ERROR(error);
48646122852SIngo Weinhold
48746122852SIngo Weinhold		_cachedReader = fCachedHeapReader;
48846122852SIngo Weinhold		return B_OK;
48946122852SIngo Weinhold	}
49046122852SIngo Weinhold
49146122852SIngo Weinhold	HeapReaderV2* DetachCachedHeapReader()
49246122852SIngo Weinhold	{
493e527b796SIngo Weinhold		PackageFileHeapReader* rawHeapReader;
494e527b796SIngo Weinhold		DetachHeapReader(rawHeapReader);
495e527b796SIngo Weinhold
496e527b796SIngo Weinhold		// We don't need the raw heap reader anymore, since the cached reader
497e527b796SIngo Weinhold		// is not a wrapper around it, but completely independent from it.
498e527b796SIngo Weinhold		delete rawHeapReader;
49946122852SIngo Weinhold
50046122852SIngo Weinhold		HeapReaderV2* cachedHeapReader = fCachedHeapReader;
50146122852SIngo Weinhold		fCachedHeapReader = NULL;
50246122852SIngo Weinhold		return cachedHeapReader;
5031f633814SIngo Weinhold	}
5041f633814SIngo Weinhold
5051f633814SIngo Weinholdprivate:
50646122852SIngo Weinhold	HeapReaderV2*	fCachedHeapReader;
507e527b796SIngo Weinhold	int				fFD;
5081f633814SIngo Weinhold};
5091f633814SIngo Weinhold
5101f633814SIngo Weinhold
511e85e9dadSIngo Weinhold// #pragma mark - Package
512e85e9dadSIngo Weinhold
513e85e9dadSIngo Weinhold
514dff8d2eaSIngo WeinholdPackage::Package(::Volume* volume, PackagesDirectory* directory, dev_t deviceID,
515dff8d2eaSIngo Weinhold	ino_t nodeID)
516cc32c484SIngo Weinhold	:
5176978941aSIngo Weinhold	fVolume(volume),
518dff8d2eaSIngo Weinhold	fPackagesDirectory(directory),
519d07c930cSIngo Weinhold	fFileName(),
520d07c930cSIngo Weinhold	fName(),
521d07c930cSIngo Weinhold	fInstallPath(),
522415e374eSIngo Weinhold	fVersionedName(),
52301102ee5SIngo Weinhold	fVersion(NULL),
524abf0c287SAugustin Cavalier	fFlags(0),
525eadc3c84SIngo Weinhold	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
5264031a32aSIngo Weinhold	fLinkDirectory(NULL),
527744a460cSIngo Weinhold	fFD(-1),
528744a460cSIngo Weinhold	fOpenCount(0),
5291f633814SIngo Weinhold	fHeapReader(NULL),
530cc32c484SIngo Weinhold	fNodeID(nodeID),
531cc32c484SIngo Weinhold	fDeviceID(deviceID)
532cc32c484SIngo Weinhold{
533744a460cSIngo Weinhold	mutex_init(&fLock, "packagefs package");
534dff8d2eaSIngo Weinhold
535dff8d2eaSIngo Weinhold	fPackagesDirectory->AcquireReference();
536cc32c484SIngo Weinhold}
537cc32c484SIngo Weinhold
538cc32c484SIngo Weinhold
539cc32c484SIngo WeinholdPackage::~Package()
540cc32c484SIngo Weinhold{
5411f633814SIngo Weinhold	delete fHeapReader;
5421f633814SIngo Weinhold
543cc32c484SIngo Weinhold	while (PackageNode* node = fNodes.RemoveHead())
54446776004SIngo Weinhold		node->ReleaseReference();
545cc32c484SIngo Weinhold
54601102ee5SIngo Weinhold	while (Resolvable* resolvable = fResolvables.RemoveHead())
54701102ee5SIngo Weinhold		delete resolvable;
54801102ee5SIngo Weinhold
54901102ee5SIngo Weinhold	while (Dependency* dependency = fDependencies.RemoveHead())
55001102ee5SIngo Weinhold		delete dependency;
55101102ee5SIngo Weinhold
55201102ee5SIngo Weinhold	delete fVersion;
553744a460cSIngo Weinhold
554dff8d2eaSIngo Weinhold	fPackagesDirectory->ReleaseReference();
555dff8d2eaSIngo Weinhold
556744a460cSIngo Weinhold	mutex_destroy(&fLock);
557cc32c484SIngo Weinhold}
558cc32c484SIngo Weinhold
559cc32c484SIngo Weinhold
560cc32c484SIngo Weinholdstatus_t
561ddabac20SIngo WeinholdPackage::Init(const char* fileName)
562cc32c484SIngo Weinhold{
563d07c930cSIngo Weinhold	if (!fFileName.SetTo(fileName))
564cc32c484SIngo Weinhold		RETURN_ERROR(B_NO_MEMORY);
565cc32c484SIngo Weinhold
566cc32c484SIngo Weinhold	return B_OK;
567cc32c484SIngo Weinhold}
568cc32c484SIngo Weinhold
569cc32c484SIngo Weinhold
570e85e9dadSIngo Weinholdstatus_t
5713a7e0b00SIngo WeinholdPackage::Load(const PackageSettings& settings)
572e85e9dadSIngo Weinhold{
5733a7e0b00SIngo Weinhold	status_t error = _Load(settings);
5741f633814SIngo Weinhold	if (error != B_OK)
575415e374eSIngo Weinhold		return error;
5761f633814SIngo Weinhold
577415e374eSIngo Weinhold	if (!_InitVersionedName())
5781f633814SIngo Weinhold		RETURN_ERROR(B_NO_MEMORY);
5791f633814SIngo Weinhold
5801f633814SIngo Weinhold	return B_OK;
581e85e9dadSIngo Weinhold}
582e85e9dadSIngo Weinhold
583e85e9dadSIngo Weinhold
584d07c930cSIngo Weinholdvoid
585d07c930cSIngo WeinholdPackage::SetName(const String& name)
58601102ee5SIngo Weinhold{
587d07c930cSIngo Weinhold	fName = name;
58801102ee5SIngo Weinhold}
58901102ee5SIngo Weinhold
59001102ee5SIngo Weinhold
591d07c930cSIngo Weinholdvoid
592d07c930cSIngo WeinholdPackage::SetInstallPath(const String& installPath)
59348a8980cSIngo Weinhold{
594d07c930cSIngo Weinhold	fInstallPath = installPath;
59548a8980cSIngo Weinhold}
59648a8980cSIngo Weinhold
59748a8980cSIngo Weinhold
59801102ee5SIngo Weinholdvoid
59901102ee5SIngo WeinholdPackage::SetVersion(::Version* version)
60001102ee5SIngo Weinhold{
60101102ee5SIngo Weinhold	if (fVersion != NULL)
60201102ee5SIngo Weinhold		delete fVersion;
60301102ee5SIngo Weinhold
60401102ee5SIngo Weinhold	fVersion = version;
60501102ee5SIngo Weinhold}
60601102ee5SIngo Weinhold
60701102ee5SIngo Weinhold
608eadc3c84SIngo Weinholdconst char*
609eadc3c84SIngo WeinholdPackage::ArchitectureName() const
610eadc3c84SIngo Weinhold{
611eadc3c84SIngo Weinhold	if (fArchitecture < 0
612eadc3c84SIngo Weinhold		|| fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
613eadc3c84SIngo Weinhold		return NULL;
614eadc3c84SIngo Weinhold	}
615eadc3c84SIngo Weinhold
616eadc3c84SIngo Weinhold	return kArchitectureNames[fArchitecture];
617eadc3c84SIngo Weinhold}
618eadc3c84SIngo Weinhold
619eadc3c84SIngo Weinhold
620cc32c484SIngo Weinholdvoid
621cc32c484SIngo WeinholdPackage::AddNode(PackageNode* node)
622cc32c484SIngo Weinhold{
623cc32c484SIngo Weinhold	fNodes.Add(node);
62446776004SIngo Weinhold	node->AcquireReference();
625cc32c484SIngo Weinhold}
626744a460cSIngo Weinhold
627744a460cSIngo Weinhold
62801102ee5SIngo Weinholdvoid
62901102ee5SIngo WeinholdPackage::AddResolvable(Resolvable* resolvable)
63001102ee5SIngo Weinhold{
63101102ee5SIngo Weinhold	fResolvables.Add(resolvable);
63201102ee5SIngo Weinhold}
63301102ee5SIngo Weinhold
63401102ee5SIngo Weinhold
63501102ee5SIngo Weinholdvoid
63601102ee5SIngo WeinholdPackage::AddDependency(Dependency* dependency)
63701102ee5SIngo Weinhold{
63801102ee5SIngo Weinhold	fDependencies.Add(dependency);
63901102ee5SIngo Weinhold}
64001102ee5SIngo Weinhold
64101102ee5SIngo Weinhold
642744a460cSIngo Weinholdint
643744a460cSIngo WeinholdPackage::Open()
644744a460cSIngo Weinhold{
645744a460cSIngo Weinhold	MutexLocker locker(fLock);
646744a460cSIngo Weinhold	if (fOpenCount > 0) {
647744a460cSIngo Weinhold		fOpenCount++;
648744a460cSIngo Weinhold		return fFD;
649744a460cSIngo Weinhold	}
650744a460cSIngo Weinhold
651744a460cSIngo Weinhold	// open the file
65211e3c6ddSAugustin Cavalier	fFD = openat(fPackagesDirectory->DirectoryFD(), fFileName,
65311e3c6ddSAugustin Cavalier		O_RDONLY | O_NOCACHE);
654744a460cSIngo Weinhold	if (fFD < 0) {
65553aae3dbSIngo Weinhold		ERROR("Failed to open package file \"%s\": %s\n", fFileName.Data(),
65653aae3dbSIngo Weinhold			strerror(errno));
657744a460cSIngo Weinhold		return errno;
658744a460cSIngo Weinhold	}
659744a460cSIngo Weinhold
660744a460cSIngo Weinhold	// stat it to verify that it's still the same file
661744a460cSIngo Weinhold	struct stat st;
662744a460cSIngo Weinhold	if (fstat(fFD, &st) < 0) {
66353aae3dbSIngo Weinhold		ERROR("Failed to stat package file \"%s\": %s\n", fFileName.Data(),
66453aae3dbSIngo Weinhold			strerror(errno));
665744a460cSIngo Weinhold		close(fFD);
666744a460cSIngo Weinhold		fFD = -1;
667744a460cSIngo Weinhold		return errno;
668744a460cSIngo Weinhold	}
669744a460cSIngo Weinhold
670744a460cSIngo Weinhold	if (st.st_dev != fDeviceID || st.st_ino != fNodeID) {
671744a460cSIngo Weinhold		close(fFD);
672744a460cSIngo Weinhold		fFD = -1;
673744a460cSIngo Weinhold		RETURN_ERROR(B_ENTRY_NOT_FOUND);
674744a460cSIngo Weinhold	}
675744a460cSIngo Weinhold
676744a460cSIngo Weinhold	fOpenCount = 1;
6771f633814SIngo Weinhold
6781f633814SIngo Weinhold	if (fHeapReader != NULL)
6791f633814SIngo Weinhold		fHeapReader->UpdateFD(fFD);
6801f633814SIngo Weinhold
681744a460cSIngo Weinhold	return fFD;
682744a460cSIngo Weinhold}
683744a460cSIngo Weinhold
684744a460cSIngo Weinhold
685744a460cSIngo Weinholdvoid
686744a460cSIngo WeinholdPackage::Close()
687744a460cSIngo Weinhold{
688744a460cSIngo Weinhold	MutexLocker locker(fLock);
689744a460cSIngo Weinhold	if (fOpenCount == 0) {
690744a460cSIngo Weinhold		ERROR("Package open count already 0!\n");
691744a460cSIngo Weinhold		return;
692744a460cSIngo Weinhold	}
693744a460cSIngo Weinhold
694744a460cSIngo Weinhold	if (--fOpenCount == 0) {
695744a460cSIngo Weinhold		close(fFD);
696744a460cSIngo Weinhold		fFD = -1;
6971f633814SIngo Weinhold
6981f633814SIngo Weinhold		if (fHeapReader != NULL)
6991f633814SIngo Weinhold			fHeapReader->UpdateFD(fFD);
700744a460cSIngo Weinhold	}
701744a460cSIngo Weinhold}
7021f633814SIngo Weinhold
7031f633814SIngo Weinhold
7041f633814SIngo Weinholdstatus_t
7051f633814SIngo WeinholdPackage::CreateDataReader(const PackageData& data,
7061f633814SIngo Weinhold	BAbstractBufferedDataReader*& _reader)
7071f633814SIngo Weinhold{
7081f633814SIngo Weinhold	if (fHeapReader == NULL)
7091f633814SIngo Weinhold		return B_BAD_VALUE;
7101f633814SIngo Weinhold
7111f633814SIngo Weinhold	return fHeapReader->CreateDataReader(data, _reader);
7121f633814SIngo Weinhold}
713415e374eSIngo Weinhold
714415e374eSIngo Weinhold
715415e374eSIngo Weinholdstatus_t
7163a7e0b00SIngo WeinholdPackage::_Load(const PackageSettings& settings)
717415e374eSIngo Weinhold{
718415e374eSIngo Weinhold	// open package file
719415e374eSIngo Weinhold	int fd = Open();
720415e374eSIngo Weinhold	if (fd < 0)
721415e374eSIngo Weinhold		RETURN_ERROR(fd);
722415e374eSIngo Weinhold	PackageCloser packageCloser(this);
723415e374eSIngo Weinhold
724415e374eSIngo Weinhold	// initialize package reader
725415e374eSIngo Weinhold	LoaderErrorOutput errorOutput(this);
726415e374eSIngo Weinhold
727415e374eSIngo Weinhold	// try current package file format version
728415e374eSIngo Weinhold	{
729415e374eSIngo Weinhold		CachingPackageReader packageReader(&errorOutput);
730415e374eSIngo Weinhold		status_t error = packageReader.Init(fd, false,
731415e374eSIngo Weinhold			BHPKG::B_HPKG_READER_DONT_PRINT_VERSION_MISMATCH_MESSAGE);
732415e374eSIngo Weinhold		if (error == B_OK) {
733