PackageWriterImpl.cpp revision fc198cc3
15fb1c6ffSOliver Tappe/*
2c9ed1ea2SIngo Weinhold * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3fd9c0b33SOliver Tappe * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
45fb1c6ffSOliver Tappe * Distributed under the terms of the MIT License.
55fb1c6ffSOliver Tappe */
65fb1c6ffSOliver Tappe
75fb1c6ffSOliver Tappe
85fb1c6ffSOliver Tappe#include <package/hpkg/PackageWriterImpl.h>
95fb1c6ffSOliver Tappe
105fb1c6ffSOliver Tappe#include <dirent.h>
115fb1c6ffSOliver Tappe#include <errno.h>
125fb1c6ffSOliver Tappe#include <fcntl.h>
135fb1c6ffSOliver Tappe#include <stdio.h>
145fb1c6ffSOliver Tappe#include <stdlib.h>
155fb1c6ffSOliver Tappe#include <string.h>
165fb1c6ffSOliver Tappe#include <sys/stat.h>
175fb1c6ffSOliver Tappe#include <unistd.h>
185fb1c6ffSOliver Tappe
195fb1c6ffSOliver Tappe#include <algorithm>
205fb1c6ffSOliver Tappe#include <new>
215fb1c6ffSOliver Tappe
225fb1c6ffSOliver Tappe#include <ByteOrder.h>
23d77c6cd2SOliver Tappe#include <Directory.h>
247fd711efSOliver Tappe#include <Entry.h>
25d77c6cd2SOliver Tappe#include <FindDirectory.h>
265fb1c6ffSOliver Tappe#include <fs_attr.h>
27d77c6cd2SOliver Tappe#include <Path.h>
285fb1c6ffSOliver Tappe
290ee16518SIngo Weinhold#include <package/hpkg/BlockBufferPoolNoLock.h>
3000bc8e9cSIngo Weinhold#include <package/hpkg/PackageAttributeValue.h>
3100bc8e9cSIngo Weinhold#include <package/hpkg/PackageContentHandler.h>
3200bc8e9cSIngo Weinhold#include <package/hpkg/PackageData.h>
3300bc8e9cSIngo Weinhold#include <package/hpkg/PackageDataReader.h>
3400bc8e9cSIngo Weinhold
355fb1c6ffSOliver Tappe#include <AutoDeleter.h>
3600bc8e9cSIngo Weinhold#include <RangeArray.h>
375fb1c6ffSOliver Tappe
3833bc4425SOliver Tappe#include <package/hpkg/HPKGDefsPrivate.h>
395fb1c6ffSOliver Tappe
405fb1c6ffSOliver Tappe#include <package/hpkg/DataOutput.h>
415fb1c6ffSOliver Tappe#include <package/hpkg/DataReader.h>
421f633814SIngo Weinhold#include <package/hpkg/PackageFileHeapWriter.h>
4300bc8e9cSIngo Weinhold#include <package/hpkg/PackageReaderImpl.h>
445fb1c6ffSOliver Tappe#include <package/hpkg/Stacker.h>
455fb1c6ffSOliver Tappe
465fb1c6ffSOliver Tappe
4715a5c3f7SOliver Tappeusing BPrivate::FileDescriptorCloser;
4815a5c3f7SOliver Tappe
4915a5c3f7SOliver Tappe
507ea4dbceSIngo Weinholdstatic const char* const kPublicDomainLicenseName = "Public Domain";
517ea4dbceSIngo Weinhold
527ea4dbceSIngo Weinhold
5385e13d1eSIngo Weinhold#include <typeinfo>
54caa4217eSIngo Weinhold
555fb1c6ffSOliver Tappenamespace BPackageKit {
565fb1c6ffSOliver Tappe
575fb1c6ffSOliver Tappenamespace BHPKG {
585fb1c6ffSOliver Tappe
595fb1c6ffSOliver Tappenamespace BPrivate {
605fb1c6ffSOliver Tappe
615fb1c6ffSOliver Tappe
625fb1c6ffSOliver Tappe// minimum length of data we require before trying to zlib compress them
635fb1c6ffSOliver Tappestatic const size_t kZlibCompressionSizeThreshold = 64;
645fb1c6ffSOliver Tappe
655fb1c6ffSOliver Tappe
665fb1c6ffSOliver Tappe// #pragma mark - Attributes
675fb1c6ffSOliver Tappe
685fb1c6ffSOliver Tappe
695fb1c6ffSOliver Tappestruct PackageWriterImpl::Attribute
705fb1c6ffSOliver Tappe	: public DoublyLinkedListLinkImpl<Attribute> {
7133bc4425SOliver Tappe	BHPKGAttributeID			id;
725fb1c6ffSOliver Tappe	AttributeValue				value;
735fb1c6ffSOliver Tappe	DoublyLinkedList<Attribute>	children;
745fb1c6ffSOliver Tappe
7533bc4425SOliver Tappe	Attribute(BHPKGAttributeID id_ = B_HPKG_ATTRIBUTE_ID_ENUM_COUNT)
765fb1c6ffSOliver Tappe		:
7733bc4425SOliver Tappe		id(id_)
785fb1c6ffSOliver Tappe	{
795fb1c6ffSOliver Tappe	}
805fb1c6ffSOliver Tappe
815fb1c6ffSOliver Tappe	~Attribute()
825fb1c6ffSOliver Tappe	{
835fb1c6ffSOliver Tappe		DeleteChildren();
845fb1c6ffSOliver Tappe	}
855fb1c6ffSOliver Tappe
865fb1c6ffSOliver Tappe	void AddChild(Attribute* child)
875fb1c6ffSOliver Tappe	{
885fb1c6ffSOliver Tappe		children.Add(child);
895fb1c6ffSOliver Tappe	}
905fb1c6ffSOliver Tappe
9100bc8e9cSIngo Weinhold	void RemoveChild(Attribute* child)
9200bc8e9cSIngo Weinhold	{
9300bc8e9cSIngo Weinhold		children.Remove(child);
9400bc8e9cSIngo Weinhold	}
9500bc8e9cSIngo Weinhold
965fb1c6ffSOliver Tappe	void DeleteChildren()
975fb1c6ffSOliver Tappe	{
985fb1c6ffSOliver Tappe		while (Attribute* child = children.RemoveHead())
995fb1c6ffSOliver Tappe			delete child;
1005fb1c6ffSOliver Tappe	}
10100bc8e9cSIngo Weinhold
10200bc8e9cSIngo Weinhold	Attribute* FindEntryChild(const char* fileName) const
10300bc8e9cSIngo Weinhold	{
10400bc8e9cSIngo Weinhold		for (DoublyLinkedList<Attribute>::ConstIterator it
10500bc8e9cSIngo Weinhold				= children.GetIterator(); Attribute* child = it.Next();) {
10600bc8e9cSIngo Weinhold			if (child->id != B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY)
10700bc8e9cSIngo Weinhold				continue;
10800bc8e9cSIngo Weinhold			if (child->value.type != B_HPKG_ATTRIBUTE_TYPE_STRING)
10900bc8e9cSIngo Weinhold				continue;
11000bc8e9cSIngo Weinhold			const char* childName = child->value.string->string;
11100bc8e9cSIngo Weinhold			if (strcmp(fileName, childName) == 0)
11200bc8e9cSIngo Weinhold				return child;
11300bc8e9cSIngo Weinhold		}
11400bc8e9cSIngo Weinhold
11500bc8e9cSIngo Weinhold		return NULL;
11600bc8e9cSIngo Weinhold	}
11700bc8e9cSIngo Weinhold
11800bc8e9cSIngo Weinhold	Attribute* FindEntryChild(const char* fileName, size_t nameLength) const
11900bc8e9cSIngo Weinhold	{
12000bc8e9cSIngo Weinhold		BString name(fileName, nameLength);
12100bc8e9cSIngo Weinhold		return (size_t)name.Length() == nameLength
12200bc8e9cSIngo Weinhold			? FindEntryChild(name) : NULL;
12300bc8e9cSIngo Weinhold	}
12400bc8e9cSIngo Weinhold
12500bc8e9cSIngo Weinhold	Attribute* FindNodeAttributeChild(const char* attributeName) const
12600bc8e9cSIngo Weinhold	{
12700bc8e9cSIngo Weinhold		for (DoublyLinkedList<Attribute>::ConstIterator it
12800bc8e9cSIngo Weinhold				= children.GetIterator(); Attribute* child = it.Next();) {
12900bc8e9cSIngo Weinhold			if (child->id != B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE)
13000bc8e9cSIngo Weinhold				continue;
13100bc8e9cSIngo Weinhold			if (child->value.type != B_HPKG_ATTRIBUTE_TYPE_STRING)
13200bc8e9cSIngo Weinhold				continue;
13300bc8e9cSIngo Weinhold			const char* childName = child->value.string->string;
13400bc8e9cSIngo Weinhold			if (strcmp(attributeName, childName) == 0)
13500bc8e9cSIngo Weinhold				return child;
13600bc8e9cSIngo Weinhold		}
13700bc8e9cSIngo Weinhold
13800bc8e9cSIngo Weinhold		return NULL;
13900bc8e9cSIngo Weinhold	}
14000bc8e9cSIngo Weinhold
14100bc8e9cSIngo Weinhold	Attribute* ChildWithID(BHPKGAttributeID id) const
14200bc8e9cSIngo Weinhold	{
14300bc8e9cSIngo Weinhold		for (DoublyLinkedList<Attribute>::ConstIterator it
14400bc8e9cSIngo Weinhold				= children.GetIterator(); Attribute* child = it.Next();) {
14500bc8e9cSIngo Weinhold			if (child->id == id)
14600bc8e9cSIngo Weinhold				return child;
14700bc8e9cSIngo Weinhold		}
14800bc8e9cSIngo Weinhold
14900bc8e9cSIngo Weinhold		return NULL;
15000bc8e9cSIngo Weinhold	}
15100bc8e9cSIngo Weinhold};
15200bc8e9cSIngo Weinhold
15300bc8e9cSIngo Weinhold
15400bc8e9cSIngo Weinhold// #pragma mark - PackageContentHandler
15500bc8e9cSIngo Weinhold
15600bc8e9cSIngo Weinhold
15700bc8e9cSIngo Weinholdstruct PackageWriterImpl::PackageContentHandler
15800bc8e9cSIngo Weinhold	: BLowLevelPackageContentHandler {
15900bc8e9cSIngo Weinhold	PackageContentHandler(Attribute* rootAttribute, BErrorOutput* errorOutput,
1601f633814SIngo Weinhold		StringCache& stringCache)
16100bc8e9cSIngo Weinhold		:
16200bc8e9cSIngo Weinhold		fErrorOutput(errorOutput),
16300bc8e9cSIngo Weinhold		fStringCache(stringCache),
16400bc8e9cSIngo Weinhold		fRootAttribute(rootAttribute),
16500bc8e9cSIngo Weinhold		fErrorOccurred(false)
16600bc8e9cSIngo Weinhold	{
16700bc8e9cSIngo Weinhold	}
16800bc8e9cSIngo Weinhold
16900bc8e9cSIngo Weinhold	virtual status_t HandleSectionStart(BHPKGPackageSectionID sectionID,
17000bc8e9cSIngo Weinhold		bool& _handleSection)
17100bc8e9cSIngo Weinhold	{
17200bc8e9cSIngo Weinhold		// we're only interested in the TOC
17300bc8e9cSIngo Weinhold		_handleSection = sectionID == B_HPKG_SECTION_PACKAGE_TOC;
17400bc8e9cSIngo Weinhold		return B_OK;
17500bc8e9cSIngo Weinhold	}
17600bc8e9cSIngo Weinhold
17700bc8e9cSIngo Weinhold	virtual status_t HandleSectionEnd(BHPKGPackageSectionID sectionID)
17800bc8e9cSIngo Weinhold	{
17900bc8e9cSIngo Weinhold		return B_OK;
18000bc8e9cSIngo Weinhold	}
18100bc8e9cSIngo Weinhold
18200bc8e9cSIngo Weinhold	virtual status_t HandleAttribute(BHPKGAttributeID attributeID,
18300bc8e9cSIngo Weinhold		const BPackageAttributeValue& value, void* parentToken, void*& _token)
18400bc8e9cSIngo Weinhold	{
18500bc8e9cSIngo Weinhold		if (fErrorOccurred)
18600bc8e9cSIngo Weinhold			return B_OK;
18700bc8e9cSIngo Weinhold
18800bc8e9cSIngo Weinhold		Attribute* parentAttribute = parentToken != NULL
18900bc8e9cSIngo Weinhold			? (Attribute*)parentToken : fRootAttribute;
19000bc8e9cSIngo Weinhold
19100bc8e9cSIngo Weinhold		Attribute* attribute = new Attribute(attributeID);
19200bc8e9cSIngo Weinhold		parentAttribute->AddChild(attribute);
19300bc8e9cSIngo Weinhold
19400bc8e9cSIngo Weinhold		switch (value.type) {
19500bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_INT:
19600bc8e9cSIngo Weinhold				attribute->value.SetTo(value.signedInt);
19700bc8e9cSIngo Weinhold				break;
19800bc8e9cSIngo Weinhold
19900bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_UINT:
20000bc8e9cSIngo Weinhold				attribute->value.SetTo(value.unsignedInt);
20100bc8e9cSIngo Weinhold				break;
20200bc8e9cSIngo Weinhold
20300bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_STRING:
20400bc8e9cSIngo Weinhold			{
20500bc8e9cSIngo Weinhold				CachedString* string = fStringCache.Get(value.string);
20600bc8e9cSIngo Weinhold				if (string == NULL)
20700bc8e9cSIngo Weinhold					throw std::bad_alloc();
20800bc8e9cSIngo Weinhold				attribute->value.SetTo(string);
20900bc8e9cSIngo Weinhold				break;
21000bc8e9cSIngo Weinhold			}
21100bc8e9cSIngo Weinhold
21200bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_RAW:
21300bc8e9cSIngo Weinhold				if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
21400bc8e9cSIngo Weinhold					attribute->value.SetToData(value.data.size,
2151f633814SIngo Weinhold						value.data.offset);
21600bc8e9cSIngo Weinhold				} else if (value.encoding
21700bc8e9cSIngo Weinhold						== B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) {
21800bc8e9cSIngo Weinhold					attribute->value.SetToData(value.data.size, value.data.raw);
21900bc8e9cSIngo Weinhold				} else {
22000bc8e9cSIngo Weinhold					fErrorOutput->PrintError("Invalid attribute value encoding "
22100bc8e9cSIngo Weinhold						"%d (attribute %d)\n", value.encoding, attributeID);
22200bc8e9cSIngo Weinhold					return B_BAD_DATA;
22300bc8e9cSIngo Weinhold				}
22400bc8e9cSIngo Weinhold				break;
22500bc8e9cSIngo Weinhold
22600bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_INVALID:
22700bc8e9cSIngo Weinhold			default:
22800bc8e9cSIngo Weinhold				fErrorOutput->PrintError("Invalid attribute value type %d "
22900bc8e9cSIngo Weinhold					"(attribute %d)\n", value.type, attributeID);
23000bc8e9cSIngo Weinhold				return B_BAD_DATA;
23100bc8e9cSIngo Weinhold		}
23200bc8e9cSIngo Weinhold
23300bc8e9cSIngo Weinhold		_token = attribute;
23400bc8e9cSIngo Weinhold		return B_OK;
23500bc8e9cSIngo Weinhold	}
23600bc8e9cSIngo Weinhold
23700bc8e9cSIngo Weinhold	virtual status_t HandleAttributeDone(BHPKGAttributeID attributeID,
23800bc8e9cSIngo Weinhold		const BPackageAttributeValue& value, void* parentToken, void* token)
23900bc8e9cSIngo Weinhold	{
24000bc8e9cSIngo Weinhold		return B_OK;
24100bc8e9cSIngo Weinhold	}
24200bc8e9cSIngo Weinhold
24300bc8e9cSIngo Weinhold	virtual void HandleErrorOccurred()
24400bc8e9cSIngo Weinhold	{
24500bc8e9cSIngo Weinhold		fErrorOccurred = true;
24600bc8e9cSIngo Weinhold	}
24700bc8e9cSIngo Weinhold
24800bc8e9cSIngo Weinholdprivate:
24900bc8e9cSIngo Weinhold	BErrorOutput*	fErrorOutput;
25000bc8e9cSIngo Weinhold	StringCache&	fStringCache;
25100bc8e9cSIngo Weinhold	Attribute*		fRootAttribute;
25200bc8e9cSIngo Weinhold	bool			fErrorOccurred;
2535fb1c6ffSOliver Tappe};
2545fb1c6ffSOliver Tappe
2555fb1c6ffSOliver Tappe
256f2022173SOliver Tappe// #pragma mark - Entry
2575fb1c6ffSOliver Tappe
2585fb1c6ffSOliver Tappe
2595fb1c6ffSOliver Tappestruct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> {
2600f9a98a4SIngo Weinhold	Entry(char* name, size_t nameLength, int fd, bool isImplicit)
2615fb1c6ffSOliver Tappe		:
2625fb1c6ffSOliver Tappe		fName(name),
2635fb1c6ffSOliver Tappe		fNameLength(nameLength),
2640f9a98a4SIngo Weinhold		fFD(fd),
2655fb1c6ffSOliver Tappe		fIsImplicit(isImplicit)
2665fb1c6ffSOliver Tappe	{
2675fb1c6ffSOliver Tappe	}
2685fb1c6ffSOliver Tappe
2695fb1c6ffSOliver Tappe	~Entry()
2705fb1c6ffSOliver Tappe	{
2715fb1c6ffSOliver Tappe		DeleteChildren();
2725fb1c6ffSOliver Tappe		free(fName);
2735fb1c6ffSOliver Tappe	}
2745fb1c6ffSOliver Tappe
2750f9a98a4SIngo Weinhold	static Entry* Create(const char* name, size_t nameLength, int fd,
2760f9a98a4SIngo Weinhold		bool isImplicit)
2775fb1c6ffSOliver Tappe	{
2785fb1c6ffSOliver Tappe		char* clonedName = (char*)malloc(nameLength + 1);
2795fb1c6ffSOliver Tappe		if (clonedName == NULL)
2805fb1c6ffSOliver Tappe			throw std::bad_alloc();
2815fb1c6ffSOliver Tappe		memcpy(clonedName, name, nameLength);
2825fb1c6ffSOliver Tappe		clonedName[nameLength] = '\0';
2835fb1c6ffSOliver Tappe
2840f9a98a4SIngo Weinhold		Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, fd,
2855fb1c6ffSOliver Tappe			isImplicit);
2865fb1c6ffSOliver Tappe		if (entry == NULL) {
2875fb1c6ffSOliver Tappe			free(clonedName);
2885fb1c6ffSOliver Tappe			throw std::bad_alloc();
2895fb1c6ffSOliver Tappe		}
2905fb1c6ffSOliver Tappe
2915fb1c6ffSOliver Tappe		return entry;
2925fb1c6ffSOliver Tappe	}
2935fb1c6ffSOliver Tappe
2945fb1c6ffSOliver Tappe	const char* Name() const
2955fb1c6ffSOliver Tappe	{
2965fb1c6ffSOliver Tappe		return fName;
2975fb1c6ffSOliver Tappe	}
2985fb1c6ffSOliver Tappe
2990f9a98a4SIngo Weinhold	int FD() const
3000f9a98a4SIngo Weinhold	{
3010f9a98a4SIngo Weinhold		return fFD;
3020f9a98a4SIngo Weinhold	}
3030f9a98a4SIngo Weinhold
3040f9a98a4SIngo Weinhold	void SetFD(int fd)
3050f9a98a4SIngo Weinhold	{
3060f9a98a4SIngo Weinhold		fFD = fd;
3070f9a98a4SIngo Weinhold	}
3080f9a98a4SIngo Weinhold
3095fb1c6ffSOliver Tappe	bool IsImplicit() const
3105fb1c6ffSOliver Tappe	{
3115fb1c6ffSOliver Tappe		return fIsImplicit;
3125fb1c6ffSOliver Tappe	}
3135fb1c6ffSOliver Tappe
3145fb1c6ffSOliver Tappe	void SetImplicit(bool isImplicit)
3155fb1c6ffSOliver Tappe	{
3165fb1c6ffSOliver Tappe		fIsImplicit = isImplicit;
3175fb1c6ffSOliver Tappe	}
3185fb1c6ffSOliver Tappe
3195fb1c6ffSOliver Tappe	bool HasName(const char* name, size_t nameLength)
3205fb1c6ffSOliver Tappe	{
3215fb1c6ffSOliver Tappe		return nameLength == fNameLength
3225fb1c6ffSOliver Tappe			&& strncmp(name, fName, nameLength) == 0;
3235fb1c6ffSOliver Tappe	}
3245fb1c6ffSOliver Tappe
3255fb1c6ffSOliver Tappe	void AddChild(Entry* child)
3265fb1c6ffSOliver Tappe	{
3275fb1c6ffSOliver Tappe		fChildren.Add(child);
3285fb1c6ffSOliver Tappe	}
3295fb1c6ffSOliver Tappe
3305fb1c6ffSOliver Tappe	void DeleteChildren()
3315fb1c6ffSOliver Tappe	{
3325fb1c6ffSOliver Tappe		while (Entry* child = fChildren.RemoveHead())
3335fb1c6ffSOliver Tappe			delete child;
3345fb1c6ffSOliver Tappe	}
3355fb1c6ffSOliver Tappe
3365fb1c6ffSOliver Tappe	Entry* GetChild(const char* name, size_t nameLength) const
3375fb1c6ffSOliver Tappe	{
3385fb1c6ffSOliver Tappe		EntryList::ConstIterator it = fChildren.GetIterator();
3395fb1c6ffSOliver Tappe		while (Entry* child = it.Next()) {
3405fb1c6ffSOliver Tappe			if (child->HasName(name, nameLength))
3415fb1c6ffSOliver Tappe				return child;
3425fb1c6ffSOliver Tappe		}
3435fb1c6ffSOliver Tappe
3445fb1c6ffSOliver Tappe		return NULL;
3455fb1c6ffSOliver Tappe	}
3465fb1c6ffSOliver Tappe
3475fb1c6ffSOliver Tappe	EntryList::ConstIterator ChildIterator() const
3485fb1c6ffSOliver Tappe	{
3495fb1c6ffSOliver Tappe		return fChildren.GetIterator();
3505fb1c6ffSOliver Tappe	}
3515fb1c6ffSOliver Tappe
3525fb1c6ffSOliver Tappeprivate:
3535fb1c6ffSOliver Tappe	char*		fName;
3545fb1c6ffSOliver Tappe	size_t		fNameLength;
3550f9a98a4SIngo Weinhold	int			fFD;
3565fb1c6ffSOliver Tappe	bool		fIsImplicit;
3575fb1c6ffSOliver Tappe	EntryList	fChildren;
3585fb1c6ffSOliver Tappe};
3595fb1c6ffSOliver Tappe
3605fb1c6ffSOliver Tappe
361f2022173SOliver Tappe// #pragma mark - SubPathAdder
3625fb1c6ffSOliver Tappe
3635fb1c6ffSOliver Tappe
3647fd711efSOliver Tappestruct PackageWriterImpl::SubPathAdder {
3658524dd36SIngo Weinhold	SubPathAdder(BErrorOutput* errorOutput, char* pathBuffer,
3668524dd36SIngo Weinhold		const char* subPath)
3678524dd36SIngo Weinhold		:
3688524dd36SIngo Weinhold		fOriginalPathEnd(pathBuffer + strlen(pathBuffer))
3697fd711efSOliver Tappe	{
3708524dd36SIngo Weinhold		if (fOriginalPathEnd != pathBuffer)
3718524dd36SIngo Weinhold			strlcat(pathBuffer, "/", B_PATH_NAME_LENGTH);
3728524dd36SIngo Weinhold
3738524dd36SIngo Weinhold		if (strlcat(pathBuffer, subPath, B_PATH_NAME_LENGTH)
3748524dd36SIngo Weinhold				>= B_PATH_NAME_LENGTH) {
3758524dd36SIngo Weinhold			*fOriginalPathEnd = '\0';
3768524dd36SIngo Weinhold			errorOutput->PrintError("Path too long: \"%s/%s\"\n", pathBuffer,
3778524dd36SIngo Weinhold				subPath);
3788524dd36SIngo Weinhold			throw status_t(B_BUFFER_OVERFLOW);
3798524dd36SIngo Weinhold		}
3807fd711efSOliver Tappe	}
3817fd711efSOliver Tappe
3827fd711efSOliver Tappe	~SubPathAdder()
3837fd711efSOliver Tappe	{
3847fd711efSOliver Tappe		*fOriginalPathEnd = '\0';
3857fd711efSOliver Tappe	}
3868524dd36SIngo Weinhold
3877fd711efSOliver Tappeprivate:
3887fd711efSOliver Tappe	char* fOriginalPathEnd;
3897fd711efSOliver Tappe};
3907fd711efSOliver Tappe
3917fd711efSOliver Tappe
39221ee6d5cSIngo Weinhold// #pragma mark - HeapAttributeOffsetter
39321ee6d5cSIngo Weinhold
39421ee6d5cSIngo Weinhold
39500bc8e9cSIngo Weinholdstruct PackageWriterImpl::HeapAttributeOffsetter {
3961f633814SIngo Weinhold	HeapAttributeOffsetter(const RangeArray<uint64>& ranges,
3971f633814SIngo Weinhold		const Array<uint64>& deltas)
39800bc8e9cSIngo Weinhold		:
39900bc8e9cSIngo Weinhold		fRanges(ranges),
40000bc8e9cSIngo Weinhold		fDeltas(deltas)
40100bc8e9cSIngo Weinhold	{
40200bc8e9cSIngo Weinhold	}
40300bc8e9cSIngo Weinhold
40400bc8e9cSIngo Weinhold	void ProcessAttribute(Attribute* attribute)
40500bc8e9cSIngo Weinhold	{
40600bc8e9cSIngo Weinhold		// If the attribute refers to a heap value, adjust it
40700bc8e9cSIngo Weinhold		AttributeValue& value = attribute->value;
40800bc8e9cSIngo Weinhold
40900bc8e9cSIngo Weinhold		if (value.type == B_HPKG_ATTRIBUTE_TYPE_RAW
41000bc8e9cSIngo Weinhold			&& value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
4111f633814SIngo Weinhold			uint64 delta = fDeltas[fRanges.InsertionIndex(value.data.offset)];
41200bc8e9cSIngo Weinhold			value.data.offset -= delta;
41300bc8e9cSIngo Weinhold		}
41400bc8e9cSIngo Weinhold
41500bc8e9cSIngo Weinhold		// recurse
41600bc8e9cSIngo Weinhold		for (DoublyLinkedList<Attribute>::Iterator it
41700bc8e9cSIngo Weinhold					= attribute->children.GetIterator();
41800bc8e9cSIngo Weinhold				Attribute* child = it.Next();) {
41900bc8e9cSIngo Weinhold			ProcessAttribute(child);
42000bc8e9cSIngo Weinhold		}
42100bc8e9cSIngo Weinhold	}
42200bc8e9cSIngo Weinhold
42300bc8e9cSIngo Weinholdprivate:
4241f633814SIngo Weinhold	const RangeArray<uint64>&	fRanges;
4251f633814SIngo Weinhold	const Array<uint64>&		fDeltas;
42600bc8e9cSIngo Weinhold};
42700bc8e9cSIngo Weinhold
42800bc8e9cSIngo Weinhold
4295fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl (Inline Methods)
4305fb1c6ffSOliver Tappe
4315fb1c6ffSOliver Tappe
4325fb1c6ffSOliver Tappetemplate<typename Type>
4335fb1c6ffSOliver Tappeinline PackageWriterImpl::Attribute*
43433bc4425SOliver TappePackageWriterImpl::_AddAttribute(BHPKGAttributeID attributeID, Type value)
4355fb1c6ffSOliver Tappe{
4365fb1c6ffSOliver Tappe	AttributeValue attributeValue;
4375fb1c6ffSOliver Tappe	attributeValue.SetTo(value);
43833bc4425SOliver Tappe	return _AddAttribute(attributeID, attributeValue);
4395fb1c6ffSOliver Tappe}
4405fb1c6ffSOliver Tappe
4415fb1c6ffSOliver Tappe
4425fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl
4435fb1c6ffSOliver Tappe
4445fb1c6ffSOliver Tappe
4457fd711efSOliver TappePackageWriterImpl::PackageWriterImpl(BPackageWriterListener* listener)
4465fb1c6ffSOliver Tappe	:
4471f633814SIngo Weinhold	inherited("package", listener),
4487fd711efSOliver Tappe	fListener(listener),
44900bc8e9cSIngo Weinhold	fHeapRangesToRemove(NULL),
4505fb1c6ffSOliver Tappe	fRootEntry(NULL),
4515fb1c6ffSOliver Tappe	fRootAttribute(NULL),
4527efa133cSIngo Weinhold	fTopAttribute(NULL),
4537efa133cSIngo Weinhold	fCheckLicenses(true)
4545fb1c6ffSOliver Tappe{
4555fb1c6ffSOliver Tappe}
4565fb1c6ffSOliver Tappe
4575fb1c6ffSOliver Tappe
4585fb1c6ffSOliver TappePackageWriterImpl::~PackageWriterImpl()
4595fb1c6ffSOliver Tappe{
460c9ed1ea2SIngo Weinhold	delete fHeapRangesToRemove;
4615fb1c6ffSOliver Tappe	delete fRootAttribute;
4625fb1c6ffSOliver Tappe	delete fRootEntry;
4635fb1c6ffSOliver Tappe}
4645fb1c6ffSOliver Tappe
4655fb1c6ffSOliver Tappe
4665fb1c6ffSOliver Tappestatus_t
467796343edSIngo WeinholdPackageWriterImpl::Init(const char* fileName,
468796343edSIngo Weinhold	const BPackageWriterParameters& parameters)
4695fb1c6ffSOliver Tappe{
4705fb1c6ffSOliver Tappe	try {
471796343edSIngo Weinhold		return _Init(fileName, parameters);
4725fb1c6ffSOliver Tappe	} catch (status_t error) {
4735fb1c6ffSOliver Tappe		return error;
4745fb1c6ffSOliver Tappe	} catch (std::bad_alloc) {
4757fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
4765fb1c6ffSOliver Tappe		return B_NO_MEMORY;
4775fb1c6ffSOliver Tappe	}
4785fb1c6ffSOliver Tappe}
4795fb1c6ffSOliver Tappe
4805fb1c6ffSOliver Tappe
4816ae0ecd4SIngo Weinholdstatus_t
4826ae0ecd4SIngo WeinholdPackageWriterImpl::SetInstallPath(const char* installPath)
4836ae0ecd4SIngo Weinhold{
4846ae0ecd4SIngo Weinhold	fInstallPath = installPath;
4856ae0ecd4SIngo Weinhold	return installPath == NULL
4866ae0ecd4SIngo Weinhold		|| (size_t)fInstallPath.Length() == strlen(installPath)
4876ae0ecd4SIngo Weinhold		? B_OK : B_NO_MEMORY;
4886ae0ecd4SIngo Weinhold}
4896ae0ecd4SIngo Weinhold
4906ae0ecd4SIngo Weinhold
4917efa133cSIngo Weinholdvoid
4927efa133cSIngo WeinholdPackageWriterImpl::SetCheckLicenses(bool checkLicenses)
4937efa133cSIngo Weinhold{
4947efa133cSIngo Weinhold	fCheckLicenses = checkLicenses;
4957efa133cSIngo Weinhold}
4967efa133cSIngo Weinhold
4977efa133cSIngo Weinhold
4985fb1c6ffSOliver Tappestatus_t
4990f9a98a4SIngo WeinholdPackageWriterImpl::AddEntry(const char* fileName, int fd)
5005fb1c6ffSOliver Tappe{
5015fb1c6ffSOliver Tappe	try {
5027fd711efSOliver Tappe		// if it's ".PackageInfo", parse it
5037fd711efSOliver Tappe		if (strcmp(fileName, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
5047fd711efSOliver Tappe			struct ErrorListener : public BPackageInfo::ParseErrorListener {
5057fd711efSOliver Tappe				ErrorListener(BPackageWriterListener* _listener)
506fc198cc3SIngo Weinhold					:
507fc198cc3SIngo Weinhold					listener(_listener),
508fc198cc3SIngo Weinhold					errorSeen(false)
509fc198cc3SIngo Weinhold				{
510fc198cc3SIngo Weinhold				}
511fc198cc3SIngo Weinhold
5127fd711efSOliver Tappe				virtual void OnError(const BString& msg, int line, int col) {
5137fd711efSOliver Tappe					listener->PrintError("Parse error in %s(%d:%d) -> %s\n",
5147fd711efSOliver Tappe						B_HPKG_PACKAGE_INFO_FILE_NAME, line, col, msg.String());
515fc198cc3SIngo Weinhold					errorSeen = true;
5167fd711efSOliver Tappe				}
517fc198cc3SIngo Weinhold
5187fd711efSOliver Tappe				BPackageWriterListener* listener;
519fc198cc3SIngo Weinhold				bool errorSeen;
5207fd711efSOliver Tappe			} errorListener(fListener);
5210f9a98a4SIngo Weinhold
5220f9a98a4SIngo Weinhold			if (fd >= 0) {
5230f9a98a4SIngo Weinhold				// a file descriptor is given -- read the config from there
5240f9a98a4SIngo Weinhold				// stat the file to get the file size
5250f9a98a4SIngo Weinhold				struct stat st;
5260f9a98a4SIngo Weinhold				if (fstat(fd, &st) != 0)
5270f9a98a4SIngo Weinhold					return errno;
5280f9a98a4SIngo Weinhold
5290f9a98a4SIngo Weinhold				BString packageInfoString;
5300f9a98a4SIngo Weinhold				char* buffer = packageInfoString.LockBuffer(st.st_size);
5310f9a98a4SIngo Weinhold				if (buffer == NULL)
5320f9a98a4SIngo Weinhold					return B_NO_MEMORY;
5330f9a98a4SIngo Weinhold
5340f9a98a4SIngo Weinhold				ssize_t result = read_pos(fd, 0, buffer, st.st_size);
5350f9a98a4SIngo Weinhold				if (result < 0) {
5360f9a98a4SIngo Weinhold					packageInfoString.UnlockBuffer(0);
5370f9a98a4SIngo Weinhold					return errno;
5380f9a98a4SIngo Weinhold				}
5390f9a98a4SIngo Weinhold
5400f9a98a4SIngo Weinhold				buffer[st.st_size] = '\0';
5410f9a98a4SIngo Weinhold				packageInfoString.UnlockBuffer(st.st_size);
5420f9a98a4SIngo Weinhold
5430f9a98a4SIngo Weinhold				result = fPackageInfo.ReadFromConfigString(packageInfoString,
5440f9a98a4SIngo Weinhold					&errorListener);
5450f9a98a4SIngo Weinhold				if (result != B_OK)
5460f9a98a4SIngo Weinhold					return result;
5470f9a98a4SIngo Weinhold			} else {
5480f9a98a4SIngo Weinhold				// use the file name
5490f9a98a4SIngo Weinhold				BEntry packageInfoEntry(fileName);
5500f9a98a4SIngo Weinhold				status_t result = fPackageInfo.ReadFromConfigFile(
5510f9a98a4SIngo Weinhold					packageInfoEntry, &errorListener);
5520f9a98a4SIngo Weinhold				if (result != B_OK
5530f9a98a4SIngo Weinhold					|| (result = fPackageInfo.InitCheck()) != B_OK) {
554fc198cc3SIngo Weinhold					if (!errorListener.errorSeen) {
555fc198cc3SIngo Weinhold						fListener->PrintError("Failed to read %s: %s\n",
556fc198cc3SIngo Weinhold							fileName, strerror(result));
557fc198cc3SIngo Weinhold					}
5580f9a98a4SIngo Weinhold					return result;
5590f9a98a4SIngo Weinhold				}
5600f9a98a4SIngo Weinhold			}
5617fd711efSOliver Tappe		}
5627fd711efSOliver Tappe
5630f9a98a4SIngo Weinhold		return _RegisterEntry(fileName, fd);
5645fb1c6ffSOliver Tappe	} catch (status_t error) {
5655fb1c6ffSOliver Tappe		return error;
5665fb1c6ffSOliver Tappe	} catch (std::bad_alloc) {
5677fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
5685fb1c6ffSOliver Tappe		return B_NO_MEMORY;
5695fb1c6ffSOliver Tappe	}
5705fb1c6ffSOliver Tappe}
5715fb1c6ffSOliver Tappe
5725fb1c6ffSOliver Tappe
5735fb1c6ffSOliver Tappestatus_t
5745fb1c6ffSOliver TappePackageWriterImpl::Finish()
5755fb1c6ffSOliver Tappe{
5765fb1c6ffSOliver Tappe	try {
57700bc8e9cSIngo Weinhold		if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) {
57800bc8e9cSIngo Weinhold			_UpdateCheckEntryCollisions();
57900bc8e9cSIngo Weinhold
58000bc8e9cSIngo Weinhold			if (fPackageInfo.InitCheck() != B_OK)
58100bc8e9cSIngo Weinhold				_UpdateReadPackageInfo();
58200bc8e9cSIngo Weinhold		}
58300bc8e9cSIngo Weinhold
584d77c6cd2SOliver Tappe		if (fPackageInfo.InitCheck() != B_OK) {
5857fd711efSOliver Tappe			fListener->PrintError("No package-info file found (%s)!\n",
5867fd711efSOliver Tappe				B_HPKG_PACKAGE_INFO_FILE_NAME);
5877fd711efSOliver Tappe			return B_BAD_DATA;
5887fd711efSOliver Tappe		}
589d77c6cd2SOliver Tappe
5906ae0ecd4SIngo Weinhold		fPackageInfo.SetInstallPath(fInstallPath);
5916ae0ecd4SIngo Weinhold
592e6ebdaafSIngo Weinhold		RegisterPackageInfo(PackageAttributes(), fPackageInfo);
593e6ebdaafSIngo Weinhold
5947efa133cSIngo Weinhold		if (fCheckLicenses) {
5957efa133cSIngo Weinhold			status_t result = _CheckLicenses();
5967efa133cSIngo Weinhold			if (result != B_OK)
5977efa133cSIngo Weinhold				return result;
5987efa133cSIngo Weinhold		}
599d77c6cd2SOliver Tappe
60000bc8e9cSIngo Weinhold		if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0)
60100bc8e9cSIngo Weinhold			_CompactHeap();
60200bc8e9cSIngo Weinhold
6035fb1c6ffSOliver Tappe		return _Finish();
6045fb1c6ffSOliver Tappe	} catch (status_t error) {
6055fb1c6ffSOliver Tappe		return error;
6065fb1c6ffSOliver Tappe	} catch (std::bad_alloc) {
6077fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
6085fb1c6ffSOliver Tappe		return B_NO_MEMORY;
6095fb1c6ffSOliver Tappe	}
6105fb1c6ffSOliver Tappe}
6115fb1c6ffSOliver Tappe
6125fb1c6ffSOliver Tappe
6135fb1c6ffSOliver Tappestatus_t
614796343edSIngo WeinholdPackageWriterImpl::_Init(const char* fileName,
615796343edSIngo Weinhold	const BPackageWriterParameters& parameters)
6165fb1c6ffSOliver Tappe{
617695a1b24SIngo Weinhold	status_t result = inherited::Init(fileName, sizeof(hpkg_header),
618695a1b24SIngo Weinhold		parameters);
619f2022173SOliver Tappe	if (result != B_OK)
620f2022173SOliver Tappe		return result;
621f2022173SOliver Tappe
622f2022173SOliver Tappe	if (fStringCache.Init() != B_OK)
6235fb1c6ffSOliver Tappe		throw std::bad_alloc();
6245fb1c6ffSOliver Tappe
6255fb1c6ffSOliver Tappe	// create entry list
6260f9a98a4SIngo Weinhold	fRootEntry = new Entry(NULL, 0, -1, true);
6275fb1c6ffSOliver Tappe
62833bc4425SOliver Tappe	fRootAttribute = new Attribute();
6295fb1c6ffSOliver Tappe
6301f633814SIngo Weinhold	fHeapOffset = fHeaderSize = sizeof(hpkg_header);
6315fb1c6ffSOliver Tappe	fTopAttribute = fRootAttribute;
6325fb1c6ffSOliver Tappe
633c9ed1ea2SIngo Weinhold	fHeapRangesToRemove = new RangeArray<uint64>;
634c9ed1ea2SIngo Weinhold
63500bc8e9cSIngo Weinhold	// in update mode, parse the TOC
63600bc8e9cSIngo Weinhold	if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) {
63700bc8e9cSIngo Weinhold		PackageReaderImpl packageReader(fListener);
638d59e0febSIngo Weinhold		result = packageReader.Init(FD(), false, 0);
63900bc8e9cSIngo Weinhold		if (result != B_OK)
64000bc8e9cSIngo Weinhold			return result;
64100bc8e9cSIngo Weinhold
64200bc8e9cSIngo Weinhold		fHeapOffset = packageReader.HeapOffset();
64300bc8e9cSIngo Weinhold
6441f633814SIngo Weinhold		PackageContentHandler handler(fRootAttribute, fListener, fStringCache);
64500bc8e9cSIngo Weinhold
64600bc8e9cSIngo Weinhold		result = packageReader.ParseContent(&handler);
64700bc8e9cSIngo Weinhold		if (result != B_OK)
64800bc8e9cSIngo Weinhold			return result;
64900bc8e9cSIngo Weinhold
65046122852SIngo Weinhold		fHeapWriter->Reinit(packageReader.RawHeapReader());
651c9ed1ea2SIngo Weinhold
652c9ed1ea2SIngo Weinhold		// Remove the old packages attributes and TOC section from the heap.
653c9ed1ea2SIngo Weinhold		// We'll write new ones later.
654c9ed1ea2SIngo Weinhold		const PackageFileSection& attributesSection
655c9ed1ea2SIngo Weinhold			= packageReader.PackageAttributesSection();
656c9ed1ea2SIngo Weinhold		const PackageFileSection& tocSection = packageReader.TOCSection();
657c9ed1ea2SIngo Weinhold		if (!fHeapRangesToRemove->AddRange(attributesSection.offset,
658c9ed1ea2SIngo Weinhold				attributesSection.uncompressedLength)
659c9ed1ea2SIngo Weinhold		   || !fHeapRangesToRemove->AddRange(tocSection.offset,
660c9ed1ea2SIngo Weinhold				tocSection.uncompressedLength)) {
661c9ed1ea2SIngo Weinhold			throw std::bad_alloc();
662c9ed1ea2SIngo Weinhold		}
66300bc8e9cSIngo Weinhold	}
66400bc8e9cSIngo Weinhold
6655fb1c6ffSOliver Tappe	return B_OK;
6665fb1c6ffSOliver Tappe}
6675fb1c6ffSOliver Tappe
6685fb1c6ffSOliver Tappe
669d77c6cd2SOliver Tappestatus_t
670d77c6cd2SOliver TappePackageWriterImpl::_CheckLicenses()
671d77c6cd2SOliver Tappe{
672d77c6cd2SOliver Tappe	BPath systemLicensePath;
673d77c6cd2SOliver Tappe	status_t result
6747162cff6SIngo Weinhold#ifdef HAIKU_TARGET_PLATFORM_HAIKU
675d77c6cd2SOliver Tappe		= find_directory(B_SYSTEM_DATA_DIRECTORY, &systemLicensePath);
6767162cff6SIngo Weinhold#else
6777162cff6SIngo Weinhold		= systemLicensePath.SetTo(HAIKU_BUILD_SYSTEM_DATA_DIRECTORY);
6787162cff6SIngo Weinhold#endif
679d77c6cd2SOliver Tappe	if (result != B_OK) {
68086cdd3f8SAxel Dörfler		fListener->PrintError("unable to find system data path: %s!\n",
68186cdd3f8SAxel Dörfler			strerror(result));
682d77c6cd2SOliver Tappe		return result;
683d77c6cd2SOliver Tappe	}
684d77c6cd2SOliver Tappe	if ((result = systemLicensePath.Append("licenses")) != B_OK) {
685d77c6cd2SOliver Tappe		fListener->PrintError("unable to append to system data path!\n");
686d77c6cd2SOliver Tappe		return result;
687d77c6cd2SOliver Tappe	}
688d77c6cd2SOliver Tappe
689d77c6cd2SOliver Tappe	BDirectory systemLicenseDir(systemLicensePath.Path());
690d77c6cd2SOliver Tappe
6919968845dSIngo Weinhold	const BStringList& licenseList = fPackageInfo.LicenseList();
6929968845dSIngo Weinhold	for (int i = 0; i < licenseList.CountStrings(); ++i) {
6939968845dSIngo Weinhold		const BString& licenseName = licenseList.StringAt(i);
6947ea4dbceSIngo Weinhold		if (licenseName == kPublicDomainLicenseName)
6957ea4dbceSIngo Weinhold			continue;
6967ea4dbceSIngo Weinhold
697d77c6cd2SOliver Tappe		BEntry license;
698d77c6cd2SOliver Tappe		if (systemLicenseDir.FindEntry(licenseName.String(), &license) == B_OK)
699d77c6cd2SOliver Tappe			continue;
700d77c6cd2SOliver Tappe
701d77c6cd2SOliver Tappe		// license is not a system license, so it must be contained in package
70200bc8e9cSIngo Weinhold		BString licensePath("data/licenses/");
70300bc8e9cSIngo Weinhold		licensePath << licenseName;
70400bc8e9cSIngo Weinhold
70500bc8e9cSIngo Weinhold		if (!_IsEntryInPackage(licensePath)) {
706d77c6cd2SOliver Tappe			fListener->PrintError("License '%s' isn't contained in package!\n",
707d77c6cd2SOliver Tappe				licenseName.String());
708d77c6cd2SOliver Tappe			return B_BAD_DATA;
709d77c6cd2SOliver Tappe		}
710d77c6cd2SOliver Tappe	}
711d77c6cd2SOliver Tappe
712d77c6cd2SOliver Tappe	return B_OK;
713d77c6cd2SOliver Tappe}
714d77c6cd2SOliver Tappe
715d77c6cd2SOliver Tappe
71600bc8e9cSIngo Weinholdbool
71700bc8e9cSIngo WeinholdPackageWriterImpl::_IsEntryInPackage(const char* fileName)
71800bc8e9cSIngo Weinhold{
71900bc8e9cSIngo Weinhold	const char* originalFileName = fileName;
72000bc8e9cSIngo Weinhold
72100bc8e9cSIngo Weinhold	// find the closest ancestor of the entry that is in the added entries
72200bc8e9cSIngo Weinhold	bool added = false;
72300bc8e9cSIngo Weinhold	Entry* entry = fRootEntry;
72400bc8e9cSIngo Weinhold	while (entry != NULL) {
72500bc8e9cSIngo Weinhold		if (!entry->IsImplicit()) {
72600bc8e9cSIngo Weinhold			added = true;
72700bc8e9cSIngo Weinhold			break;
72800bc8e9cSIngo Weinhold		}
72900bc8e9cSIngo Weinhold
73000bc8e9cSIngo Weinhold		if (*fileName == '\0')
73100bc8e9cSIngo Weinhold			break;
73200bc8e9cSIngo Weinhold
73300bc8e9cSIngo Weinhold		const char* nextSlash = strchr(fileName, '/');
73400bc8e9cSIngo Weinhold
73500bc8e9cSIngo Weinhold		if (nextSlash == NULL) {
736