PackageWriterImpl.cpp revision 7ea4dbce
15fb1c6ffSOliver Tappe/*
27162cff6SIngo Weinhold * Copyright 2009-2011, 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
295fb1c6ffSOliver Tappe#include <AutoDeleter.h>
305fb1c6ffSOliver Tappe
3133bc4425SOliver Tappe#include <package/hpkg/HPKGDefsPrivate.h>
325fb1c6ffSOliver Tappe
335fb1c6ffSOliver Tappe#include <package/hpkg/DataOutput.h>
345fb1c6ffSOliver Tappe#include <package/hpkg/DataReader.h>
355fb1c6ffSOliver Tappe#include <package/hpkg/Stacker.h>
365fb1c6ffSOliver Tappe
375fb1c6ffSOliver Tappe
3815a5c3f7SOliver Tappeusing BPrivate::FileDescriptorCloser;
3915a5c3f7SOliver Tappe
4015a5c3f7SOliver Tappe
417ea4dbceSIngo Weinholdstatic const char* const kPublicDomainLicenseName = "Public Domain";
427ea4dbceSIngo Weinhold
437ea4dbceSIngo Weinhold
44caa4217eSIngo Weinhold// We need to remap a few file operations on non-Haiku platforms, so dealing
45caa4217eSIngo Weinhold// with symlinks works correctly.
46caa4217eSIngo Weinhold#ifndef __HAIKU__
47caa4217eSIngo Weinhold
48caa4217eSIngo Weinhold
49caa4217eSIngo Weinholdextern "C" int _kern_open(int fd, const char *path, int openMode, int perms);
50caa4217eSIngo Weinholdextern "C" status_t _kern_close(int fd);
51caa4217eSIngo Weinholdextern "C" status_t _kern_read_stat(int fd, const char *path, bool traverseLink,
52caa4217eSIngo Weinhold	struct stat *st, size_t statSize);
53caa4217eSIngo Weinhold
54caa4217eSIngo Weinhold
55caa4217eSIngo Weinholdstatic int
56caa4217eSIngo Weinholdbuild_openat(int dirFD, const char* fileName, int openMode, int permissions)
57caa4217eSIngo Weinhold{
58caa4217eSIngo Weinhold	int fd = _kern_open(dirFD, fileName, openMode, permissions);
59caa4217eSIngo Weinhold	if (fd < 0) {
60caa4217eSIngo Weinhold		errno = fd;
61caa4217eSIngo Weinhold		return -1;
62caa4217eSIngo Weinhold	}
63caa4217eSIngo Weinhold
64caa4217eSIngo Weinhold	return fd;
65caa4217eSIngo Weinhold}
66caa4217eSIngo Weinhold
67caa4217eSIngo Weinhold
68caa4217eSIngo Weinholdstatic int
69caa4217eSIngo Weinholdbuild_fstat(int fd, struct stat* st)
70caa4217eSIngo Weinhold{
71caa4217eSIngo Weinhold	status_t error = _kern_read_stat(fd, NULL, false, st, sizeof(struct stat));
72caa4217eSIngo Weinhold	if (error != B_OK) {
73caa4217eSIngo Weinhold		errno = error;
74caa4217eSIngo Weinhold		return -1;
75caa4217eSIngo Weinhold	}
76caa4217eSIngo Weinhold
77caa4217eSIngo Weinhold	return 0;
78caa4217eSIngo Weinhold}
79caa4217eSIngo Weinhold
80caa4217eSIngo Weinhold
81caa4217eSIngo Weinholdstruct BuildFileDescriptorCloser {
82caa4217eSIngo Weinhold	BuildFileDescriptorCloser(int fd)
83caa4217eSIngo Weinhold		:
84caa4217eSIngo Weinhold		fFD(fd)
85caa4217eSIngo Weinhold	{
86caa4217eSIngo Weinhold	}
87caa4217eSIngo Weinhold
88caa4217eSIngo Weinhold	~BuildFileDescriptorCloser()
89caa4217eSIngo Weinhold	{
90caa4217eSIngo Weinhold		if (fFD >= 0)
91caa4217eSIngo Weinhold			_kern_close(fFD);
92caa4217eSIngo Weinhold	}
93caa4217eSIngo Weinhold
94caa4217eSIngo Weinholdprivate:
95caa4217eSIngo Weinhold	int	fFD;
96caa4217eSIngo Weinhold};
97caa4217eSIngo Weinhold
98caa4217eSIngo Weinhold
99caa4217eSIngo Weinhold#undef openat
100caa4217eSIngo Weinhold#define openat(dirFD, fileName, openMode) \
101caa4217eSIngo Weinhold	build_openat(dirFD, fileName, openMode, 0)
102caa4217eSIngo Weinhold
103caa4217eSIngo Weinhold#undef fstat
104caa4217eSIngo Weinhold#define fstat(fd, st)	build_fstat(fd, st)
105caa4217eSIngo Weinhold
106caa4217eSIngo Weinhold#undef FileDescriptorCloser
107caa4217eSIngo Weinhold#define FileDescriptorCloser	BuildFileDescriptorCloser
108caa4217eSIngo Weinhold
109caa4217eSIngo Weinhold
110caa4217eSIngo Weinhold#endif
111caa4217eSIngo Weinhold
112caa4217eSIngo Weinhold
1135fb1c6ffSOliver Tappenamespace BPackageKit {
1145fb1c6ffSOliver Tappe
1155fb1c6ffSOliver Tappenamespace BHPKG {
1165fb1c6ffSOliver Tappe
1175fb1c6ffSOliver Tappenamespace BPrivate {
1185fb1c6ffSOliver Tappe
1195fb1c6ffSOliver Tappe
1205fb1c6ffSOliver Tappe// minimum length of data we require before trying to zlib compress them
1215fb1c6ffSOliver Tappestatic const size_t kZlibCompressionSizeThreshold = 64;
1225fb1c6ffSOliver Tappe
1235fb1c6ffSOliver Tappe
1245fb1c6ffSOliver Tappe// #pragma mark - Attributes
1255fb1c6ffSOliver Tappe
1265fb1c6ffSOliver Tappe
1275fb1c6ffSOliver Tappestruct PackageWriterImpl::Attribute
1285fb1c6ffSOliver Tappe	: public DoublyLinkedListLinkImpl<Attribute> {
12933bc4425SOliver Tappe	BHPKGAttributeID			id;
1305fb1c6ffSOliver Tappe	AttributeValue				value;
1315fb1c6ffSOliver Tappe	DoublyLinkedList<Attribute>	children;
1325fb1c6ffSOliver Tappe
13333bc4425SOliver Tappe	Attribute(BHPKGAttributeID id_ = B_HPKG_ATTRIBUTE_ID_ENUM_COUNT)
1345fb1c6ffSOliver Tappe		:
13533bc4425SOliver Tappe		id(id_)
1365fb1c6ffSOliver Tappe	{
1375fb1c6ffSOliver Tappe	}
1385fb1c6ffSOliver Tappe
1395fb1c6ffSOliver Tappe	~Attribute()
1405fb1c6ffSOliver Tappe	{
1415fb1c6ffSOliver Tappe		DeleteChildren();
1425fb1c6ffSOliver Tappe	}
1435fb1c6ffSOliver Tappe
1445fb1c6ffSOliver Tappe	void AddChild(Attribute* child)
1455fb1c6ffSOliver Tappe	{
1465fb1c6ffSOliver Tappe		children.Add(child);
1475fb1c6ffSOliver Tappe	}
1485fb1c6ffSOliver Tappe
1495fb1c6ffSOliver Tappe	void DeleteChildren()
1505fb1c6ffSOliver Tappe	{
1515fb1c6ffSOliver Tappe		while (Attribute* child = children.RemoveHead())
1525fb1c6ffSOliver Tappe			delete child;
1535fb1c6ffSOliver Tappe	}
1545fb1c6ffSOliver Tappe};
1555fb1c6ffSOliver Tappe
1565fb1c6ffSOliver Tappe
157f2022173SOliver Tappe// #pragma mark - Entry
1585fb1c6ffSOliver Tappe
1595fb1c6ffSOliver Tappe
1605fb1c6ffSOliver Tappestruct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> {
1615fb1c6ffSOliver Tappe	Entry(char* name, size_t nameLength, bool isImplicit)
1625fb1c6ffSOliver Tappe		:
1635fb1c6ffSOliver Tappe		fName(name),
1645fb1c6ffSOliver Tappe		fNameLength(nameLength),
1655fb1c6ffSOliver Tappe		fIsImplicit(isImplicit)
1665fb1c6ffSOliver Tappe	{
1675fb1c6ffSOliver Tappe	}
1685fb1c6ffSOliver Tappe
1695fb1c6ffSOliver Tappe	~Entry()
1705fb1c6ffSOliver Tappe	{
1715fb1c6ffSOliver Tappe		DeleteChildren();
1725fb1c6ffSOliver Tappe		free(fName);
1735fb1c6ffSOliver Tappe	}
1745fb1c6ffSOliver Tappe
1755fb1c6ffSOliver Tappe	static Entry* Create(const char* name, size_t nameLength, bool isImplicit)
1765fb1c6ffSOliver Tappe	{
1775fb1c6ffSOliver Tappe		char* clonedName = (char*)malloc(nameLength + 1);
1785fb1c6ffSOliver Tappe		if (clonedName == NULL)
1795fb1c6ffSOliver Tappe			throw std::bad_alloc();
1805fb1c6ffSOliver Tappe		memcpy(clonedName, name, nameLength);
1815fb1c6ffSOliver Tappe		clonedName[nameLength] = '\0';
1825fb1c6ffSOliver Tappe
1835fb1c6ffSOliver Tappe		Entry* entry = new(std::nothrow) Entry(clonedName, nameLength,
1845fb1c6ffSOliver Tappe			isImplicit);
1855fb1c6ffSOliver Tappe		if (entry == NULL) {
1865fb1c6ffSOliver Tappe			free(clonedName);
1875fb1c6ffSOliver Tappe			throw std::bad_alloc();
1885fb1c6ffSOliver Tappe		}
1895fb1c6ffSOliver Tappe
1905fb1c6ffSOliver Tappe		return entry;
1915fb1c6ffSOliver Tappe	}
1925fb1c6ffSOliver Tappe
1935fb1c6ffSOliver Tappe	const char* Name() const
1945fb1c6ffSOliver Tappe	{
1955fb1c6ffSOliver Tappe		return fName;
1965fb1c6ffSOliver Tappe	}
1975fb1c6ffSOliver Tappe
1985fb1c6ffSOliver Tappe	bool IsImplicit() const
1995fb1c6ffSOliver Tappe	{
2005fb1c6ffSOliver Tappe		return fIsImplicit;
2015fb1c6ffSOliver Tappe	}
2025fb1c6ffSOliver Tappe
2035fb1c6ffSOliver Tappe	void SetImplicit(bool isImplicit)
2045fb1c6ffSOliver Tappe	{
2055fb1c6ffSOliver Tappe		fIsImplicit = isImplicit;
2065fb1c6ffSOliver Tappe	}
2075fb1c6ffSOliver Tappe
2085fb1c6ffSOliver Tappe	bool HasName(const char* name, size_t nameLength)
2095fb1c6ffSOliver Tappe	{
2105fb1c6ffSOliver Tappe		return nameLength == fNameLength
2115fb1c6ffSOliver Tappe			&& strncmp(name, fName, nameLength) == 0;
2125fb1c6ffSOliver Tappe	}
2135fb1c6ffSOliver Tappe
2145fb1c6ffSOliver Tappe	void AddChild(Entry* child)
2155fb1c6ffSOliver Tappe	{
2165fb1c6ffSOliver Tappe		fChildren.Add(child);
2175fb1c6ffSOliver Tappe	}
2185fb1c6ffSOliver Tappe
2195fb1c6ffSOliver Tappe	void DeleteChildren()
2205fb1c6ffSOliver Tappe	{
2215fb1c6ffSOliver Tappe		while (Entry* child = fChildren.RemoveHead())
2225fb1c6ffSOliver Tappe			delete child;
2235fb1c6ffSOliver Tappe	}
2245fb1c6ffSOliver Tappe
2255fb1c6ffSOliver Tappe	Entry* GetChild(const char* name, size_t nameLength) const
2265fb1c6ffSOliver Tappe	{
2275fb1c6ffSOliver Tappe		EntryList::ConstIterator it = fChildren.GetIterator();
2285fb1c6ffSOliver Tappe		while (Entry* child = it.Next()) {
2295fb1c6ffSOliver Tappe			if (child->HasName(name, nameLength))
2305fb1c6ffSOliver Tappe				return child;
2315fb1c6ffSOliver Tappe		}
2325fb1c6ffSOliver Tappe
2335fb1c6ffSOliver Tappe		return NULL;
2345fb1c6ffSOliver Tappe	}
2355fb1c6ffSOliver Tappe
2365fb1c6ffSOliver Tappe	EntryList::ConstIterator ChildIterator() const
2375fb1c6ffSOliver Tappe	{
2385fb1c6ffSOliver Tappe		return fChildren.GetIterator();
2395fb1c6ffSOliver Tappe	}
2405fb1c6ffSOliver Tappe
2415fb1c6ffSOliver Tappeprivate:
2425fb1c6ffSOliver Tappe	char*		fName;
2435fb1c6ffSOliver Tappe	size_t		fNameLength;
2445fb1c6ffSOliver Tappe	bool		fIsImplicit;
2455fb1c6ffSOliver Tappe	EntryList	fChildren;
2465fb1c6ffSOliver Tappe};
2475fb1c6ffSOliver Tappe
2485fb1c6ffSOliver Tappe
249f2022173SOliver Tappe// #pragma mark - SubPathAdder
2505fb1c6ffSOliver Tappe
2515fb1c6ffSOliver Tappe
2527fd711efSOliver Tappestruct PackageWriterImpl::SubPathAdder {
2537fd711efSOliver Tappe	SubPathAdder(char* pathBuffer, const char* subPath)
2547fd711efSOliver Tappe		: fOriginalPathEnd(pathBuffer + strlen(pathBuffer))
2557fd711efSOliver Tappe	{
2567fd711efSOliver Tappe		strcat(pathBuffer, "/");
2577fd711efSOliver Tappe		strcat(pathBuffer, subPath);
2587fd711efSOliver Tappe	}
2597fd711efSOliver Tappe
2607fd711efSOliver Tappe	~SubPathAdder()
2617fd711efSOliver Tappe	{
2627fd711efSOliver Tappe		*fOriginalPathEnd = '\0';
2637fd711efSOliver Tappe	}
2647fd711efSOliver Tappeprivate:
2657fd711efSOliver Tappe	char* fOriginalPathEnd;
2667fd711efSOliver Tappe};
2677fd711efSOliver Tappe
2687fd711efSOliver Tappe
2695fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl (Inline Methods)
2705fb1c6ffSOliver Tappe
2715fb1c6ffSOliver Tappe
2725fb1c6ffSOliver Tappetemplate<typename Type>
2735fb1c6ffSOliver Tappeinline PackageWriterImpl::Attribute*
27433bc4425SOliver TappePackageWriterImpl::_AddAttribute(BHPKGAttributeID attributeID, Type value)
2755fb1c6ffSOliver Tappe{
2765fb1c6ffSOliver Tappe	AttributeValue attributeValue;
2775fb1c6ffSOliver Tappe	attributeValue.SetTo(value);
27833bc4425SOliver Tappe	return _AddAttribute(attributeID, attributeValue);
2795fb1c6ffSOliver Tappe}
2805fb1c6ffSOliver Tappe
2815fb1c6ffSOliver Tappe
2825fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl
2835fb1c6ffSOliver Tappe
2845fb1c6ffSOliver Tappe
2857fd711efSOliver TappePackageWriterImpl::PackageWriterImpl(BPackageWriterListener* listener)
2865fb1c6ffSOliver Tappe	:
28791ebce66SOliver Tappe	inherited(listener),
2887fd711efSOliver Tappe	fListener(listener),
2894ee7d007SOliver Tappe	fDataBuffer(NULL),
2904ee7d007SOliver Tappe	fDataBufferSize(2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB),
2915fb1c6ffSOliver Tappe	fRootEntry(NULL),
2925fb1c6ffSOliver Tappe	fRootAttribute(NULL),
29333bc4425SOliver Tappe	fTopAttribute(NULL)
2945fb1c6ffSOliver Tappe{
2955fb1c6ffSOliver Tappe}
2965fb1c6ffSOliver Tappe
2975fb1c6ffSOliver Tappe
2985fb1c6ffSOliver TappePackageWriterImpl::~PackageWriterImpl()
2995fb1c6ffSOliver Tappe{
3005fb1c6ffSOliver Tappe	delete fRootAttribute;
3015fb1c6ffSOliver Tappe
3025fb1c6ffSOliver Tappe	delete fRootEntry;
3035fb1c6ffSOliver Tappe
3045fb1c6ffSOliver Tappe	free(fDataBuffer);
3055fb1c6ffSOliver Tappe}
3065fb1c6ffSOliver Tappe
3075fb1c6ffSOliver Tappe
3085fb1c6ffSOliver Tappestatus_t
3095fb1c6ffSOliver TappePackageWriterImpl::Init(const char* fileName)
3105fb1c6ffSOliver Tappe{
3115fb1c6ffSOliver Tappe	try {
3125fb1c6ffSOliver Tappe		return _Init(fileName);
3135fb1c6ffSOliver Tappe	} catch (status_t error) {
3145fb1c6ffSOliver Tappe		return error;
3155fb1c6ffSOliver Tappe	} catch (std::bad_alloc) {
3167fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
3175fb1c6ffSOliver Tappe		return B_NO_MEMORY;
3185fb1c6ffSOliver Tappe	}
3195fb1c6ffSOliver Tappe}
3205fb1c6ffSOliver Tappe
3215fb1c6ffSOliver Tappe
3225fb1c6ffSOliver Tappestatus_t
3235fb1c6ffSOliver TappePackageWriterImpl::AddEntry(const char* fileName)
3245fb1c6ffSOliver Tappe{
3255fb1c6ffSOliver Tappe	try {
3267fd711efSOliver Tappe		// if it's ".PackageInfo", parse it
3277fd711efSOliver Tappe		if (strcmp(fileName, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
3287fd711efSOliver Tappe			struct ErrorListener : public BPackageInfo::ParseErrorListener {
3297fd711efSOliver Tappe				ErrorListener(BPackageWriterListener* _listener)
3307fd711efSOliver Tappe					: listener(_listener) {}
3317fd711efSOliver Tappe				virtual void OnError(const BString& msg, int line, int col) {
3327fd711efSOliver Tappe					listener->PrintError("Parse error in %s(%d:%d) -> %s\n",
3337fd711efSOliver Tappe						B_HPKG_PACKAGE_INFO_FILE_NAME, line, col, msg.String());
3347fd711efSOliver Tappe				}
3357fd711efSOliver Tappe				BPackageWriterListener* listener;
3367fd711efSOliver Tappe			} errorListener(fListener);
3377fd711efSOliver Tappe			BEntry packageInfoEntry(fileName);
338d77c6cd2SOliver Tappe			status_t result = fPackageInfo.ReadFromConfigFile(packageInfoEntry,
3397fd711efSOliver Tappe				&errorListener);
340d77c6cd2SOliver Tappe			if (result != B_OK || (result = fPackageInfo.InitCheck()) != B_OK)
3417fd711efSOliver Tappe				return result;
342d77c6cd2SOliver Tappe			RegisterPackageInfo(PackageAttributes(), fPackageInfo);
3437fd711efSOliver Tappe		}
3447fd711efSOliver Tappe
3455fb1c6ffSOliver Tappe		return _RegisterEntry(fileName);
3465fb1c6ffSOliver Tappe	} catch (status_t error) {
3475fb1c6ffSOliver Tappe		return error;
3485fb1c6ffSOliver Tappe	} catch (std::bad_alloc) {
3497fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
3505fb1c6ffSOliver Tappe		return B_NO_MEMORY;
3515fb1c6ffSOliver Tappe	}
3525fb1c6ffSOliver Tappe}
3535fb1c6ffSOliver Tappe
3545fb1c6ffSOliver Tappe
3555fb1c6ffSOliver Tappestatus_t
3565fb1c6ffSOliver TappePackageWriterImpl::Finish()
3575fb1c6ffSOliver Tappe{
3585fb1c6ffSOliver Tappe	try {
359d77c6cd2SOliver Tappe		if (fPackageInfo.InitCheck() != B_OK) {
3607fd711efSOliver Tappe			fListener->PrintError("No package-info file found (%s)!\n",
3617fd711efSOliver Tappe				B_HPKG_PACKAGE_INFO_FILE_NAME);
3627fd711efSOliver Tappe			return B_BAD_DATA;
3637fd711efSOliver Tappe		}
364d77c6cd2SOliver Tappe
365d77c6cd2SOliver Tappe		status_t result = _CheckLicenses();
366d77c6cd2SOliver Tappe		if (result != B_OK)
367d77c6cd2SOliver Tappe			return result;
368d77c6cd2SOliver Tappe
3695fb1c6ffSOliver Tappe		return _Finish();
3705fb1c6ffSOliver Tappe	} catch (status_t error) {
3715fb1c6ffSOliver Tappe		return error;
3725fb1c6ffSOliver Tappe	} catch (std::bad_alloc) {
3737fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
3745fb1c6ffSOliver Tappe		return B_NO_MEMORY;
3755fb1c6ffSOliver Tappe	}
3765fb1c6ffSOliver Tappe}
3775fb1c6ffSOliver Tappe
3785fb1c6ffSOliver Tappe
3795fb1c6ffSOliver Tappestatus_t
3805fb1c6ffSOliver TappePackageWriterImpl::_Init(const char* fileName)
3815fb1c6ffSOliver Tappe{
38291ebce66SOliver Tappe	status_t result = inherited::Init(fileName, "package");
383f2022173SOliver Tappe	if (result != B_OK)
384f2022173SOliver Tappe		return result;
385f2022173SOliver Tappe
3864ee7d007SOliver Tappe	// allocate data buffer
3874ee7d007SOliver Tappe	fDataBuffer = malloc(fDataBufferSize);
3884ee7d007SOliver Tappe	if (fDataBuffer == NULL)
3894ee7d007SOliver Tappe		throw std::bad_alloc();
3904ee7d007SOliver Tappe
391f2022173SOliver Tappe	if (fStringCache.Init() != B_OK)
3925fb1c6ffSOliver Tappe		throw std::bad_alloc();
3935fb1c6ffSOliver Tappe
3945fb1c6ffSOliver Tappe	// create entry list
3955fb1c6ffSOliver Tappe	fRootEntry = new Entry(NULL, 0, true);
3965fb1c6ffSOliver Tappe
39733bc4425SOliver Tappe	fRootAttribute = new Attribute();
3985fb1c6ffSOliver Tappe
3995fb1c6ffSOliver Tappe	fHeapOffset = fHeapEnd = sizeof(hpkg_header);
4005fb1c6ffSOliver Tappe	fTopAttribute = fRootAttribute;
4015fb1c6ffSOliver Tappe
4025fb1c6ffSOliver Tappe	return B_OK;
4035fb1c6ffSOliver Tappe}
4045fb1c6ffSOliver Tappe
4055fb1c6ffSOliver Tappe
406d77c6cd2SOliver Tappestatus_t
407d77c6cd2SOliver TappePackageWriterImpl::_CheckLicenses()
408d77c6cd2SOliver Tappe{
409d77c6cd2SOliver Tappe	BPath systemLicensePath;
410d77c6cd2SOliver Tappe	status_t result
4117162cff6SIngo Weinhold#ifdef HAIKU_TARGET_PLATFORM_HAIKU
412d77c6cd2SOliver Tappe		= find_directory(B_SYSTEM_DATA_DIRECTORY, &systemLicensePath);
4137162cff6SIngo Weinhold#else
4147162cff6SIngo Weinhold		= systemLicensePath.SetTo(HAIKU_BUILD_SYSTEM_DATA_DIRECTORY);
4157162cff6SIngo Weinhold#endif
416d77c6cd2SOliver Tappe	if (result != B_OK) {
417d77c6cd2SOliver Tappe		fListener->PrintError("unable to find system data path!\n");
418d77c6cd2SOliver Tappe		return result;
419d77c6cd2SOliver Tappe	}
420d77c6cd2SOliver Tappe	if ((result = systemLicensePath.Append("licenses")) != B_OK) {
421d77c6cd2SOliver Tappe		fListener->PrintError("unable to append to system data path!\n");
422d77c6cd2SOliver Tappe		return result;
423d77c6cd2SOliver Tappe	}
424d77c6cd2SOliver Tappe
425d77c6cd2SOliver Tappe	BDirectory systemLicenseDir(systemLicensePath.Path());
426d77c6cd2SOliver Tappe	BDirectory packageLicenseDir("./data/licenses");
427d77c6cd2SOliver Tappe
428d77c6cd2SOliver Tappe	const BObjectList<BString>& licenseList = fPackageInfo.LicenseList();
429d77c6cd2SOliver Tappe	for (int i = 0; i < licenseList.CountItems(); ++i) {
430d77c6cd2SOliver Tappe		const BString& licenseName = *licenseList.ItemAt(i);
4317ea4dbceSIngo Weinhold		if (licenseName == kPublicDomainLicenseName)
4327ea4dbceSIngo Weinhold			continue;
4337ea4dbceSIngo Weinhold
434d77c6cd2SOliver Tappe		BEntry license;
435d77c6cd2SOliver Tappe		if (systemLicenseDir.FindEntry(licenseName.String(), &license) == B_OK)
436d77c6cd2SOliver Tappe			continue;
437d77c6cd2SOliver Tappe
438d77c6cd2SOliver Tappe		// license is not a system license, so it must be contained in package
439d77c6cd2SOliver Tappe		if (packageLicenseDir.FindEntry(licenseName.String(),
440d77c6cd2SOliver Tappe				&license) != B_OK) {
441d77c6cd2SOliver Tappe			fListener->PrintError("License '%s' isn't contained in package!\n",
442d77c6cd2SOliver Tappe				licenseName.String());
443d77c6cd2SOliver Tappe			return B_BAD_DATA;
444d77c6cd2SOliver Tappe		}
445d77c6cd2SOliver Tappe	}
446d77c6cd2SOliver Tappe
447d77c6cd2SOliver Tappe	return B_OK;
448d77c6cd2SOliver Tappe}
449d77c6cd2SOliver Tappe
450d77c6cd2SOliver Tappe
4515fb1c6ffSOliver Tappestatus_t
4525fb1c6ffSOliver TappePackageWriterImpl::_Finish()
4535fb1c6ffSOliver Tappe{
4545fb1c6ffSOliver Tappe	// write entries
4555fb1c6ffSOliver Tappe	for (EntryList::ConstIterator it = fRootEntry->ChildIterator();
4565fb1c6ffSOliver Tappe			Entry* entry = it.Next();) {
4577fd711efSOliver Tappe		char pathBuffer[B_PATH_NAME_LENGTH];
4587fd711efSOliver Tappe		pathBuffer[0] = '\0';
4597fd711efSOliver Tappe		_AddEntry(AT_FDCWD, entry, entry->Name(), pathBuffer);
4605fb1c6ffSOliver Tappe	}
4615fb1c6ffSOliver Tappe
4627fd711efSOliver Tappe	off_t heapSize = fHeapEnd - sizeof(hpkg_header);
4635fb1c6ffSOliver Tappe
4645fb1c6ffSOliver Tappe	hpkg_header header;
4655fb1c6ffSOliver Tappe
4665fb1c6ffSOliver Tappe	// write the TOC and package attributes
4675fb1c6ffSOliver Tappe	_WriteTOC(header);
4685fb1c6ffSOliver Tappe	_WritePackageAttributes(header);
4695fb1c6ffSOliver Tappe
4705fb1c6ffSOliver Tappe	off_t totalSize = fHeapEnd;
4717fd711efSOliver Tappe
4727fd711efSOliver Tappe	fListener->OnPackageSizeInfo(sizeof(hpkg_header), heapSize,
4737fd711efSOliver Tappe		B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed),
4747fd711efSOliver Tappe		B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed),
4757fd711efSOliver Tappe		totalSize);
4765fb1c6ffSOliver Tappe
4775fb1c6ffSOliver Tappe	// prepare the header
4785fb1c6ffSOliver Tappe
4795fb1c6ffSOliver Tappe	// general
4805fb1c6ffSOliver Tappe	header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC);
4815fb1c6ffSOliver Tappe	header.header_size = B_HOST_TO_BENDIAN_INT16(
4825fb1c6ffSOliver Tappe		(uint16)sizeof(hpkg_header));
4835fb1c6ffSOliver Tappe	header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION);
4845fb1c6ffSOliver Tappe	header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize);
4855fb1c6ffSOliver Tappe
4865fb1c6ffSOliver Tappe	// write the header
487f2022173SOliver Tappe	WriteBuffer(&header, sizeof(hpkg_header), 0);
4885fb1c6ffSOliver Tappe
4894ee7d007SOliver Tappe	SetFinished(true);
4905fb1c6ffSOliver Tappe	return B_OK;
4915fb1c6ffSOliver Tappe}
4925fb1c6ffSOliver Tappe
4935fb1c6ffSOliver Tappe
4945fb1c6ffSOliver Tappestatus_t
4955fb1c6ffSOliver TappePackageWriterImpl::_RegisterEntry(const char* fileName)
4965fb1c6ffSOliver Tappe{
4975fb1c6ffSOliver Tappe	if (*fileName == '\0') {
4987fd711efSOliver Tappe		fListener->PrintError("Invalid empty file name\n");
4995fb1c6ffSOliver Tappe		return B_BAD_VALUE;
5005fb1c6ffSOliver Tappe	}
5015fb1c6ffSOliver Tappe
5025fb1c6ffSOliver Tappe	// add all components of the path
5035fb1c6ffSOliver Tappe	Entry* entry = fRootEntry;
5045fb1c6ffSOliver Tappe	while (*fileName != 0) {
5055fb1c6ffSOliver Tappe		const char* nextSlash = strchr(fileName, '/');
5065fb1c6ffSOliver Tappe		// no slash, just add the file name
5075fb1c6ffSOliver Tappe		if (nextSlash == NULL) {
5085fb1c6ffSOliver Tappe			entry = _RegisterEntry(entry, fileName, strlen(fileName), false);
5095fb1c6ffSOliver Tappe			break;
5105fb1c6ffSOliver Tappe		}
5115fb1c6ffSOliver Tappe
5125fb1c6ffSOliver Tappe		// find the start of the next component, skipping slashes
5135fb1c6ffSOliver Tappe		const char* nextComponent = nextSlash + 1;
5145fb1c6ffSOliver Tappe		while (*nextComponent == '/')
5155fb1c6ffSOliver Tappe			nextComponent++;
5165fb1c6ffSOliver Tappe
5175fb1c6ffSOliver Tappe		if (nextSlash == fileName) {
5185fb1c6ffSOliver Tappe			// the FS root
5195fb1c6ffSOliver Tappe			entry = _RegisterEntry(entry, fileName, 1,
5205fb1c6ffSOliver Tappe				*nextComponent != '\0');
5215fb1c6ffSOliver Tappe		} else {
5225fb1c6ffSOliver Tappe			entry = _RegisterEntry(entry, fileName, nextSlash - fileName,
5235fb1c6ffSOliver Tappe				*nextComponent != '\0');
5245fb1c6ffSOliver Tappe		}
5255fb1c6ffSOliver Tappe
5265fb1c6ffSOliver Tappe		fileName = nextComponent;
5275fb1c6ffSOliver Tappe	}
5285fb1c6ffSOliver Tappe
5295fb1c6ffSOliver Tappe	return B_OK;
5305fb1c6ffSOliver Tappe}
5315fb1c6ffSOliver Tappe
5325fb1c6ffSOliver Tappe
5335fb1c6ffSOliver TappePackageWriterImpl::Entry*
5345fb1c6ffSOliver TappePackageWriterImpl::_RegisterEntry(Entry* parent, const char* name,
5355fb1c6ffSOliver Tappe	size_t nameLength, bool isImplicit)
5365fb1c6ffSOliver Tappe{
5375fb1c6ffSOliver Tappe	// check the component name -- don't allow "." or ".."
5385fb1c6ffSOliver Tappe	if (name[0] == '.'
5395fb1c6ffSOliver Tappe		&& (nameLength == 1 || (nameLength == 2 && name[1] == '.'))) {
5407fd711efSOliver Tappe		fListener->PrintError("Invalid file name: \".\" and \"..\" "
5415fb1c6ffSOliver Tappe			"are not allowed as path components\n");
5425fb1c6ffSOliver Tappe		throw status_t(B_BAD_VALUE);
5435fb1c6ffSOliver Tappe	}
5445fb1c6ffSOliver Tappe
5455fb1c6ffSOliver Tappe	// the entry might already exist
5465fb1c6ffSOliver Tappe	Entry* entry = parent->GetChild(name, nameLength);
5475fb1c6ffSOliver Tappe	if (entry != NULL) {
5485fb1c6ffSOliver Tappe		// If the entry was implicit and is no longer, we mark it non-implicit
5495fb1c6ffSOliver Tappe		// and delete all of it's children.
5505fb1c6ffSOliver Tappe		if (entry->IsImplicit() && !isImplicit) {
5515fb1c6ffSOliver Tappe			entry->DeleteChildren();
5525fb1c6ffSOliver Tappe			entry->SetImplicit(false);
5535fb1c6ffSOliver Tappe		}
5545fb1c6ffSOliver Tappe	} else {
5555fb1c6ffSOliver Tappe		// nope -- create it
5565fb1c6ffSOliver Tappe		entry = Entry::Create(name, nameLength, isImplicit);
5575fb1c6ffSOliver Tappe		parent->AddChild(entry);
5585fb1c6ffSOliver Tappe	}
5595fb1c6ffSOliver Tappe
5605fb1c6ffSOliver Tappe	return entry;
5615fb1c6ffSOliver Tappe}
5625fb1c6ffSOliver Tappe
5635fb1c6ffSOliver Tappe
5645fb1c6ffSOliver Tappevoid
5655fb1c6ffSOliver TappePackageWriterImpl::_WriteTOC(hpkg_header& header)
5665fb1c6ffSOliver Tappe{
5675fb1c6ffSOliver Tappe	// prepare the writer (zlib writer on top of a file writer)
5685fb1c6ffSOliver Tappe	off_t startOffset = fHeapEnd;
5694ee7d007SOliver Tappe	FDDataWriter realWriter(FD(), startOffset, fListener);
5705fb1c6ffSOliver Tappe	ZlibDataWriter zlibWriter(&realWriter);
5714ee7d007SOliver Tappe	SetDataWriter(&zlibWriter);
5725fb1c6ffSOliver Tappe	zlibWriter.Init();
5735fb1c6ffSOliver Tappe
5745fb1c6ffSOliver Tappe	// write the sections
5755fb1c6ffSOliver Tappe	uint64 uncompressedStringsSize;
5765fb1c6ffSOliver Tappe	uint64 uncompressedMainSize;
57733bc4425SOliver Tappe	int32 cachedStringsWritten
57833bc4425SOliver Tappe		= _WriteTOCSections(uncompressedStringsSize, uncompressedMainSize);
5795fb1c6ffSOliver Tappe
5805fb1c6ffSOliver Tappe	// finish the writer
5815fb1c6ffSOliver Tappe	zlibWriter.Finish();
5825fb1c6ffSOliver Tappe	fHeapEnd = realWriter.Offset();
5834ee7d007SOliver Tappe	SetDataWriter(NULL);
5845fb1c6ffSOliver Tappe
5855fb1c6ffSOliver Tappe	off_t endOffset = fHeapEnd;
5867fd711efSOliver Tappe
58733bc4425SOliver Tappe	fListener->OnTOCSizeInfo(uncompressedStringsSize, uncompressedMainSize,
5887fd711efSOliver Tappe		zlibWriter.BytesWritten());
5895fb1c6ffSOliver Tappe
5905fb1c6ffSOliver Tappe	// update the header
5915fb1c6ffSOliver Tappe
5925fb1c6ffSOliver Tappe	// TOC
5935fb1c6ffSOliver Tappe	header.toc_compression = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB);
5945fb1c6ffSOliver Tappe	header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64(
5955fb1c6ffSOliver Tappe		endOffset - startOffset);
5965fb1c6ffSOliver Tappe	header.toc_length_uncompressed = B_HOST_TO_BENDIAN_INT64(
5975fb1c6ffSOliver Tappe		zlibWriter.BytesWritten());
5985fb1c6ffSOliver Tappe
5995fb1c6ffSOliver Tappe	// TOC subsections
6005fb1c6ffSOliver Tappe	header.toc_strings_length = B_HOST_TO_BENDIAN_INT64(
6015fb1c6ffSOliver Tappe		uncompressedStringsSize);
6025fb1c6ffSOliver Tappe	header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten);
6035fb1c6ffSOliver Tappe}
6045fb1c6ffSOliver Tappe
6055fb1c6ffSOliver Tappe
6065fb1c6ffSOliver Tappeint32
60733bc4425SOliver TappePackageWriterImpl::_WriteTOCSections(uint64& _stringsSize, uint64& _mainSize)
6085fb1c6ffSOliver Tappe{
6095fb1c6ffSOliver Tappe	// write the cached strings
6104ee7d007SOliver Tappe	uint64 cachedStringsOffset = DataWriter()->BytesWritten();
611f2022173SOliver Tappe	int32 cachedStringsWritten = WriteCachedStrings(fStringCache, 2);
6125fb1c6ffSOliver Tappe
6135fb1c6ffSOliver Tappe	// write the main TOC section
6144ee7d007SOliver Tappe	uint64 mainOffset = DataWriter()->BytesWritten();
6155fb1c6ffSOliver Tappe	_WriteAttributeChildren(fRootAttribute);
6165fb1c6ffSOliver Tappe
6175fb1c6ffSOliver Tappe	_stringsSize = mainOffset - cachedStringsOffset;
6184ee7d007SOliver Tappe	_mainSize = DataWriter()->BytesWritten() - mainOffset;
6195fb1c6ffSOliver Tappe
6205fb1c6ffSOliver Tappe	return cachedStringsWritten;
6215fb1c6ffSOliver Tappe}
6225fb1c6ffSOliver Tappe
6235fb1c6ffSOliver Tappe
6245fb1c6ffSOliver Tappevoid
6255fb1c6ffSOliver TappePackageWriterImpl::_WriteAttributeChildren(Attribute* attribute)
6265fb1c6ffSOliver Tappe{
6275fb1c6ffSOliver Tappe	DoublyLinkedList<Attribute>::Iterator it
6285fb1c6ffSOliver Tappe		= attribute->children.GetIterator();
6295fb1c6ffSOliver Tappe	while (Attribute* child = it.Next()) {
6305fb1c6ffSOliver Tappe		// write tag
631f2022173SOliver Tappe		uint8 encoding = child->value.ApplicableEncoding();
63233bc4425SOliver Tappe		WriteUnsignedLEB128(HPKG_ATTRIBUTE_TAG_COMPOSE(child->id,
63333bc4425SOliver Tappe			child->value.type, encoding, !child->children.IsEmpty()));
6345fb1c6ffSOliver Tappe
6355fb1c6ffSOliver Tappe		// write value
636f2022173SOliver Tappe		WriteAttributeValue(child->value, encoding);
6375fb1c6ffSOliver Tappe
6385fb1c6ffSOliver Tappe		if (!child->children.IsEmpty())
6395fb1c6ffSOliver Tappe			_WriteAttributeChildren(child);
6405fb1c6ffSOliver Tappe	}
6415fb1c6ffSOliver Tappe
642f2022173SOliver Tappe	WriteUnsignedLEB128(0);
6435fb1c6ffSOliver Tappe}
6445fb1c6ffSOliver Tappe
6455fb1c6ffSOliver Tappe
6465fb1c6ffSOliver Tappevoid
6475fb1c6ffSOliver TappePackageWriterImpl::_WritePackageAttributes(hpkg_header& header)
6485fb1c6ffSOliver Tappe{
649fd9c0b33SOliver Tappe	// write the package attributes (zlib writer on top of a file writer)
6505fb1c6ffSOliver Tappe	off_t startOffset = fHeapEnd;
6514ee7d007SOliver Tappe	FDDataWriter realWriter(FD(), startOffset, fListener);
652fd9c0b33SOliver Tappe	ZlibDataWriter zlibWriter(&realWriter);
6534ee7d007SOliver Tappe	SetDataWriter(&zlibWriter);
654fd9c0b33SOliver Tappe	zlibWriter.Init();
6555fb1c6ffSOliver Tappe
6564ee7d007SOliver Tappe	// write cached strings and package attributes tree
6574ee7d007SOliver Tappe	uint32 stringsLengthUncompressed;
6584ee7d007SOliver Tappe	uint32 stringsCount = WritePackageAttributes(PackageAttributes(),
6594ee7d007SOliver Tappe		stringsLengthUncompressed);
660fd9c0b33SOliver Tappe
661fd9c0b33SOliver Tappe	zlibWriter.Finish();
6625fb1c6ffSOliver Tappe	fHeapEnd = realWriter.Offset();
6634ee7d007SOliver Tappe	SetDataWriter(NULL);
6645fb1c6ffS