PackageWriterImpl.cpp revision 8524dd36
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
4485e13d1eSIngo Weinhold#include <typeinfo>
45caa4217eSIngo Weinhold
465fb1c6ffSOliver Tappenamespace BPackageKit {
475fb1c6ffSOliver Tappe
485fb1c6ffSOliver Tappenamespace BHPKG {
495fb1c6ffSOliver Tappe
505fb1c6ffSOliver Tappenamespace BPrivate {
515fb1c6ffSOliver Tappe
525fb1c6ffSOliver Tappe
535fb1c6ffSOliver Tappe// minimum length of data we require before trying to zlib compress them
545fb1c6ffSOliver Tappestatic const size_t kZlibCompressionSizeThreshold = 64;
555fb1c6ffSOliver Tappe
565fb1c6ffSOliver Tappe
575fb1c6ffSOliver Tappe// #pragma mark - Attributes
585fb1c6ffSOliver Tappe
595fb1c6ffSOliver Tappe
605fb1c6ffSOliver Tappestruct PackageWriterImpl::Attribute
615fb1c6ffSOliver Tappe	: public DoublyLinkedListLinkImpl<Attribute> {
6233bc4425SOliver Tappe	BHPKGAttributeID			id;
635fb1c6ffSOliver Tappe	AttributeValue				value;
645fb1c6ffSOliver Tappe	DoublyLinkedList<Attribute>	children;
655fb1c6ffSOliver Tappe
6633bc4425SOliver Tappe	Attribute(BHPKGAttributeID id_ = B_HPKG_ATTRIBUTE_ID_ENUM_COUNT)
675fb1c6ffSOliver Tappe		:
6833bc4425SOliver Tappe		id(id_)
695fb1c6ffSOliver Tappe	{
705fb1c6ffSOliver Tappe	}
715fb1c6ffSOliver Tappe
725fb1c6ffSOliver Tappe	~Attribute()
735fb1c6ffSOliver Tappe	{
745fb1c6ffSOliver Tappe		DeleteChildren();
755fb1c6ffSOliver Tappe	}
765fb1c6ffSOliver Tappe
775fb1c6ffSOliver Tappe	void AddChild(Attribute* child)
785fb1c6ffSOliver Tappe	{
795fb1c6ffSOliver Tappe		children.Add(child);
805fb1c6ffSOliver Tappe	}
815fb1c6ffSOliver Tappe
825fb1c6ffSOliver Tappe	void DeleteChildren()
835fb1c6ffSOliver Tappe	{
845fb1c6ffSOliver Tappe		while (Attribute* child = children.RemoveHead())
855fb1c6ffSOliver Tappe			delete child;
865fb1c6ffSOliver Tappe	}
875fb1c6ffSOliver Tappe};
885fb1c6ffSOliver Tappe
895fb1c6ffSOliver Tappe
90f2022173SOliver Tappe// #pragma mark - Entry
915fb1c6ffSOliver Tappe
925fb1c6ffSOliver Tappe
935fb1c6ffSOliver Tappestruct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl<Entry> {
940f9a98a4SIngo Weinhold	Entry(char* name, size_t nameLength, int fd, bool isImplicit)
955fb1c6ffSOliver Tappe		:
965fb1c6ffSOliver Tappe		fName(name),
975fb1c6ffSOliver Tappe		fNameLength(nameLength),
980f9a98a4SIngo Weinhold		fFD(fd),
995fb1c6ffSOliver Tappe		fIsImplicit(isImplicit)
1005fb1c6ffSOliver Tappe	{
1015fb1c6ffSOliver Tappe	}
1025fb1c6ffSOliver Tappe
1035fb1c6ffSOliver Tappe	~Entry()
1045fb1c6ffSOliver Tappe	{
1055fb1c6ffSOliver Tappe		DeleteChildren();
1065fb1c6ffSOliver Tappe		free(fName);
1075fb1c6ffSOliver Tappe	}
1085fb1c6ffSOliver Tappe
1090f9a98a4SIngo Weinhold	static Entry* Create(const char* name, size_t nameLength, int fd,
1100f9a98a4SIngo Weinhold		bool isImplicit)
1115fb1c6ffSOliver Tappe	{
1125fb1c6ffSOliver Tappe		char* clonedName = (char*)malloc(nameLength + 1);
1135fb1c6ffSOliver Tappe		if (clonedName == NULL)
1145fb1c6ffSOliver Tappe			throw std::bad_alloc();
1155fb1c6ffSOliver Tappe		memcpy(clonedName, name, nameLength);
1165fb1c6ffSOliver Tappe		clonedName[nameLength] = '\0';
1175fb1c6ffSOliver Tappe
1180f9a98a4SIngo Weinhold		Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, fd,
1195fb1c6ffSOliver Tappe			isImplicit);
1205fb1c6ffSOliver Tappe		if (entry == NULL) {
1215fb1c6ffSOliver Tappe			free(clonedName);
1225fb1c6ffSOliver Tappe			throw std::bad_alloc();
1235fb1c6ffSOliver Tappe		}
1245fb1c6ffSOliver Tappe
1255fb1c6ffSOliver Tappe		return entry;
1265fb1c6ffSOliver Tappe	}
1275fb1c6ffSOliver Tappe
1285fb1c6ffSOliver Tappe	const char* Name() const
1295fb1c6ffSOliver Tappe	{
1305fb1c6ffSOliver Tappe		return fName;
1315fb1c6ffSOliver Tappe	}
1325fb1c6ffSOliver Tappe
1330f9a98a4SIngo Weinhold	int FD() const
1340f9a98a4SIngo Weinhold	{
1350f9a98a4SIngo Weinhold		return fFD;
1360f9a98a4SIngo Weinhold	}
1370f9a98a4SIngo Weinhold
1380f9a98a4SIngo Weinhold	void SetFD(int fd)
1390f9a98a4SIngo Weinhold	{
1400f9a98a4SIngo Weinhold		fFD = fd;
1410f9a98a4SIngo Weinhold	}
1420f9a98a4SIngo Weinhold
1435fb1c6ffSOliver Tappe	bool IsImplicit() const
1445fb1c6ffSOliver Tappe	{
1455fb1c6ffSOliver Tappe		return fIsImplicit;
1465fb1c6ffSOliver Tappe	}
1475fb1c6ffSOliver Tappe
1485fb1c6ffSOliver Tappe	void SetImplicit(bool isImplicit)
1495fb1c6ffSOliver Tappe	{
1505fb1c6ffSOliver Tappe		fIsImplicit = isImplicit;
1515fb1c6ffSOliver Tappe	}
1525fb1c6ffSOliver Tappe
1535fb1c6ffSOliver Tappe	bool HasName(const char* name, size_t nameLength)
1545fb1c6ffSOliver Tappe	{
1555fb1c6ffSOliver Tappe		return nameLength == fNameLength
1565fb1c6ffSOliver Tappe			&& strncmp(name, fName, nameLength) == 0;
1575fb1c6ffSOliver Tappe	}
1585fb1c6ffSOliver Tappe
1595fb1c6ffSOliver Tappe	void AddChild(Entry* child)
1605fb1c6ffSOliver Tappe	{
1615fb1c6ffSOliver Tappe		fChildren.Add(child);
1625fb1c6ffSOliver Tappe	}
1635fb1c6ffSOliver Tappe
1645fb1c6ffSOliver Tappe	void DeleteChildren()
1655fb1c6ffSOliver Tappe	{
1665fb1c6ffSOliver Tappe		while (Entry* child = fChildren.RemoveHead())
1675fb1c6ffSOliver Tappe			delete child;
1685fb1c6ffSOliver Tappe	}
1695fb1c6ffSOliver Tappe
1705fb1c6ffSOliver Tappe	Entry* GetChild(const char* name, size_t nameLength) const
1715fb1c6ffSOliver Tappe	{
1725fb1c6ffSOliver Tappe		EntryList::ConstIterator it = fChildren.GetIterator();
1735fb1c6ffSOliver Tappe		while (Entry* child = it.Next()) {
1745fb1c6ffSOliver Tappe			if (child->HasName(name, nameLength))
1755fb1c6ffSOliver Tappe				return child;
1765fb1c6ffSOliver Tappe		}
1775fb1c6ffSOliver Tappe
1785fb1c6ffSOliver Tappe		return NULL;
1795fb1c6ffSOliver Tappe	}
1805fb1c6ffSOliver Tappe
1815fb1c6ffSOliver Tappe	EntryList::ConstIterator ChildIterator() const
1825fb1c6ffSOliver Tappe	{
1835fb1c6ffSOliver Tappe		return fChildren.GetIterator();
1845fb1c6ffSOliver Tappe	}
1855fb1c6ffSOliver Tappe
1865fb1c6ffSOliver Tappeprivate:
1875fb1c6ffSOliver Tappe	char*		fName;
1885fb1c6ffSOliver Tappe	size_t		fNameLength;
1890f9a98a4SIngo Weinhold	int			fFD;
1905fb1c6ffSOliver Tappe	bool		fIsImplicit;
1915fb1c6ffSOliver Tappe	EntryList	fChildren;
1925fb1c6ffSOliver Tappe};
1935fb1c6ffSOliver Tappe
1945fb1c6ffSOliver Tappe
195f2022173SOliver Tappe// #pragma mark - SubPathAdder
1965fb1c6ffSOliver Tappe
1975fb1c6ffSOliver Tappe
1987fd711efSOliver Tappestruct PackageWriterImpl::SubPathAdder {
1998524dd36SIngo Weinhold	SubPathAdder(BErrorOutput* errorOutput, char* pathBuffer,
2008524dd36SIngo Weinhold		const char* subPath)
2018524dd36SIngo Weinhold		:
2028524dd36SIngo Weinhold		fOriginalPathEnd(pathBuffer + strlen(pathBuffer))
2037fd711efSOliver Tappe	{
2048524dd36SIngo Weinhold		if (fOriginalPathEnd != pathBuffer)
2058524dd36SIngo Weinhold			strlcat(pathBuffer, "/", B_PATH_NAME_LENGTH);
2068524dd36SIngo Weinhold
2078524dd36SIngo Weinhold		if (strlcat(pathBuffer, subPath, B_PATH_NAME_LENGTH)
2088524dd36SIngo Weinhold				>= B_PATH_NAME_LENGTH) {
2098524dd36SIngo Weinhold			*fOriginalPathEnd = '\0';
2108524dd36SIngo Weinhold			errorOutput->PrintError("Path too long: \"%s/%s\"\n", pathBuffer,
2118524dd36SIngo Weinhold				subPath);
2128524dd36SIngo Weinhold			throw status_t(B_BUFFER_OVERFLOW);
2138524dd36SIngo Weinhold		}
2147fd711efSOliver Tappe	}
2157fd711efSOliver Tappe
2167fd711efSOliver Tappe	~SubPathAdder()
2177fd711efSOliver Tappe	{
2187fd711efSOliver Tappe		*fOriginalPathEnd = '\0';
2197fd711efSOliver Tappe	}
2208524dd36SIngo Weinhold
2217fd711efSOliver Tappeprivate:
2227fd711efSOliver Tappe	char* fOriginalPathEnd;
2237fd711efSOliver Tappe};
2247fd711efSOliver Tappe
2257fd711efSOliver Tappe
2265fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl (Inline Methods)
2275fb1c6ffSOliver Tappe
2285fb1c6ffSOliver Tappe
2295fb1c6ffSOliver Tappetemplate<typename Type>
2305fb1c6ffSOliver Tappeinline PackageWriterImpl::Attribute*
23133bc4425SOliver TappePackageWriterImpl::_AddAttribute(BHPKGAttributeID attributeID, Type value)
2325fb1c6ffSOliver Tappe{
2335fb1c6ffSOliver Tappe	AttributeValue attributeValue;
2345fb1c6ffSOliver Tappe	attributeValue.SetTo(value);
23533bc4425SOliver Tappe	return _AddAttribute(attributeID, attributeValue);
2365fb1c6ffSOliver Tappe}
2375fb1c6ffSOliver Tappe
2385fb1c6ffSOliver Tappe
2395fb1c6ffSOliver Tappe// #pragma mark - PackageWriterImpl
2405fb1c6ffSOliver Tappe
2415fb1c6ffSOliver Tappe
2427fd711efSOliver TappePackageWriterImpl::PackageWriterImpl(BPackageWriterListener* listener)
2435fb1c6ffSOliver Tappe	:
24491ebce66SOliver Tappe	inherited(listener),
2457fd711efSOliver Tappe	fListener(listener),
2464ee7d007SOliver Tappe	fDataBuffer(NULL),
2474ee7d007SOliver Tappe	fDataBufferSize(2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB),
2485fb1c6ffSOliver Tappe	fRootEntry(NULL),
2495fb1c6ffSOliver Tappe	fRootAttribute(NULL),
25033bc4425SOliver Tappe	fTopAttribute(NULL)
2515fb1c6ffSOliver Tappe{
2525fb1c6ffSOliver Tappe}
2535fb1c6ffSOliver Tappe
2545fb1c6ffSOliver Tappe
2555fb1c6ffSOliver TappePackageWriterImpl::~PackageWriterImpl()
2565fb1c6ffSOliver Tappe{
2575fb1c6ffSOliver Tappe	delete fRootAttribute;
2585fb1c6ffSOliver Tappe
2595fb1c6ffSOliver Tappe	delete fRootEntry;
2605fb1c6ffSOliver Tappe
2615fb1c6ffSOliver Tappe	free(fDataBuffer);
2625fb1c6ffSOliver Tappe}
2635fb1c6ffSOliver Tappe
2645fb1c6ffSOliver Tappe
2655fb1c6ffSOliver Tappestatus_t
2665fb1c6ffSOliver TappePackageWriterImpl::Init(const char* fileName)
2675fb1c6ffSOliver Tappe{
2685fb1c6ffSOliver Tappe	try {
2695fb1c6ffSOliver Tappe		return _Init(fileName);
2705fb1c6ffSOliver Tappe	} catch (status_t error) {
2715fb1c6ffSOliver Tappe		return error;
2725fb1c6ffSOliver Tappe	} catch (std::bad_alloc) {
2737fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
2745fb1c6ffSOliver Tappe		return B_NO_MEMORY;
2755fb1c6ffSOliver Tappe	}
2765fb1c6ffSOliver Tappe}
2775fb1c6ffSOliver Tappe
2785fb1c6ffSOliver Tappe
2795fb1c6ffSOliver Tappestatus_t
2800f9a98a4SIngo WeinholdPackageWriterImpl::AddEntry(const char* fileName, int fd)
2815fb1c6ffSOliver Tappe{
2825fb1c6ffSOliver Tappe	try {
2837fd711efSOliver Tappe		// if it's ".PackageInfo", parse it
2847fd711efSOliver Tappe		if (strcmp(fileName, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
2857fd711efSOliver Tappe			struct ErrorListener : public BPackageInfo::ParseErrorListener {
2867fd711efSOliver Tappe				ErrorListener(BPackageWriterListener* _listener)
2877fd711efSOliver Tappe					: listener(_listener) {}
2887fd711efSOliver Tappe				virtual void OnError(const BString& msg, int line, int col) {
2897fd711efSOliver Tappe					listener->PrintError("Parse error in %s(%d:%d) -> %s\n",
2907fd711efSOliver Tappe						B_HPKG_PACKAGE_INFO_FILE_NAME, line, col, msg.String());
2917fd711efSOliver Tappe				}
2927fd711efSOliver Tappe				BPackageWriterListener* listener;
2937fd711efSOliver Tappe			} errorListener(fListener);
2940f9a98a4SIngo Weinhold
2950f9a98a4SIngo Weinhold			if (fd >= 0) {
2960f9a98a4SIngo Weinhold				// a file descriptor is given -- read the config from there
2970f9a98a4SIngo Weinhold				// stat the file to get the file size
2980f9a98a4SIngo Weinhold				struct stat st;
2990f9a98a4SIngo Weinhold				if (fstat(fd, &st) != 0)
3000f9a98a4SIngo Weinhold					return errno;
3010f9a98a4SIngo Weinhold
3020f9a98a4SIngo Weinhold				BString packageInfoString;
3030f9a98a4SIngo Weinhold				char* buffer = packageInfoString.LockBuffer(st.st_size);
3040f9a98a4SIngo Weinhold				if (buffer == NULL)
3050f9a98a4SIngo Weinhold					return B_NO_MEMORY;
3060f9a98a4SIngo Weinhold
3070f9a98a4SIngo Weinhold				ssize_t result = read_pos(fd, 0, buffer, st.st_size);
3080f9a98a4SIngo Weinhold				if (result < 0) {
3090f9a98a4SIngo Weinhold					packageInfoString.UnlockBuffer(0);
3100f9a98a4SIngo Weinhold					return errno;
3110f9a98a4SIngo Weinhold				}
3120f9a98a4SIngo Weinhold
3130f9a98a4SIngo Weinhold				buffer[st.st_size] = '\0';
3140f9a98a4SIngo Weinhold				packageInfoString.UnlockBuffer(st.st_size);
3150f9a98a4SIngo Weinhold
3160f9a98a4SIngo Weinhold				result = fPackageInfo.ReadFromConfigString(packageInfoString,
3170f9a98a4SIngo Weinhold					&errorListener);
3180f9a98a4SIngo Weinhold				if (result != B_OK)
3190f9a98a4SIngo Weinhold					return result;
3200f9a98a4SIngo Weinhold			} else {
3210f9a98a4SIngo Weinhold				// use the file name
3220f9a98a4SIngo Weinhold				BEntry packageInfoEntry(fileName);
3230f9a98a4SIngo Weinhold				status_t result = fPackageInfo.ReadFromConfigFile(
3240f9a98a4SIngo Weinhold					packageInfoEntry, &errorListener);
3250f9a98a4SIngo Weinhold				if (result != B_OK
3260f9a98a4SIngo Weinhold					|| (result = fPackageInfo.InitCheck()) != B_OK) {
3270f9a98a4SIngo Weinhold					return result;
3280f9a98a4SIngo Weinhold				}
3290f9a98a4SIngo Weinhold			}
3300f9a98a4SIngo Weinhold
331d77c6cd2SOliver Tappe			RegisterPackageInfo(PackageAttributes(), fPackageInfo);
3327fd711efSOliver Tappe		}
3337fd711efSOliver Tappe
3340f9a98a4SIngo Weinhold		return _RegisterEntry(fileName, fd);
3355fb1c6ffSOliver Tappe	} catch (status_t error) {
3365fb1c6ffSOliver Tappe		return error;
3375fb1c6ffSOliver Tappe	} catch (std::bad_alloc) {
3387fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
3395fb1c6ffSOliver Tappe		return B_NO_MEMORY;
3405fb1c6ffSOliver Tappe	}
3415fb1c6ffSOliver Tappe}
3425fb1c6ffSOliver Tappe
3435fb1c6ffSOliver Tappe
3445fb1c6ffSOliver Tappestatus_t
3455fb1c6ffSOliver TappePackageWriterImpl::Finish()
3465fb1c6ffSOliver Tappe{
3475fb1c6ffSOliver Tappe	try {
348d77c6cd2SOliver Tappe		if (fPackageInfo.InitCheck() != B_OK) {
3497fd711efSOliver Tappe			fListener->PrintError("No package-info file found (%s)!\n",
3507fd711efSOliver Tappe				B_HPKG_PACKAGE_INFO_FILE_NAME);
3517fd711efSOliver Tappe			return B_BAD_DATA;
3527fd711efSOliver Tappe		}
353d77c6cd2SOliver Tappe
354d77c6cd2SOliver Tappe		status_t result = _CheckLicenses();
355d77c6cd2SOliver Tappe		if (result != B_OK)
356d77c6cd2SOliver Tappe			return result;
357d77c6cd2SOliver Tappe
3585fb1c6ffSOliver Tappe		return _Finish();
3595fb1c6ffSOliver Tappe	} catch (status_t error) {
3605fb1c6ffSOliver Tappe		return error;
3615fb1c6ffSOliver Tappe	} catch (std::bad_alloc) {
3627fd711efSOliver Tappe		fListener->PrintError("Out of memory!\n");
3635fb1c6ffSOliver Tappe		return B_NO_MEMORY;
3645fb1c6ffSOliver Tappe	}
3655fb1c6ffSOliver Tappe}
3665fb1c6ffSOliver Tappe
3675fb1c6ffSOliver Tappe
3685fb1c6ffSOliver Tappestatus_t
3695fb1c6ffSOliver TappePackageWriterImpl::_Init(const char* fileName)
3705fb1c6ffSOliver Tappe{
37191ebce66SOliver Tappe	status_t result = inherited::Init(fileName, "package");
372f2022173SOliver Tappe	if (result != B_OK)
373f2022173SOliver Tappe		return result;
374f2022173SOliver Tappe
3754ee7d007SOliver Tappe	// allocate data buffer
3764ee7d007SOliver Tappe	fDataBuffer = malloc(fDataBufferSize);
3774ee7d007SOliver Tappe	if (fDataBuffer == NULL)
3784ee7d007SOliver Tappe		throw std::bad_alloc();
3794ee7d007SOliver Tappe
380f2022173SOliver Tappe	if (fStringCache.Init() != B_OK)
3815fb1c6ffSOliver Tappe		throw std::bad_alloc();
3825fb1c6ffSOliver Tappe
3835fb1c6ffSOliver Tappe	// create entry list
3840f9a98a4SIngo Weinhold	fRootEntry = new Entry(NULL, 0, -1, true);
3855fb1c6ffSOliver Tappe
38633bc4425SOliver Tappe	fRootAttribute = new Attribute();
3875fb1c6ffSOliver Tappe
3885fb1c6ffSOliver Tappe	fHeapOffset = fHeapEnd = sizeof(hpkg_header);
3895fb1c6ffSOliver Tappe	fTopAttribute = fRootAttribute;
3905fb1c6ffSOliver Tappe
3915fb1c6ffSOliver Tappe	return B_OK;
3925fb1c6ffSOliver Tappe}
3935fb1c6ffSOliver Tappe
3945fb1c6ffSOliver Tappe
395d77c6cd2SOliver Tappestatus_t
396d77c6cd2SOliver TappePackageWriterImpl::_CheckLicenses()
397d77c6cd2SOliver Tappe{
398d77c6cd2SOliver Tappe	BPath systemLicensePath;
399d77c6cd2SOliver Tappe	status_t result
4007162cff6SIngo Weinhold#ifdef HAIKU_TARGET_PLATFORM_HAIKU
401d77c6cd2SOliver Tappe		= find_directory(B_SYSTEM_DATA_DIRECTORY, &systemLicensePath);
4027162cff6SIngo Weinhold#else
4037162cff6SIngo Weinhold		= systemLicensePath.SetTo(HAIKU_BUILD_SYSTEM_DATA_DIRECTORY);
4047162cff6SIngo Weinhold#endif
405d77c6cd2SOliver Tappe	if (result != B_OK) {
406d77c6cd2SOliver Tappe		fListener->PrintError("unable to find system data path!\n");
407d77c6cd2SOliver Tappe		return result;
408d77c6cd2SOliver Tappe	}
409d77c6cd2SOliver Tappe	if ((result = systemLicensePath.Append("licenses")) != B_OK) {
410d77c6cd2SOliver Tappe		fListener->PrintError("unable to append to system data path!\n");
411d77c6cd2SOliver Tappe		return result;
412d77c6cd2SOliver Tappe	}
413d77c6cd2SOliver Tappe
414d77c6cd2SOliver Tappe	BDirectory systemLicenseDir(systemLicensePath.Path());
415d77c6cd2SOliver Tappe	BDirectory packageLicenseDir("./data/licenses");
416d77c6cd2SOliver Tappe
417d77c6cd2SOliver Tappe	const BObjectList<BString>& licenseList = fPackageInfo.LicenseList();
418d77c6cd2SOliver Tappe	for (int i = 0; i < licenseList.CountItems(); ++i) {
419d77c6cd2SOliver Tappe		const BString& licenseName = *licenseList.ItemAt(i);
4207ea4dbceSIngo Weinhold		if (licenseName == kPublicDomainLicenseName)
4217ea4dbceSIngo Weinhold			continue;
4227ea4dbceSIngo Weinhold
423d77c6cd2SOliver Tappe		BEntry license;
424d77c6cd2SOliver Tappe		if (systemLicenseDir.FindEntry(licenseName.String(), &license) == B_OK)
425d77c6cd2SOliver Tappe			continue;
426d77c6cd2SOliver Tappe
427d77c6cd2SOliver Tappe		// license is not a system license, so it must be contained in package
428d77c6cd2SOliver Tappe		if (packageLicenseDir.FindEntry(licenseName.String(),
429d77c6cd2SOliver Tappe				&license) != B_OK) {
430d77c6cd2SOliver Tappe			fListener->PrintError("License '%s' isn't contained in package!\n",
431d77c6cd2SOliver Tappe				licenseName.String());
432d77c6cd2SOliver Tappe			return B_BAD_DATA;
433d77c6cd2SOliver Tappe		}
434d77c6cd2SOliver Tappe	}
435d77c6cd2SOliver Tappe
436d77c6cd2SOliver Tappe	return B_OK;
437d77c6cd2SOliver Tappe}
438d77c6cd2SOliver Tappe
439d77c6cd2SOliver Tappe
4405fb1c6ffSOliver Tappestatus_t
4415fb1c6ffSOliver TappePackageWriterImpl::_Finish()
4425fb1c6ffSOliver Tappe{
4435fb1c6ffSOliver Tappe	// write entries
4445fb1c6ffSOliver Tappe	for (EntryList::ConstIterator it = fRootEntry->ChildIterator();
4455fb1c6ffSOliver Tappe			Entry* entry = it.Next();) {
4467fd711efSOliver Tappe		char pathBuffer[B_PATH_NAME_LENGTH];
4477fd711efSOliver Tappe		pathBuffer[0] = '\0';
4487fd711efSOliver Tappe		_AddEntry(AT_FDCWD, entry, entry->Name(), pathBuffer);
4495fb1c6ffSOliver Tappe	}
4505fb1c6ffSOliver Tappe
4517fd711efSOliver Tappe	off_t heapSize = fHeapEnd - sizeof(hpkg_header);
4525fb1c6ffSOliver Tappe
4535fb1c6ffSOliver Tappe	hpkg_header header;
4545fb1c6ffSOliver Tappe
4555fb1c6ffSOliver Tappe	// write the TOC and package attributes
4565fb1c6ffSOliver Tappe	_WriteTOC(header);
4575fb1c6ffSOliver Tappe	_WritePackageAttributes(header);
4585fb1c6ffSOliver Tappe
4595fb1c6ffSOliver Tappe	off_t totalSize = fHeapEnd;
4607fd711efSOliver Tappe
4617fd711efSOliver Tappe	fListener->OnPackageSizeInfo(sizeof(hpkg_header), heapSize,
4627fd711efSOliver Tappe		B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed),
4637fd711efSOliver Tappe		B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed),
4647fd711efSOliver Tappe		totalSize);
4655fb1c6ffSOliver Tappe
4665fb1c6ffSOliver Tappe	// prepare the header
4675fb1c6ffSOliver Tappe
4685fb1c6ffSOliver Tappe	// general
4695fb1c6ffSOliver Tappe	header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC);
4705fb1c6ffSOliver Tappe	header.header_size = B_HOST_TO_BENDIAN_INT16(
4715fb1c6ffSOliver Tappe		(uint16)sizeof(hpkg_header));
4725fb1c6ffSOliver Tappe	header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION);
4735fb1c6ffSOliver Tappe	header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize);
4745fb1c6ffSOliver Tappe
4755fb1c6ffSOliver Tappe	// write the header
476f2022173SOliver Tappe	WriteBuffer(&header, sizeof(hpkg_header), 0);
4775fb1c6ffSOliver Tappe
4784ee7d007SOliver Tappe	SetFinished(true);
4795fb1c6ffSOliver Tappe	return B_OK;
4805fb1c6ffSOliver Tappe}
4815fb1c6ffSOliver Tappe
4825fb1c6ffSOliver Tappe
4835fb1c6ffSOliver Tappestatus_t
4840f9a98a4SIngo WeinholdPackageWriterImpl::_RegisterEntry(const char* fileName, int fd)
4855fb1c6ffSOliver Tappe{
4865fb1c6ffSOliver Tappe	if (*fileName == '\0') {
4877fd711efSOliver Tappe		fListener->PrintError("Invalid empty file name\n");
4885fb1c6ffSOliver Tappe		return B_BAD_VALUE;
4895fb1c6ffSOliver Tappe	}
4905fb1c6ffSOliver Tappe
4915fb1c6ffSOliver Tappe	// add all components of the path
4925fb1c6ffSOliver Tappe	Entry* entry = fRootEntry;
4935fb1c6ffSOliver Tappe	while (*fileName != 0) {
4945fb1c6ffSOliver Tappe		const char* nextSlash = strchr(fileName, '/');
4955fb1c6ffSOliver Tappe		// no slash, just add the file name
4965fb1c6ffSOliver Tappe		if (nextSlash == NULL) {
4970f9a98a4SIngo Weinhold			entry = _RegisterEntry(entry, fileName, strlen(fileName), fd,
4980f9a98a4SIngo Weinhold				false);
4995fb1c6ffSOliver Tappe			break;
5005fb1c6ffSOliver Tappe		}
5015fb1c6ffSOliver Tappe
5025fb1c6ffSOliver Tappe		// find the start of the next component, skipping slashes
5035fb1c6ffSOliver Tappe		const char* nextComponent = nextSlash + 1;
5045fb1c6ffSOliver Tappe		while (*nextComponent == '/')
5055fb1c6ffSOliver Tappe			nextComponent++;
5065fb1c6ffSOliver Tappe
5070f9a98a4SIngo Weinhold		bool lastComponent = *nextComponent != '\0';
5080f9a98a4SIngo Weinhold
5095fb1c6ffSOliver Tappe		if (nextSlash == fileName) {
5105fb1c6ffSOliver Tappe			// the FS root
5110f9a98a4SIngo Weinhold			entry = _RegisterEntry(entry, fileName, 1, lastComponent ? fd : -1,
5120f9a98a4SIngo Weinhold				lastComponent);
5135fb1c6ffSOliver Tappe		} else {
5145fb1c6ffSOliver Tappe			entry = _RegisterEntry(entry, fileName, nextSlash - fileName,
5150f9a98a4SIngo Weinhold				lastComponent ? fd : -1, lastComponent);
5165fb1c6ffSOliver Tappe		}
5175fb1c6ffSOliver Tappe
5185fb1c6ffSOliver Tappe		fileName = nextComponent;
5195fb1c6ffSOliver Tappe	}
5205fb1c6ffSOliver Tappe
5215fb1c6ffSOliver Tappe	return B_OK;
5225fb1c6ffSOliver Tappe}
5235fb1c6ffSOliver Tappe
5245fb1c6ffSOliver Tappe
5255fb1c6ffSOliver TappePackageWriterImpl::Entry*
5265fb1c6ffSOliver TappePackageWriterImpl::_RegisterEntry(Entry* parent, const char* name,
5270f9a98a4SIngo Weinhold	size_t nameLength, int fd, bool isImplicit)
5285fb1c6ffSOliver Tappe{
5295fb1c6ffSOliver Tappe	// check the component name -- don't allow "." or ".."
5305fb1c6ffSOliver Tappe	if (name[0] == '.'
5315fb1c6ffSOliver Tappe		&& (nameLength == 1 || (nameLength == 2 && name[1] == '.'))) {
5327fd711efSOliver Tappe		fListener->PrintError("Invalid file name: \".\" and \"..\" "
5335fb1c6ffSOliver Tappe			"are not allowed as path components\n");
5345fb1c6ffSOliver Tappe		throw status_t(B_BAD_VALUE);
5355fb1c6ffSOliver Tappe	}
5365fb1c6ffSOliver Tappe
5375fb1c6ffSOliver Tappe	// the entry might already exist
5385fb1c6ffSOliver Tappe	Entry* entry = parent->GetChild(name, nameLength);
5395fb1c6ffSOliver Tappe	if (entry != NULL) {
5405fb1c6ffSOliver Tappe		// If the entry was implicit and is no longer, we mark it non-implicit
5415fb1c6ffSOliver Tappe		// and delete all of it's children.
5425fb1c6ffSOliver Tappe		if (entry->IsImplicit() && !isImplicit) {
5435fb1c6ffSOliver Tappe			entry->DeleteChildren();
5445fb1c6ffSOliver Tappe			entry->SetImplicit(false);
5450f9a98a4SIngo Weinhold			entry->SetFD(fd);
5465fb1c6ffSOliver Tappe		}
5475fb1c6ffSOliver Tappe	} else {
5485fb1c6ffSOliver Tappe		// nope -- create it
5490f9a98a4SIngo Weinhold		entry = Entry::Create(name, nameLength, fd, isImplicit);
5505fb1c6ffSOliver Tappe		parent->AddChild(entry);
5515fb1c6ffSOliver Tappe	}
5525fb1c6ffSOliver Tappe
5535fb1c6ffSOliver Tappe	return entry;
5545fb1c6ffSOliver Tappe}
5555fb1c6ffSOliver Tappe
5565fb1c6ffSOliver Tappe
5575fb1c6ffSOliver Tappevoid
5585fb1c6ffSOliver TappePackageWriterImpl::_WriteTOC(hpkg_header& header)
5595fb1c6ffSOliver Tappe{
5605fb1c6ffSOliver Tappe	// prepare the writer (zlib writer on top of a file writer)
5615fb1c6ffSOliver Tappe	off_t startOffset = fHeapEnd;
5624ee7d007SOliver Tappe	FDDataWriter realWriter(FD(), startOffset, fListener);
5635fb1c6ffSOliver Tappe	ZlibDataWriter zlibWriter(&realWriter);
5644ee7d007SOliver Tappe	SetDataWriter(&zlibWriter);
5655fb1c6ffSOliver Tappe	zlibWriter.Init();
5665fb1c6ffSOliver Tappe
5675fb1c6ffSOliver Tappe	// write the sections
5685fb1c6ffSOliver Tappe	uint64 uncompressedStringsSize;
5695fb1c6ffSOliver Tappe	uint64 uncompressedMainSize;
57033bc4425SOliver Tappe	int32 cachedStringsWritten
57133bc4425SOliver Tappe		= _WriteTOCSections(uncompressedStringsSize, uncompressedMainSize);
5725fb1c6ffSOliver Tappe
5735fb1c6ffSOliver Tappe	// finish the writer
5745fb1c6ffSOliver Tappe	zlibWriter.Finish();
5755fb1c6ffSOliver Tappe	fHeapEnd = realWriter.Offset();
5764ee7d007SOliver Tappe	SetDataWriter(NULL);
5775fb1c6ffSOliver Tappe
5785fb1c6ffSOliver Tappe	off_t endOffset = fHeapEnd;
5797fd711efSOliver Tappe
58033bc4425SOliver Tappe	fListener->OnTOCSizeInfo(uncompressedStringsSize, uncompressedMainSize,
5817fd711efSOliver Tappe		zlibWriter.BytesWritten());
5825fb1c6ffSOliver Tappe
5835fb1c6ffSOliver Tappe	// update the header
5845fb1c6ffSOliver Tappe
5855fb1c6ffSOliver Tappe	// TOC
5865fb1c6ffSOliver Tappe	header.toc_compression = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB);
5875fb1c6ffSOliver Tappe	header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64(
5885fb1c6ffSOliver Tappe		endOffset - startOffset);
5895fb1c6ffSOliver Tappe	header.toc_length_uncompressed = B_HOST_TO_BENDIAN_INT64(
5905fb1c6ffSOliver Tappe		zlibWriter.BytesWritten());
5915fb1c6ffSOliver Tappe
5925fb1c6ffSOliver Tappe	// TOC subsections
5935fb1c6ffSOliver Tappe	header.toc_strings_length = B_HOST_TO_BENDIAN_INT64(
5945fb1c6ffSOliver Tappe		uncompressedStringsSize);
5955fb1c6ffSOliver Tappe	header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten);
5965fb1c6ffSOliver Tappe}
5975fb1c6ffSOliver Tappe
5985fb1c6ffSOliver Tappe
5995fb1c6ffSOliver Tappeint32
60033bc4425SOliver TappePackageWriterImpl::_WriteTOCSections(uint64& _stringsSize, uint64& _mainSize)
6015fb1c6ffSOliver Tappe{
6025fb1c6ffSOliver Tappe	// write the cached strings
6034ee7d007SOliver Tappe	uint64 cachedStringsOffset = DataWriter()->BytesWritten();
604f2022173SOliver Tappe	int32 cachedStringsWritten = WriteCachedStrings(fStringCache, 2);
6055fb1c6ffSOliver Tappe
6065fb1c6ffSOliver Tappe	// write the main TOC section
6074ee7d007SOliver Tappe	uint64 mainOffset = DataWriter()->BytesWritten();
6085fb1c6ffSOliver Tappe	_WriteAttributeChildren(fRootAttribute);
6095fb1c6ffSOliver Tappe
6105fb1c6ffSOliver Tappe	_stringsSize = mainOffset - cachedStringsOffset;
6114ee7d007SOliver Tappe	_mainSize = DataWriter()->BytesWritten() - mainOffset;
6125fb1c6ffSOliver Tappe
6135fb1c6ffSOliver Tappe	return cachedStringsWritten;
6145fb1c6ffSOliver Tappe}
6155fb1c6ffSOliver Tappe
6165fb1c6ffSOliver Tappe
6175fb1c6ffSOliver Tappevoid
6185fb1c6ffSOliver TappePackageWriterImpl::_WriteAttributeChildren(Attribute* attribute)
6195fb1c6ffSOliver Tappe{
6205fb1c6ffSOliver Tappe	DoublyLinkedList<Attribute>::Iterator it
6215fb1c6ffSOliver Tappe		= attribute->children.GetIterator();
6225fb1c6ffSOliver Tappe	while (Attribute* child = it.Next()) {
6235fb1c6ffSOliver Tappe		// write tag
624f2022173SOliver Tappe		uint8 encoding = child->value.ApplicableEncoding();
62533bc4425SOliver Tappe		WriteUnsignedLEB128(HPKG_ATTRIBUTE_TAG_COMPOSE(child->id,
62633bc4425SOliver Tappe			child->value.type, encoding, !child->children.IsEmpty()));
6275fb1c6ffSOliver Tappe
6285fb1c6ffSOliver Tappe		// write value
629f2022173SOliver Tappe		WriteAttributeValue(child->value, encoding);
6305fb1c6ffSOliver Tappe
6315fb1c6ffSOliver Tappe		if (!child->children.IsEmpty())
6325fb1c6ffSOliver Tappe			_WriteAttributeChildren(child);
6335fb1c6ffSOliver Tappe	}
6345fb1c6ffSOliver Tappe
635f2022173SOliver Tappe	WriteUnsignedLEB128(0);
6365fb1c6ffSOliver Tappe}
6375fb1c6ffSOliver Tappe
6385fb1c6ffSOliver Tappe
6395fb1c6ffSOliver Tappevoid
6405fb1c6ffSOliver TappePackageWriterImpl::_WritePackageAttributes(hpkg_header& header)
6415fb1c6ffSOliver Tappe{
642fd9c0b33SOliver Tappe	// write the package attributes (zlib writer on top of a file writer)
6435fb1c6ffSOliver Tappe	off_t startOffset = fHeapEnd;
6444ee7d007SOliver Tappe	FDDataWriter realWriter(FD(), startOffset, fListener);
645fd9c0b33SOliver Tappe	ZlibDataWriter zlibWriter(&realWriter);
6464ee7d007SOliver Tappe	SetDataWriter(&zlibWriter);
647fd9c0b33SOliver Tappe	zlibWriter.Init();
6485fb1c6ffSOliver Tappe
6494ee7d007SOliver Tappe	// write cached strings and package attributes tree
6504ee7d007SOliver Tappe	uint32 stringsLengthUncompressed;
6514ee7d007SOliver Tappe	uint32 stringsCount = WritePackageAttributes(PackageAttributes(),
6524ee7d007SOliver Tappe		stringsLengthUncompressed);
653fd9c0b33SOliver Tappe
654fd9c0b33SOliver Tappe	zlibWriter.Finish();
6555fb1c6ffSOliver Tappe	fHeapEnd = realWriter.Offset();
6564ee7d007SOliver Tappe	SetDataWriter(NULL);
6575fb1c6ffSOliver Tappe
6585fb1c6ffSOliver Tappe	off_t endOffset = fHeapEnd;
6595fb1c6ffSOliver Tappe
660f2022173SOliver Tappe	fListener->OnPackageAttributesSizeInfo(stringsCount,
661f2022173SOliver Tappe		zlibWriter.BytesWritten());
6625fb1c6ffSOliver Tappe
6635fb1c6ffSOliver Tappe	// update the header
664fd9c0b33SOliver Tappe	header.attributes_compression
665fd9c0b33SOliver Tappe		= B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB);
6665fb1c6ffSOliver Tappe	header.attributes_length_compressed
6675fb1c6ffSOliver Tappe		= B_HOST_TO_BENDIAN_INT32(endOffset - startOffset);
6685fb1c6ffSOliver Tappe	header.attributes_length_uncompressed
669fd9c0b33SOliver Tappe		= B_HOST_TO_BENDIAN_INT32(zlibWriter.BytesWritten());
6704ee7d007SOliver Tappe	header.attributes_strings_count = B_HOST_TO_BENDIAN_INT32(stringsCount);
671f2022173SOliver Tappe	header.attributes_strings_length
672