15fb1c6ffSOliver Tappe/*
232832cbeSIngo Weinhold * Copyright 2009-2014, 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/DataReader.h>
41cdfeba5aSIngo Weinhold#include <package/hpkg/PackageFileHeapReader.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// #pragma mark - Attributes
635fb1c6ffSOliver Tappe
645fb1c6ffSOliver Tappe
655fb1c6ffSOliver Tappestruct PackageWriterImpl::Attribute
665fb1c6ffSOliver Tappe	: public DoublyLinkedListLinkImpl<Attribute> {
6733bc4425SOliver Tappe	BHPKGAttributeID			id;
685fb1c6ffSOliver Tappe	AttributeValue				value;
695fb1c6ffSOliver Tappe	DoublyLinkedList<Attribute>	children;
705fb1c6ffSOliver Tappe
7133bc4425SOliver Tappe	Attribute(BHPKGAttributeID id_ = B_HPKG_ATTRIBUTE_ID_ENUM_COUNT)
725fb1c6ffSOliver Tappe		:
7333bc4425SOliver Tappe		id(id_)
745fb1c6ffSOliver Tappe	{
755fb1c6ffSOliver Tappe	}
765fb1c6ffSOliver Tappe
775fb1c6ffSOliver Tappe	~Attribute()
785fb1c6ffSOliver Tappe	{
795fb1c6ffSOliver Tappe		DeleteChildren();
805fb1c6ffSOliver Tappe	}
815fb1c6ffSOliver Tappe
825fb1c6ffSOliver Tappe	void AddChild(Attribute* child)
835fb1c6ffSOliver Tappe	{
845fb1c6ffSOliver Tappe		children.Add(child);
855fb1c6ffSOliver Tappe	}
865fb1c6ffSOliver Tappe
8700bc8e9cSIngo Weinhold	void RemoveChild(Attribute* child)
8800bc8e9cSIngo Weinhold	{
8900bc8e9cSIngo Weinhold		children.Remove(child);
9000bc8e9cSIngo Weinhold	}
9100bc8e9cSIngo Weinhold
925fb1c6ffSOliver Tappe	void DeleteChildren()
935fb1c6ffSOliver Tappe	{
945fb1c6ffSOliver Tappe		while (Attribute* child = children.RemoveHead())
955fb1c6ffSOliver Tappe			delete child;
965fb1c6ffSOliver Tappe	}
9700bc8e9cSIngo Weinhold
9800bc8e9cSIngo Weinhold	Attribute* FindEntryChild(const char* fileName) const
9900bc8e9cSIngo Weinhold	{
10000bc8e9cSIngo Weinhold		for (DoublyLinkedList<Attribute>::ConstIterator it
10100bc8e9cSIngo Weinhold				= children.GetIterator(); Attribute* child = it.Next();) {
10200bc8e9cSIngo Weinhold			if (child->id != B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY)
10300bc8e9cSIngo Weinhold				continue;
10400bc8e9cSIngo Weinhold			if (child->value.type != B_HPKG_ATTRIBUTE_TYPE_STRING)
10500bc8e9cSIngo Weinhold				continue;
10600bc8e9cSIngo Weinhold			const char* childName = child->value.string->string;
10700bc8e9cSIngo Weinhold			if (strcmp(fileName, childName) == 0)
10800bc8e9cSIngo Weinhold				return child;
10900bc8e9cSIngo Weinhold		}
11000bc8e9cSIngo Weinhold
11100bc8e9cSIngo Weinhold		return NULL;
11200bc8e9cSIngo Weinhold	}
11300bc8e9cSIngo Weinhold
11400bc8e9cSIngo Weinhold	Attribute* FindEntryChild(const char* fileName, size_t nameLength) const
11500bc8e9cSIngo Weinhold	{
11600bc8e9cSIngo Weinhold		BString name(fileName, nameLength);
11700bc8e9cSIngo Weinhold		return (size_t)name.Length() == nameLength
11800bc8e9cSIngo Weinhold			? FindEntryChild(name) : NULL;
11900bc8e9cSIngo Weinhold	}
12000bc8e9cSIngo Weinhold
12100bc8e9cSIngo Weinhold	Attribute* FindNodeAttributeChild(const char* attributeName) const
12200bc8e9cSIngo Weinhold	{
12300bc8e9cSIngo Weinhold		for (DoublyLinkedList<Attribute>::ConstIterator it
12400bc8e9cSIngo Weinhold				= children.GetIterator(); Attribute* child = it.Next();) {
12500bc8e9cSIngo Weinhold			if (child->id != B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE)
12600bc8e9cSIngo Weinhold				continue;
12700bc8e9cSIngo Weinhold			if (child->value.type != B_HPKG_ATTRIBUTE_TYPE_STRING)
12800bc8e9cSIngo Weinhold				continue;
12900bc8e9cSIngo Weinhold			const char* childName = child->value.string->string;
13000bc8e9cSIngo Weinhold			if (strcmp(attributeName, childName) == 0)
13100bc8e9cSIngo Weinhold				return child;
13200bc8e9cSIngo Weinhold		}
13300bc8e9cSIngo Weinhold
13400bc8e9cSIngo Weinhold		return NULL;
13500bc8e9cSIngo Weinhold	}
13600bc8e9cSIngo Weinhold
13700bc8e9cSIngo Weinhold	Attribute* ChildWithID(BHPKGAttributeID id) const
13800bc8e9cSIngo Weinhold	{
13900bc8e9cSIngo Weinhold		for (DoublyLinkedList<Attribute>::ConstIterator it
14000bc8e9cSIngo Weinhold				= children.GetIterator(); Attribute* child = it.Next();) {
14100bc8e9cSIngo Weinhold			if (child->id == id)
14200bc8e9cSIngo Weinhold				return child;
14300bc8e9cSIngo Weinhold		}
14400bc8e9cSIngo Weinhold
14500bc8e9cSIngo Weinhold		return NULL;
14600bc8e9cSIngo Weinhold	}
14700bc8e9cSIngo Weinhold};
14800bc8e9cSIngo Weinhold
14900bc8e9cSIngo Weinhold
15000bc8e9cSIngo Weinhold// #pragma mark - PackageContentHandler
15100bc8e9cSIngo Weinhold
15200bc8e9cSIngo Weinhold
15300bc8e9cSIngo Weinholdstruct PackageWriterImpl::PackageContentHandler
15400bc8e9cSIngo Weinhold	: BLowLevelPackageContentHandler {
15500bc8e9cSIngo Weinhold	PackageContentHandler(Attribute* rootAttribute, BErrorOutput* errorOutput,
1561f633814SIngo Weinhold		StringCache& stringCache)
15700bc8e9cSIngo Weinhold		:
15800bc8e9cSIngo Weinhold		fErrorOutput(errorOutput),
15900bc8e9cSIngo Weinhold		fStringCache(stringCache),
16000bc8e9cSIngo Weinhold		fRootAttribute(rootAttribute),
16100bc8e9cSIngo Weinhold		fErrorOccurred(false)
16200bc8e9cSIngo Weinhold	{
16300bc8e9cSIngo Weinhold	}
16400bc8e9cSIngo Weinhold
16500bc8e9cSIngo Weinhold	virtual status_t HandleSectionStart(BHPKGPackageSectionID sectionID,
16600bc8e9cSIngo Weinhold		bool& _handleSection)
16700bc8e9cSIngo Weinhold	{
16800bc8e9cSIngo Weinhold		// we're only interested in the TOC
16900bc8e9cSIngo Weinhold		_handleSection = sectionID == B_HPKG_SECTION_PACKAGE_TOC;
17000bc8e9cSIngo Weinhold		return B_OK;
17100bc8e9cSIngo Weinhold	}
17200bc8e9cSIngo Weinhold
17300bc8e9cSIngo Weinhold	virtual status_t HandleSectionEnd(BHPKGPackageSectionID sectionID)
17400bc8e9cSIngo Weinhold	{
17500bc8e9cSIngo Weinhold		return B_OK;
17600bc8e9cSIngo Weinhold	}
17700bc8e9cSIngo Weinhold
17800bc8e9cSIngo Weinhold	virtual status_t HandleAttribute(BHPKGAttributeID attributeID,
17900bc8e9cSIngo Weinhold		const BPackageAttributeValue& value, void* parentToken, void*& _token)
18000bc8e9cSIngo Weinhold	{
18100bc8e9cSIngo Weinhold		if (fErrorOccurred)
18200bc8e9cSIngo Weinhold			return B_OK;
18300bc8e9cSIngo Weinhold
18400bc8e9cSIngo Weinhold		Attribute* parentAttribute = parentToken != NULL
18500bc8e9cSIngo Weinhold			? (Attribute*)parentToken : fRootAttribute;
18600bc8e9cSIngo Weinhold
18700bc8e9cSIngo Weinhold		Attribute* attribute = new Attribute(attributeID);
18800bc8e9cSIngo Weinhold		parentAttribute->AddChild(attribute);
18900bc8e9cSIngo Weinhold
19000bc8e9cSIngo Weinhold		switch (value.type) {
19100bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_INT:
19200bc8e9cSIngo Weinhold				attribute->value.SetTo(value.signedInt);
19300bc8e9cSIngo Weinhold				break;
19400bc8e9cSIngo Weinhold
19500bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_UINT:
19600bc8e9cSIngo Weinhold				attribute->value.SetTo(value.unsignedInt);
19700bc8e9cSIngo Weinhold				break;
19800bc8e9cSIngo Weinhold
19900bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_STRING:
20000bc8e9cSIngo Weinhold			{
20100bc8e9cSIngo Weinhold				CachedString* string = fStringCache.Get(value.string);
20200bc8e9cSIngo Weinhold				if (string == NULL)
20300bc8e9cSIngo Weinhold					throw std::bad_alloc();
20400bc8e9cSIngo Weinhold				attribute->value.SetTo(string);
20500bc8e9cSIngo Weinhold				break;
20600bc8e9cSIngo Weinhold			}
20700bc8e9cSIngo Weinhold
20800bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_RAW:
20900bc8e9cSIngo Weinhold				if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
21000bc8e9cSIngo Weinhold					attribute->value.SetToData(value.data.size,
2111f633814SIngo Weinhold						value.data.offset);
21200bc8e9cSIngo Weinhold				} else if (value.encoding
21300bc8e9cSIngo Weinhold						== B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) {
21400bc8e9cSIngo Weinhold					attribute->value.SetToData(value.data.size, value.data.raw);
21500bc8e9cSIngo Weinhold				} else {
21600bc8e9cSIngo Weinhold					fErrorOutput->PrintError("Invalid attribute value encoding "
21700bc8e9cSIngo Weinhold						"%d (attribute %d)\n", value.encoding, attributeID);
21800bc8e9cSIngo Weinhold					return B_BAD_DATA;
21900bc8e9cSIngo Weinhold				}
22000bc8e9cSIngo Weinhold				break;
22100bc8e9cSIngo Weinhold
22200bc8e9cSIngo Weinhold			case B_HPKG_ATTRIBUTE_TYPE_INVALID:
22300bc8e9cSIngo Weinhold			default:
22400bc8e9cSIngo Weinhold				fErrorOutput->PrintError("Invalid attribute value type %d "
22500bc8e9cSIngo Weinhold					"(attribute %d)\n", value.type, attributeID);
22600bc8e9cSIngo Weinhold				return B_BAD_DATA;
22700bc8e9cSIngo Weinhold		}
22800bc8e9cSIngo Weinhold
22900bc8e9cSIngo Weinhold		_token = attribute;
23000bc8e9cSIngo Weinhold		return B_OK;
23100bc8e9cSIngo Weinhold	}
23200bc8e9cSIngo Weinhold
23300bc8e9cSIngo Weinhold	virtual status_t HandleAttributeDone(BHPKGAttributeID attributeID,
23400bc8e9cSIngo Weinhold		const BPackageAttributeValue& value, void* parentToken, void* token)
23500bc8e9cSIngo Weinhold	{
23600bc8e9cSIngo Weinhold		return B_OK;
23700bc8e9cSIngo Weinhold	}
23800bc8e9cSIngo Weinhold
23900bc8e9cSIngo Weinhold	virtual void HandleErrorOccurred()
24000bc8e9cSIngo Weinhold	{
24100bc8e9cSIngo Weinhold		fErrorOccurred = true;
24200bc8e9cSIngo Weinhold	}
24300bc8e9cSIngo Weinhold
24400bc8e9cSIngo Weinholdprivate:
24500bc8e9cSIngo Weinhold	BErrorOutput*	fErrorOutput;
24600bc8e9cSIngo Weinhold	StringCache&	fStringCache;
24700bc8e9cSIngo Weinhold	Attribute*		fRootAttribute;
24800bc8e9cSIngo Weinhold	bool			fErrorOccurred;
2495fb1c6ffSOliver Tappe};
2505fb1c6ffSOliver Tappe
2515fb1c6ffSOliver Tappe
252f2022173SOliver Tappe// #pragma mark - Entry
2535fb1c6ffSOliver Tappe
2545fb1c6ffSOliver Tappe
2555fb1c6ffSOliver Tappestruct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> {
2560f9a98a4SIngo Weinhold	Entry(char* name, size_t nameLength, int fd, bool isImplicit)
2575fb1c6ffSOliver Tappe		:
2585fb1c6ffSOliver Tappe		fName(name),
2595fb1c6ffSOliver Tappe		fNameLength(nameLength),
2600f9a98a4SIngo Weinhold		fFD(fd),
2615fb1c6ffSOliver Tappe		fIsImplicit(isImplicit)
2625fb1c6ffSOliver Tappe	{
2635fb1c6ffSOliver Tappe	}
2645fb1c6ffSOliver Tappe
2655fb1c6ffSOliver Tappe	~Entry()
2665fb1c6ffSOliver Tappe	{
2675fb1c6ffSOliver Tappe		DeleteChildren();
2685fb1c6ffSOliver Tappe		free(fName);
2695fb1c6ffSOliver Tappe	}
2705fb1c6ffSOliver Tappe
2710f9a98a4SIngo Weinhold	static Entry* Create(const char* name, size_t nameLength, int fd,
2720f9a98a4SIngo Weinhold		bool isImplicit)
2735fb1c6ffSOliver Tappe	{
2745fb1c6ffSOliver Tappe		char* clonedName = (char*)malloc(nameLength + 1);
2755fb1c6ffSOliver Tappe		if (clonedName == NULL)
2765fb1c6ffSOliver Tappe			throw std::bad_alloc();
2775fb1c6ffSOliver Tappe		memcpy(clonedName, name, nameLength);
2785fb1c6ffSOliver Tappe		clonedName[nameLength] = '\0';
2795fb1c6ffSOliver Tappe
2800f9a98a4SIngo Weinhold		Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, fd,
2815fb1c6ffSOliver Tappe			isImplicit);
2825fb1c6ffSOliver Tappe		if (entry == NULL) {
2835fb1c6ffSOliver Tappe			free(clonedName);
2845fb1c6ffSOliver Tappe			throw std::bad_alloc();
2855fb1c6ffSOliver Tappe		}
2865fb1c6ffSOliver Tappe
2875fb1c6ffSOliver Tappe		return entry;
2885fb1c6ffSOliver Tappe	}
2895fb1c6ffSOliver Tappe
2905fb1c6ffSOliver Tappe	const char* Name() const
2915fb1c6ffSOliver Tappe	{
2925fb1c6ffSOliver Tappe		return fName;
2935fb1c6ffSOliver Tappe	}
2945fb1c6ffSOliver Tappe
2950f9a98a4SIngo Weinhold	int FD() const
2960f9a98a4SIngo Weinhold	{
2970f9a98a4SIngo Weinhold		return fFD;
2980f9a98a4SIngo Weinhold	}
2990f9a98a4SIngo Weinhold
3000f9a98a4SIngo Weinhold	void SetFD(int fd)
3010f9a98a4SIngo Weinhold	{
3020f9a98a4SIngo Weinhold		fFD = fd;
3030f9a98a4SIngo Weinhold	}
3040f9a98a4SIngo Weinhold
3055fb1c6ffSOliver Tappe	bool IsImplicit() const
3065fb1c6ffSOliver Tappe	{
3075fb1c6ffSOliver Tappe		return fIsImplicit;
3085fb1c6ffSOliver Tappe	}
3095fb1c6ffSOliver Tappe
3105fb1c6ffSOliver Tappe	void SetImplicit(bool isImplicit)
3115fb1c6ffSOliver Tappe	{
3125fb1c6ffSOliver Tappe		fIsImplicit = isImplicit;
3135fb1c6ffSOliver Tappe	}
3145fb1c6ffSOliver Tappe
3155fb1c6ffSOliver Tappe	bool HasName(const char* name, size_t nameLength)
3165fb1c6ffSOliver Tappe	{
3175fb1c6ffSOliver Tappe		return nameLength == fNameLength
3185fb1c6ffSOliver Tappe			&& strncmp(name, fName, nameLength) == 0;
3195fb1c6ffSOliver Tappe	}
3205fb1c6ffSOliver Tappe
3215fb1c6ffSOliver Tappe	void AddChild(Entry* child)
3225fb1c6ffSOliver Tappe	{
3235fb1c6ffSOliver Tappe		fChildren.Add(child);
3245fb1c6ffSOliver Tappe	}
3255fb1c6ffSOliver Tappe
3265fb1c6ffSOliver Tappe	void DeleteChildren()
3275fb1c6ffSOliver Tappe	{
3285fb1c6ffSOliver Tappe		while (Entry* child = fChildren.RemoveHead())
3295fb1c6ffSOliver Tappe			delete child;
3305fb1c6ffSOliver Tappe	}
3315fb1c6ffSOliver Tappe
3325fb1c6ffSOliver Tappe	Entry* GetChild(const char* name, size_t nameLength) const
3335fb1c6ffSOliver Tappe	{
3345fb1c6ffSOliver Tappe		EntryList::ConstIterator it = fChildren.GetIterator();
3355fb1c6ffSOliver Tappe		while (Entry* child = it.Next()) {
3365fb1c6ffSOliver Tappe			if (child->HasName(name, nameLength))
3375fb1c6ffSOliver Tappe				return child;
3385fb1c6ffSOliver Tappe		}
3395fb1c6ffSOliver Tappe
3405fb1c6ffSOliver Tappe		return NULL;
3415fb1c6ffSOliver Tappe	}
3425fb1c6ffSOliver Tappe
3435fb1c6ffSOliver Tappe	EntryList::ConstIterator ChildIterator() const
3445fb1c6ffSOliver Tappe	{
3455fb1c6ffSOliver Tappe		return fChildren.GetIterator();
3465fb1c6ffSOliver Tappe	}
3475fb1c6ffSOliver Tappe
3485fb1c6ffSOliver Tappeprivate:
3495fb1c6ffSOliver Tappe	char*		fName;
3505fb1c6ffSOliver Tappe	size_t		fNameLength;
3510f9a98a4SIngo Weinhold	int			fFD;
3525fb1c6ffSOliver Tappe	bool		fIsImplicit;
3535fb1c6ffSOliver Tappe	EntryList	fChildren;
3545fb1c6ffSOliver Tappe};
3555fb1c6ffSOliver Tappe
3565fb1c6ffSOliver Tappe
357f2022173SOliver Tappe// #pragma mark - SubPathAdder
3585fb1c6ffSOliver Tappe
3595fb1c6ffSOliver Tappe
3607fd711efSOliver Tappestruct PackageWriterImpl::SubPathAdder {
3618524dd36SIngo Weinhold	SubPathAdder(BErrorOutput* errorOutput, char* pathBuffer,
3628524dd36SIngo Weinhold		const char* subPath)
3638524dd36SIngo Weinhold		:
3648524dd36SIngo Weinhold		fOriginalPathEnd(pathBuffer + strlen(pathBuffer))
3657fd711efSOliver Tappe	{
3668524dd36SIngo Weinhold		if (fOriginalPathEnd != pathBuffer)
3678524dd36SIngo Weinhold			strlcat(pathBuffer, "/", B_PATH_NAME_LENGTH);
3688524dd36SIngo Weinhold
3698524dd36SIngo Weinhold		if (strlcat(pathBuffer, subPath, B_PATH_NAME_LENGTH)
3708524dd36SIngo Weinhold				>= B_PATH_NAME_LENGTH) {
3718524dd36SIngo Weinhold			*fOriginalPathEnd = '\0';
3728524dd36SIngo Weinhold			errorOutput->PrintError("Path too long: \"%s/%s\"\n", pathBuffer,
3738524dd36SIngo Weinhold				subPath);
3748524dd36SIngo Weinhold			throw status_t(B_BUFFER_OVERFLOW);
3758524dd36SIngo Weinhold		}
3767fd711efSOliver Tappe	}
3777fd711efSOliver Tappe
3787fd711efSOliver Tappe	~SubPathAdder()
3797fd711efSOliver Tappe	{
3807fd711efSOliver Tappe		*fOriginalPathEnd = '\0';
3817fd711efSOliver Tappe	}
3828524dd36SIngo Weinhold
3837fd711efSOliver Tappeprivate:
3847fd711efSOliver Tappe	char* fOriginalPathEnd;
3857fd711efSOliver Tappe};
3867fd711efSOliver Tappe
3877fd711efSOliver Tappe
38821ee6d5cSIngo Weinhold// #pragma mark - HeapAttributeOffsetter
38921ee6d5cSIngo Weinhold
39021ee6d5cSIngo Weinhold
39100bc8e9cSIngo Weinholdstruct PackageWriterImpl::HeapAttributeOffsetter {
3921f633814SIngo Weinhold	HeapAttributeOffsetter(const RangeArray<uint64>& ranges,
3931f633814SIngo Weinhold		const Array<uint64>& deltas)
39400bc8e9cSIngo Weinhold		:
39500bc8e9cSIngo Weinhold		fRanges(ranges),
39600bc8e9cSIngo Weinhold		fDeltas(deltas)
39700bc8e9cSIngo Weinhold	{
39800bc8e9cSIngo Weinhold	}
39900bc8e9cSIngo Weinhold
40000bc8e9cSIngo Weinhold	void ProcessAttribute(Attribute* attribute)
40100bc8e9cSIngo Weinhold	{
40200bc8e9cSIngo Weinhold		// If the attribute refers to a heap value, adjust it
40300bc8e9cSIngo Weinhold		AttributeValue& value = attribute->value;
40400bc8e9cSIngo Weinhold
40500bc8e9cSIngo Weinhold		if (value.type == B_HPKG_ATTRIBUTE_TYPE_RAW
40600bc8e9cSIngo Weinhold			&& value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
4071f633814SIngo Weinhold			uint64 delta = fDeltas[fRanges.InsertionIndex(value.data.offset)];
40800bc8e9cSIngo Weinhold			value.data.offset -= delta;
40900bc8e9cSIngo Weinhold		}
41000bc8e9cSIngo Weinhold
41100bc8e9cSIngo Weinhold		// recurse
41200bc8e9cSIngo Weinhold		for (DoublyLinkedList<Attribute>::Iterator it
41300bc8e9cSIngo Weinhold					= attribute->children.GetIterator();
41400bc8e9cSIngo Weinhold				Attribute* child = it.Next();) {
41500bc8e9cSIngo Weinhold			ProcessAttribute(child);
41600bc8e9cSIngo Weinhold		}
41700bc8e9cSIngo Weinhold	}
41800bc8e9cSIngo Weinhold
41900bc8e9cSIngo Weinholdprivate:
4201f633814SIngo Weinhold	const RangeArray<uint64>&	fRanges;
4211f633814SIngo Weinhold	const Array<uint64>&		fDeltas;
42200bc8e9cSIngo Weinhold};
42300bc8e9cSIngo Weinhold
42400bc8e9cSIngo Weinhold
4255fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl (Inline Methods)
4265fb1c6ffSOliver Tappe
4275fb1c6ffSOliver Tappe
4285fb1c6ffSOliver Tappetemplate<typename Type>
4295fb1c6ffSOliver Tappeinline PackageWriterImpl::Attribute*
43033bc4425SOliver TappePackageWriterImpl::_AddAttribute(BHPKGAttributeID attributeID, Type value)
4315fb1c6ffSOliver Tappe{
4325fb1c6ffSOliver Tappe	AttributeValue attributeValue;
4335fb1c6ffSOliver Tappe	attributeValue.SetTo(value);
43433bc4425SOliver Tappe	return _AddAttribute(attributeID, attributeValue);
4355fb1c6ffSOliver Tappe}
4365fb1c6ffSOliver Tappe
4375fb1c6ffSOliver Tappe
4385fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl
4395fb1c6ffSOliver Tappe
4405fb1c6ffSOliver Tappe
4417fd711efSOliver TappePackageWriterImpl::PackageWriterImpl(BPackageWriterListener* listener)
4425fb1c6ffSOliver Tappe	:
4431f633814SIngo Weinhold	inherited("package", listener),
4447fd711efSOliver Tappe	fListener(listener),
44500bc8e9cSIngo Weinhold	fHeapRangesToRemove(NULL),
4465fb1c6ffSOliver Tappe	fRootEntry(NULL),
4475fb1c6ffSOliver Tappe	fRootAttribute(NULL),
4487efa133cSIngo Weinhold	fTopAttribute(NULL),
4497efa133cSIngo Weinhold	fCheckLicenses(true)
4505fb1c6ffSOliver Tappe{
4515fb1c6ffSOliver Tappe}
4525fb1c6ffSOliver Tappe
4535fb1c6ffSOliver Tappe
4545fb1c6ffSOliver TappePackageWriterImpl::~PackageWriterImpl()
4555fb1c6ffSOliver Tappe{
456c9ed1ea2SIngo Weinhold	delete fHeapRangesToRemove;
4575fb1c6ffSOliver Tappe	delete fRootAttribute;
4585fb1c6ffSOliver Tappe	delete fRootEntry;
4595fb1c6ffSOliver Tappe}
4605fb1c6ffSOliver Tappe
4615fb1c6ffSOliver Tappe
4625fb1c6ffSOliver Tappestatus_t
463796343edSIngo WeinholdPackageWriterImpl::Init(const char* fileName,
464796343edSIngo Weinhold	const BPackageWriterParameters& parameters)
4655fb1c6ffSOliver Tappe{
4665fb1c6ffSOliver Tappe	try {
46744c47711SIngo Weinhold		return _Init(NULL, false, fileName, parameters);
46844c47711SIngo Weinhold	} catch (status_t error) {
46944c47711SIngo Weinhold		return error;
470b08627f3SMurai Takashi	} catch (std::bad_alloc&) {
47144c47711SIngo Weinhold		fListener->PrintError("Out of memory!\n");
47244c47711SIngo Weinhold		return B_NO_MEMORY;
47344c47711SIngo Weinhold	}
47444c47711SIngo Weinhold}
47544c47711SIngo Weinhold
47644c47711SIngo Weinhold
47744c47711SIngo Weinholdstatus_t
47844c47711SIngo WeinholdPackageWriterImpl::Init(BPositionIO* file, bool keepFile,
47944c47711SIngo Weinhold	const BPackageWriterParameters& parameters)
48044c47711SIngo Weinhold{
48144c47711SIngo Weinhold	try {
48244c47711SIngo Weinhold		return _Init(file, keepFile, NULL, parameters);
4835fb1c6ffSOliver Tappe	} catch (status_t error) {
4845fb1c6ffSOliver Tappe		return error;
485b08627f3SMurai Takashi	} catch (std::bad_alloc&) {
4867fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
4875fb1c6ffSOliver Tappe		return B_NO_MEMORY;
4885fb1c6ffSOliver Tappe	}
4895fb1c6ffSOliver Tappe}
4905fb1c6ffSOliver Tappe
4915fb1c6ffSOliver Tappe
4926ae0ecd4SIngo Weinholdstatus_t
4936ae0ecd4SIngo WeinholdPackageWriterImpl::SetInstallPath(const char* installPath)
4946ae0ecd4SIngo Weinhold{
4956ae0ecd4SIngo Weinhold	fInstallPath = installPath;
4966ae0ecd4SIngo Weinhold	return installPath == NULL
4976ae0ecd4SIngo Weinhold		|| (size_t)fInstallPath.Length() == strlen(installPath)
4986ae0ecd4SIngo Weinhold		? B_OK : B_NO_MEMORY;
4996ae0ecd4SIngo Weinhold}
5006ae0ecd4SIngo Weinhold
5016ae0ecd4SIngo Weinhold
5027efa133cSIngo Weinholdvoid
5037efa133cSIngo WeinholdPackageWriterImpl::SetCheckLicenses(bool checkLicenses)
5047efa133cSIngo Weinhold{
5057efa133cSIngo Weinhold	fCheckLicenses = checkLicenses;
5067efa133cSIngo Weinhold}
5077efa133cSIngo Weinhold
5087efa133cSIngo Weinhold
5095fb1c6ffSOliver Tappestatus_t
5100f9a98a4SIngo WeinholdPackageWriterImpl::AddEntry(const char* fileName, int fd)
5115fb1c6ffSOliver Tappe{
5125fb1c6ffSOliver Tappe	try {
5137fd711efSOliver Tappe		// if it's ".PackageInfo", parse it
5147fd711efSOliver Tappe		if (strcmp(fileName, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
5157fd711efSOliver Tappe			struct ErrorListener : public BPackageInfo::ParseErrorListener {
5167fd711efSOliver Tappe				ErrorListener(BPackageWriterListener* _listener)
517fc198cc3SIngo Weinhold					:
518fc198cc3SIngo Weinhold					listener(_listener),
519fc198cc3SIngo Weinhold					errorSeen(false)
520fc198cc3SIngo Weinhold				{
521fc198cc3SIngo Weinhold				}
522fc198cc3SIngo Weinhold
5237fd711efSOliver Tappe				virtual void OnError(const BString& msg, int line, int col) {
5247fd711efSOliver Tappe					listener->PrintError("Parse error in %s(%d:%d) -> %s\n",
5257fd711efSOliver Tappe						B_HPKG_PACKAGE_INFO_FILE_NAME, line, col, msg.String());
526fc198cc3SIngo Weinhold					errorSeen = true;
5277fd711efSOliver Tappe				}
528fc198cc3SIngo Weinhold
5297fd711efSOliver Tappe				BPackageWriterListener* listener;
530fc198cc3SIngo Weinhold				bool errorSeen;
5317fd711efSOliver Tappe			} errorListener(fListener);
5320f9a98a4SIngo Weinhold
5330f9a98a4SIngo Weinhold			if (fd >= 0) {
5340f9a98a4SIngo Weinhold				// a file descriptor is given -- read the config from there
5350f9a98a4SIngo Weinhold				// stat the file to get the file size
5360f9a98a4SIngo Weinhold				struct stat st;
5370f9a98a4SIngo Weinhold				if (fstat(fd, &st) != 0)
5380f9a98a4SIngo Weinhold					return errno;
5390f9a98a4SIngo Weinhold
5400f9a98a4SIngo Weinhold				BString packageInfoString;
5410f9a98a4SIngo Weinhold				char* buffer = packageInfoString.LockBuffer(st.st_size);
5420f9a98a4SIngo Weinhold				if (buffer == NULL)
5430f9a98a4SIngo Weinhold					return B_NO_MEMORY;
5440f9a98a4SIngo Weinhold
5450f9a98a4SIngo Weinhold				ssize_t result = read_pos(fd, 0, buffer, st.st_size);
5460f9a98a4SIngo Weinhold				if (result < 0) {
5470f9a98a4SIngo Weinhold					packageInfoString.UnlockBuffer(0);
5480f9a98a4SIngo Weinhold					return errno;
5490f9a98a4SIngo Weinhold				}
5500f9a98a4SIngo Weinhold
5510f9a98a4SIngo Weinhold				buffer[st.st_size] = '\0';
5520f9a98a4SIngo Weinhold				packageInfoString.UnlockBuffer(st.st_size);
5530f9a98a4SIngo Weinhold
5540f9a98a4SIngo Weinhold				result = fPackageInfo.ReadFromConfigString(packageInfoString,
5550f9a98a4SIngo Weinhold					&errorListener);
5560f9a98a4SIngo Weinhold				if (result != B_OK)
5570f9a98a4SIngo Weinhold					return result;
5580f9a98a4SIngo Weinhold			} else {
5590f9a98a4SIngo Weinhold				// use the file name
5600f9a98a4SIngo Weinhold				BEntry packageInfoEntry(fileName);
5610f9a98a4SIngo Weinhold				status_t result = fPackageInfo.ReadFromConfigFile(
5620f9a98a4SIngo Weinhold					packageInfoEntry, &errorListener);
5630f9a98a4SIngo Weinhold				if (result != B_OK
5640f9a98a4SIngo Weinhold					|| (result = fPackageInfo.InitCheck()) != B_OK) {
565fc198cc3SIngo Weinhold					if (!errorListener.errorSeen) {
566fc198cc3SIngo Weinhold						fListener->PrintError("Failed to read %s: %s\n",
567fc198cc3SIngo Weinhold							fileName, strerror(result));
568fc198cc3SIngo Weinhold					}
5690f9a98a4SIngo Weinhold					return result;
5700f9a98a4SIngo Weinhold				}
5710f9a98a4SIngo Weinhold			}
5727fd711efSOliver Tappe		}
5737fd711efSOliver Tappe
5740f9a98a4SIngo Weinhold		return _RegisterEntry(fileName, fd);
5755fb1c6ffSOliver Tappe	} catch (status_t error) {
5765fb1c6ffSOliver Tappe		return error;
577b08627f3SMurai Takashi	} catch (std::bad_alloc&) {
5787fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
5795fb1c6ffSOliver Tappe		return B_NO_MEMORY;
5805fb1c6ffSOliver Tappe	}
5815fb1c6ffSOliver Tappe}
5825fb1c6ffSOliver Tappe
5835fb1c6ffSOliver Tappe
5845fb1c6ffSOliver Tappestatus_t
5855fb1c6ffSOliver TappePackageWriterImpl::Finish()
5865fb1c6ffSOliver Tappe{
5875fb1c6ffSOliver Tappe	try {
58800bc8e9cSIngo Weinhold		if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) {
58900bc8e9cSIngo Weinhold			_UpdateCheckEntryCollisions();
59000bc8e9cSIngo Weinhold
59100bc8e9cSIngo Weinhold			if (fPackageInfo.InitCheck() != B_OK)
59200bc8e9cSIngo Weinhold				_UpdateReadPackageInfo();
59300bc8e9cSIngo Weinhold		}
59400bc8e9cSIngo Weinhold
595d77c6cd2SOliver Tappe		if (fPackageInfo.InitCheck() != B_OK) {
5967fd711efSOliver Tappe			fListener->PrintError("No package-info file found (%s)!\n",
5977fd711efSOliver Tappe				B_HPKG_PACKAGE_INFO_FILE_NAME);
5987fd711efSOliver Tappe			return B_BAD_DATA;
5997fd711efSOliver Tappe		}
600d77c6cd2SOliver Tappe
6016ae0ecd4SIngo Weinhold		fPackageInfo.SetInstallPath(fInstallPath);
6026ae0ecd4SIngo Weinhold
603e6ebdaafSIngo Weinhold		RegisterPackageInfo(PackageAttributes(), fPackageInfo);
604e6ebdaafSIngo Weinhold
6057efa133cSIngo Weinhold		if (fCheckLicenses) {
6067efa133cSIngo Weinhold			status_t result = _CheckLicenses();
6077efa133cSIngo Weinhold			if (result != B_OK)
6087efa133cSIngo Weinhold				return result;
6097efa133cSIngo Weinhold		}
610d77c6cd2SOliver Tappe
61100bc8e9cSIngo Weinhold		if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0)
61200bc8e9cSIngo Weinhold			_CompactHeap();
61300bc8e9cSIngo Weinhold
6145fb1c6ffSOliver Tappe		return _Finish();
6155fb1c6ffSOliver Tappe	} catch (status_t error) {
6165fb1c6ffSOliver Tappe		return error;
617b08627f3SMurai Takashi	} catch (std::bad_alloc&) {
6187fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
6195fb1c6ffSOliver Tappe		return B_NO_MEMORY;
6205fb1c6ffSOliver Tappe	}
6215fb1c6ffSOliver Tappe}
6225fb1c6ffSOliver Tappe
6235fb1c6ffSOliver Tappe
624cdfeba5aSIngo Weinholdstatus_t
625e1e6c124SIngo WeinholdPackageWriterImpl::Recompress(BPositionIO* inputFile)
626cdfeba5aSIngo Weinhold{
627e1e6c124SIngo Weinhold	if (inputFile == NULL)
628cdfeba5aSIngo Weinhold		return B_BAD_VALUE;
629cdfeba5aSIngo Weinhold
630cdfeba5aSIngo Weinhold	try {
631e1e6c124SIngo Weinhold		return _Recompress(inputFile);
632cdfeba5aSIngo Weinhold	} catch (status_t error) {
633cdfeba5aSIngo Weinhold		return error;
634b08627f3SMurai Takashi	} catch (std::bad_alloc&) {
635cdfeba5aSIngo Weinhold		fListener->PrintError("Out of memory!\n");
636cdfeba5aSIngo Weinhold		return B_NO_MEMORY;
637cdfeba5aSIngo Weinhold	}
638cdfeba5aSIngo Weinhold}
639cdfeba5aSIngo Weinhold
640cdfeba5aSIngo Weinhold
6415fb1c6ffSOliver Tappestatus_t
64244c47711SIngo WeinholdPackageWriterImpl::_Init(BPositionIO* file, bool keepFile, const char* fileName,
643796343edSIngo Weinhold	const BPackageWriterParameters& parameters)
6445fb1c6ffSOliver Tappe{
64544c47711SIngo Weinhold	status_t result = inherited::Init(file, keepFile, fileName, parameters);
646f2022173SOliver Tappe	if (result != B_OK)
647f2022173SOliver Tappe		return result;
648f2022173SOliver Tappe
649f2022173SOliver Tappe	if (fStringCache.Init() != B_OK)
6505fb1c6ffSOliver Tappe		throw std::bad_alloc();
6515fb1c6ffSOliver Tappe
6525fb1c6ffSOliver Tappe	// create entry list
6530f9a98a4SIngo Weinhold	fRootEntry = new Entry(NULL, 0, -1, true);
6545fb1c6ffSOliver Tappe
65533bc4425SOliver Tappe	fRootAttribute = new Attribute();
6565fb1c6ffSOliver Tappe
6571f633814SIngo Weinhold	fHeapOffset = fHeaderSize = sizeof(hpkg_header);
6585fb1c6ffSOliver Tappe	fTopAttribute = fRootAttribute;
6595fb1c6ffSOliver Tappe
660c9ed1ea2SIngo Weinhold	fHeapRangesToRemove = new RangeArray<uint64>;
661c9ed1ea2SIngo Weinhold
66200bc8e9cSIngo Weinhold	// in update mode, parse the TOC
66300bc8e9cSIngo Weinhold	if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) {
66400bc8e9cSIngo Weinhold		PackageReaderImpl packageReader(fListener);
6658f5130edSIngo Weinhold		hpkg_header header;
6668f5130edSIngo Weinhold		result = packageReader.Init(File(), false, 0, &header);
66700bc8e9cSIngo Weinhold		if (result != B_OK)
66800bc8e9cSIngo Weinhold			return result;
66900bc8e9cSIngo Weinhold
67000bc8e9cSIngo Weinhold		fHeapOffset = packageReader.HeapOffset();
67100bc8e9cSIngo Weinhold
6721f633814SIngo Weinhold		PackageContentHandler handler(fRootAttribute, fListener, fStringCache);
67300bc8e9cSIngo Weinhold
67400bc8e9cSIngo Weinhold		result = packageReader.ParseContent(&handler);
67500bc8e9cSIngo Weinhold		if (result != B_OK)
67600bc8e9cSIngo Weinhold			return result;
67700bc8e9cSIngo Weinhold
6788f5130edSIngo Weinhold		// While the compression level can change, we have to reuse the
6798f5130edSIngo Weinhold		// compression algorithm at least.
6808f5130edSIngo Weinhold		SetCompression(B_BENDIAN_TO_HOST_INT16(header.heap_compression));
6818f5130edSIngo Weinhold
6828f5130edSIngo Weinhold		result = InitHeapReader(fHeapOffset);
6838f5130edSIngo Weinhold		if (result != B_OK)
6848f5130edSIngo Weinhold			return result;
6858f5130edSIngo Weinhold
68646122852SIngo Weinhold		fHeapWriter->Reinit(packageReader.RawHeapReader());
687c9ed1ea2SIngo Weinhold
688c9ed1ea2SIngo Weinhold		// Remove the old packages attributes and TOC section from the heap.
689c9ed1ea2SIngo Weinhold		// We'll write new ones later.
690c9ed1ea2SIngo Weinhold		const PackageFileSection& attributesSection
691c9ed1ea2SIngo Weinhold			= packageReader.PackageAttributesSection();
692c9ed1ea2SIngo Weinhold		const PackageFileSection& tocSection = packageReader.TOCSection();
693c9ed1ea2SIngo Weinhold		if (!fHeapRangesToRemove->AddRange(attributesSection.offset,
694c9ed1ea2SIngo Weinhold				attributesSection.uncompressedLength)
695c9ed1ea2SIngo Weinhold		   || !fHeapRangesToRemove->AddRange(tocSection.offset,
696c9ed1ea2SIngo Weinhold				tocSection.uncompressedLength)) {
697c9ed1ea2SIngo Weinhold			throw std::bad_alloc();
698c9ed1ea2SIngo Weinhold		}
6998f5130edSIngo Weinhold	} else {
7008f5130edSIngo Weinhold		result = InitHeapReader(fHeapOffset);
7018f5130edSIngo Weinhold		if (result != B_OK)
7028f5130edSIngo Weinhold			return result;
70300bc8e9cSIngo Weinhold	}
70400bc8e9cSIngo Weinhold
7055fb1c6ffSOliver Tappe	return B_OK;
7065fb1c6ffSOliver Tappe}
7075fb1c6ffSOliver Tappe
7085fb1c6ffSOliver Tappe
7092fc2aebcSIngo Weinholdstatus_t
7102fc2aebcSIngo WeinholdPackageWriterImpl::_Finish()
7112fc2aebcSIngo Weinhold{
7122fc2aebcSIngo Weinhold	// write entries
7132fc2aebcSIngo Weinhold	for (EntryList::ConstIterator it = fRootEntry->ChildIterator();
7142fc2aebcSIngo Weinhold			Entry* entry = it.Next();) {
7152fc2aebcSIngo Weinhold		char pathBuffer[B_PATH_NAME_LENGTH];
7162fc2aebcSIngo Weinhold		pathBuffer[0] = '\0';
7172fc2aebcSIngo Weinhold		_AddEntry(AT_FDCWD, entry, entry->Name(), pathBuffer);
7182fc2aebcSIngo Weinhold	}
7192fc2aebcSIngo Weinhold
7202fc2aebcSIngo Weinhold	hpkg_header header;
7212fc2aebcSIngo Weinhold
7222fc2aebcSIngo Weinhold	// write the TOC and package attributes
7232fc2aebcSIngo Weinhold	uint64 tocLength;
7242fc2aebcSIngo Weinhold	_WriteTOC(header, tocLength);
7252fc2aebcSIngo Weinhold
7262fc2aebcSIngo Weinhold	uint64 attributesLength;
7272fc2aebcSIngo Weinhold	_WritePackageAttributes(header, attributesLength);
7282fc2aebcSIngo Weinhold
7292fc2aebcSIngo Weinhold	// flush the heap
7302fc2aebcSIngo Weinhold	status_t error = fHeapWriter->Finish();
7312fc2aebcSIngo Weinhold	if (error != B_OK)
7322fc2aebcSIngo Weinhold		return error;
7332fc2aebcSIngo Weinhold
7342fc2aebcSIngo Weinhold	uint64 compressedHeapSize = fHeapWriter->CompressedHeapSize();
7352fc2aebcSIngo Weinhold
7368f5130edSIngo Weinhold	header.heap_compression = B_HOST_TO_BENDIAN_INT16(
7378f5130edSIngo Weinhold		Parameters().Compression());
7382fc2aebcSIngo Weinhold	header.heap_chunk_size = B_HOST_TO_BENDIAN_INT32(fHeapWriter->ChunkSize());
7392fc2aebcSIngo Weinhold	header.heap_size_compressed = B_HOST_TO_BENDIAN_INT64(compressedHeapSize);
7402fc2aebcSIngo Weinhold	header.heap_size_uncompressed = B_HOST_TO_BENDIAN_INT64(
7412fc2aebcSIngo Weinhold		fHeapWriter->UncompressedHeapSize());
7422fc2aebcSIngo Weinhold
7432fc2aebcSIngo Weinhold	// Truncate the file to the size it is supposed to have. In update mode, it
7442fc2aebcSIngo Weinhold	// can be greater when one or more files are shrunk. In creation mode it
7452fc2aebcSIngo Weinhold	// should already have the correct size.
7462fc2aebcSIngo Weinhold	off_t totalSize = fHeapWriter->HeapOffset() + (off_t)compressedHeapSize;
747e527b796SIngo Weinhold	error = File()->SetSize(totalSize);
748e527b796SIngo Weinhold	if (error != B_OK) {
7492fc2aebcSIngo Weinhold		fListener->PrintError("Failed to truncate package file to new "
7502fc2aebcSIngo Weinhold			"size: %s\n", strerror(errno));
7512fc2aebcSIngo Weinhold		return errno;
7522fc2aebcSIngo Weinhold	}
7532fc2aebcSIngo Weinhold
7542fc2aebcSIngo Weinhold	fListener->OnPackageSizeInfo(fHeaderSize, compressedHeapSize, tocLength,
7552fc2aebcSIngo Weinhold		attributesLength, totalSize);
7562fc2aebcSIngo Weinhold
7572fc2aebcSIngo Weinhold	// prepare the header
7582fc2aebcSIngo Weinhold
7592fc2aebcSIngo Weinhold	// general
7602fc2aebcSIngo Weinhold	header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC);
7612fc2aebcSIngo Weinhold	header.header_size = B_HOST_TO_BENDIAN_INT16(fHeaderSize);
7622fc2aebcSIngo Weinhold	header.version = B_HOST_TO_BENDIAN_INT16(B_