133bc4425SOliver Tappe/*
233bc4425SOliver Tappe * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
333bc4425SOliver Tappe * Distributed under the terms of the MIT License.
433bc4425SOliver Tappe */
533bc4425SOliver Tappe
633bc4425SOliver Tappe
734d56c1bSOliver Tappe#include <package/hpkg/RepositoryReaderImpl.h>
833bc4425SOliver Tappe
933bc4425SOliver Tappe#include <errno.h>
1033bc4425SOliver Tappe#include <stdio.h>
1133bc4425SOliver Tappe#include <stdlib.h>
1233bc4425SOliver Tappe#include <string.h>
1333bc4425SOliver Tappe#include <sys/stat.h>
1433bc4425SOliver Tappe
1533bc4425SOliver Tappe#include <algorithm>
1633bc4425SOliver Tappe#include <new>
1733bc4425SOliver Tappe
1833bc4425SOliver Tappe#include <ByteOrder.h>
1934d56c1bSOliver Tappe#include <Message.h>
2033bc4425SOliver Tappe
21e527b796SIngo Weinhold#include <FdIO.h>
22e527b796SIngo Weinhold
232b6e6760SOliver Tappe#include <package/hpkg/HPKGDefsPrivate.h>
242b6e6760SOliver Tappe#include <package/hpkg/RepositoryContentHandler.h>
2533bc4425SOliver Tappe
2633bc4425SOliver Tappe
2733bc4425SOliver Tappenamespace BPackageKit {
2833bc4425SOliver Tappe
2933bc4425SOliver Tappenamespace BHPKG {
3033bc4425SOliver Tappe
3133bc4425SOliver Tappenamespace BPrivate {
3233bc4425SOliver Tappe
3333bc4425SOliver Tappe
3433bc4425SOliver Tappe//#define TRACE(format...)	printf(format)
3533bc4425SOliver Tappe#define TRACE(format...)	do {} while (false)
3633bc4425SOliver Tappe
3733bc4425SOliver Tappe
3834d56c1bSOliver Tappe// maximum repository info size we support reading
3934d56c1bSOliver Tappestatic const size_t kMaxRepositoryInfoSize		= 1 * 1024 * 1024;
4033bc4425SOliver Tappe
4133bc4425SOliver Tappe// maximum package attributes size we support reading
4234d56c1bSOliver Tappestatic const size_t kMaxPackageAttributesSize	= 64 * 1024 * 1024;
4333bc4425SOliver Tappe
4433bc4425SOliver Tappe
45e8533402SIngo Weinhold// #pragma mark - PackagesAttributeHandler
46e8533402SIngo Weinhold
47e8533402SIngo Weinhold
48e8533402SIngo Weinholdclass RepositoryReaderImpl::PackagesAttributeHandler
49e8533402SIngo Weinhold	: public AttributeHandler {
500a345af7SOliver Tappeprivate:
510a345af7SOliver Tappe	typedef AttributeHandler super;
52e8533402SIngo Weinholdpublic:
53e8533402SIngo Weinhold	PackagesAttributeHandler(BRepositoryContentHandler* contentHandler)
54e8533402SIngo Weinhold		:
55e8533402SIngo Weinhold		fContentHandler(contentHandler),
56e8533402SIngo Weinhold		fPackageName(NULL)
57e8533402SIngo Weinhold	{
58e8533402SIngo Weinhold	}
59e8533402SIngo Weinhold
60e8533402SIngo Weinhold	virtual status_t HandleAttribute(AttributeHandlerContext* context, uint8 id,
61e8533402SIngo Weinhold		const AttributeValue& value, AttributeHandler** _handler)
62e8533402SIngo Weinhold	{
63e8533402SIngo Weinhold		switch (id) {
64e8533402SIngo Weinhold			case B_HPKG_ATTRIBUTE_ID_PACKAGE:
65e8533402SIngo Weinhold			{
66e8533402SIngo Weinhold				status_t error = _NotifyPackageDone();
67e8533402SIngo Weinhold				if (error != B_OK)
68e8533402SIngo Weinhold					return error;
69e8533402SIngo Weinhold
70e8533402SIngo Weinhold				if (_handler != NULL) {
71e8533402SIngo Weinhold					if (fContentHandler != NULL) {
72e8533402SIngo Weinhold						error = fContentHandler->HandlePackage(value.string);
73e8533402SIngo Weinhold						if (error != B_OK)
74e8533402SIngo Weinhold							return error;
75e8533402SIngo Weinhold					}
76e8533402SIngo Weinhold
77e8533402SIngo Weinhold					*_handler = new(std::nothrow) PackageAttributeHandler;
78e8533402SIngo Weinhold					if (*_handler == NULL)
79e8533402SIngo Weinhold						return B_NO_MEMORY;
80e8533402SIngo Weinhold
81e8533402SIngo Weinhold					fPackageName = value.string;
82e8533402SIngo Weinhold				}
83e8533402SIngo Weinhold				break;
84e8533402SIngo Weinhold			}
85e8533402SIngo Weinhold
86e8533402SIngo Weinhold			default:
87e8533402SIngo Weinhold				if (context->ignoreUnknownAttributes)
88e8533402SIngo Weinhold					break;
89e8533402SIngo Weinhold
90e8533402SIngo Weinhold				context->errorOutput->PrintError(
91e8533402SIngo Weinhold					"Error: Invalid package attribute section: unexpected "
92e8533402SIngo Weinhold					"top level attribute id %d encountered\n", id);
93e8533402SIngo Weinhold				return B_BAD_DATA;
94e8533402SIngo Weinhold		}
95e8533402SIngo Weinhold
96e8533402SIngo Weinhold		return B_OK;
97e8533402SIngo Weinhold	}
98e8533402SIngo Weinhold
990a345af7SOliver Tappe	virtual status_t NotifyDone(AttributeHandlerContext* context)
100e8533402SIngo Weinhold	{
1010a345af7SOliver Tappe		status_t result = _NotifyPackageDone();
1020a345af7SOliver Tappe		if (result == B_OK)
1030a345af7SOliver Tappe			result = super::NotifyDone(context);
1040a345af7SOliver Tappe		return result;
105e8533402SIngo Weinhold	}
106e8533402SIngo Weinhold
107e8533402SIngo Weinholdprivate:
108e8533402SIngo Weinhold	status_t _NotifyPackageDone()
109e8533402SIngo Weinhold	{
110e8533402SIngo Weinhold		if (fPackageName == NULL || fContentHandler == NULL)
111e8533402SIngo Weinhold			return B_OK;
112e8533402SIngo Weinhold
113e8533402SIngo Weinhold		status_t error = fContentHandler->HandlePackageDone(fPackageName);
114e8533402SIngo Weinhold		fPackageName = NULL;
115e8533402SIngo Weinhold		return error;
116e8533402SIngo Weinhold	}
117e8533402SIngo Weinhold
118e8533402SIngo Weinholdprivate:
119e8533402SIngo Weinhold	BRepositoryContentHandler*	fContentHandler;
120e8533402SIngo Weinhold	const char*					fPackageName;
121e8533402SIngo Weinhold};
122e8533402SIngo Weinhold
123e8533402SIngo Weinhold
124e8533402SIngo Weinhold// #pragma mark - PackageContentHandlerAdapter
125e8533402SIngo Weinhold
126e8533402SIngo Weinhold
127e8533402SIngo Weinholdclass RepositoryReaderImpl::PackageContentHandlerAdapter
128e8533402SIngo Weinhold	: public BPackageContentHandler {
129e8533402SIngo Weinholdpublic:
130e8533402SIngo Weinhold	PackageContentHandlerAdapter(BRepositoryContentHandler* contentHandler)
131e8533402SIngo Weinhold		:
132e8533402SIngo Weinhold		fContentHandler(contentHandler)
133e8533402SIngo Weinhold	{
134e8533402SIngo Weinhold	}
135e8533402SIngo Weinhold
136e8533402SIngo Weinhold	virtual status_t HandleEntry(BPackageEntry* entry)
137e8533402SIngo Weinhold	{
138e8533402SIngo Weinhold		return B_OK;
139e8533402SIngo Weinhold	}
140e8533402SIngo Weinhold
141e8533402SIngo Weinhold	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
142e8533402SIngo Weinhold		BPackageEntryAttribute* attribute)
143e8533402SIngo Weinhold	{
144e8533402SIngo Weinhold		return B_OK;
145e8533402SIngo Weinhold	}
146e8533402SIngo Weinhold
147e8533402SIngo Weinhold	virtual status_t HandleEntryDone(BPackageEntry* entry)
148e8533402SIngo Weinhold	{
149e8533402SIngo Weinhold		return B_OK;
150e8533402SIngo Weinhold	}
151e8533402SIngo Weinhold
152e8533402SIngo Weinhold	virtual status_t HandlePackageAttribute(
153e8533402SIngo Weinhold		const BPackageInfoAttributeValue& value)
154e8533402SIngo Weinhold	{
155e8533402SIngo Weinhold		return fContentHandler->HandlePackageAttribute(value);
156e8533402SIngo Weinhold	}
157e8533402SIngo Weinhold
158e8533402SIngo Weinhold	virtual void HandleErrorOccurred()
159e8533402SIngo Weinhold	{
160e8533402SIngo Weinhold		return fContentHandler->HandleErrorOccurred();
161e8533402SIngo Weinhold	}
162e8533402SIngo Weinhold
163e8533402SIngo Weinholdprivate:
164e8533402SIngo Weinhold	BRepositoryContentHandler*	fContentHandler;
165e8533402SIngo Weinhold};
166e8533402SIngo Weinhold
167e8533402SIngo Weinhold
168e8533402SIngo Weinhold// #pragma mark - RepositoryReaderImpl
169e8533402SIngo Weinhold
170e8533402SIngo Weinhold
17134d56c1bSOliver TappeRepositoryReaderImpl::RepositoryReaderImpl(BErrorOutput* errorOutput)
17233bc4425SOliver Tappe	:
1731f633814SIngo Weinhold	inherited("repository", errorOutput)
17433bc4425SOliver Tappe{
17533bc4425SOliver Tappe}
17633bc4425SOliver Tappe
17733bc4425SOliver Tappe
17834d56c1bSOliver TappeRepositoryReaderImpl::~RepositoryReaderImpl()
17933bc4425SOliver Tappe{
18033bc4425SOliver Tappe}
18133bc4425SOliver Tappe
18233bc4425SOliver Tappe
18333bc4425SOliver Tappestatus_t
18434d56c1bSOliver TappeRepositoryReaderImpl::Init(const char* fileName)
18533bc4425SOliver Tappe{
18633bc4425SOliver Tappe	// open file
18733bc4425SOliver Tappe	int fd = open(fileName, O_RDONLY);
18833bc4425SOliver Tappe	if (fd < 0) {
18934d56c1bSOliver Tappe		ErrorOutput()->PrintError(
19034d56c1bSOliver Tappe			"Error: Failed to open repository file \"%s\": %s\n", fileName,
19134d56c1bSOliver Tappe			strerror(errno));
19233bc4425SOliver Tappe		return errno;
19333bc4425SOliver Tappe	}
19433bc4425SOliver Tappe
19533bc4425SOliver Tappe	return Init(fd, true);
19633bc4425SOliver Tappe}
19733bc4425SOliver Tappe
19833bc4425SOliver Tappe
19933bc4425SOliver Tappestatus_t
20034d56c1bSOliver TappeRepositoryReaderImpl::Init(int fd, bool keepFD)
201e527b796SIngo Weinhold{
202e527b796SIngo Weinhold	BFdIO* file = new(std::nothrow) BFdIO(fd, keepFD);
203e527b796SIngo Weinhold	if (file == NULL) {
204e527b796SIngo Weinhold		if (keepFD && fd >= 0)
205e527b796SIngo Weinhold			close(fd);
206e527b796SIngo Weinhold		return B_NO_MEMORY;
207e527b796SIngo Weinhold	}
208e527b796SIngo Weinhold
209e527b796SIngo Weinhold	return Init(file, true);
210e527b796SIngo Weinhold}
211e527b796SIngo Weinhold
212e527b796SIngo Weinhold
213e527b796SIngo Weinholdstatus_t
214e527b796SIngo WeinholdRepositoryReaderImpl::Init(BPositionIO* file, bool keepFile)
21533bc4425SOliver Tappe{
2161f633814SIngo Weinhold	hpkg_repo_header header;
2171f633814SIngo Weinhold	status_t error = inherited::Init<hpkg_repo_header, B_HPKG_REPO_MAGIC,
218e527b796SIngo Weinhold		B_HPKG_REPO_VERSION, B_HPKG_REPO_MINOR_VERSION>(file, keepFile, header,
219e527b796SIngo Weinhold		0);
22034d56c1bSOliver Tappe	if (error != B_OK)
22134d56c1bSOliver Tappe		return error;
22233bc4425SOliver Tappe
2231f633814SIngo Weinhold	// init package attributes section
2241f633814SIngo Weinhold	error = InitSection(fPackageAttributesSection,
22546122852SIngo Weinhold		UncompressedHeapSize(),
2261f633814SIngo Weinhold		B_BENDIAN_TO_HOST_INT64(header.packages_length),
2271f633814SIngo Weinhold		kMaxPackageAttributesSize,
2281f633814SIngo Weinhold		B_BENDIAN_TO_HOST_INT64(header.packages_strings_length),
2291f633814SIngo Weinhold		B_BENDIAN_TO_HOST_INT64(header.packages_strings_count));
2301f633814SIngo Weinhold	if (error != B_OK)
23133bc4425SOliver Tappe		return error;
23233bc4425SOliver Tappe
2331f633814SIngo Weinhold	// init repository info section
2341f633814SIngo Weinhold	PackageFileSection repositoryInfoSection("repository info");
2351f633814SIngo Weinhold	error = InitSection(repositoryInfoSection,
2361f633814SIngo Weinhold		fPackageAttributesSection.offset,
2371f633814SIngo Weinhold		B_BENDIAN_TO_HOST_INT32(header.info_length), kMaxRepositoryInfoSize, 0,
2381f633814SIngo Weinhold		0);
2391f633814SIngo Weinhold	if (error != B_OK)
2401f633814SIngo Weinhold		return error;
24133bc4425SOliver Tappe
2421f633814SIngo Weinhold	// prepare the sections for use
2431f633814SIngo Weinhold	error = PrepareSection(repositoryInfoSection);
24433bc4425SOliver Tappe	if (error != B_OK)
24533bc4425SOliver Tappe		return error;
24633bc4425SOliver Tappe
2471f633814SIngo Weinhold	error = PrepareSection(fPackageAttributesSection);
24833bc4425SOliver Tappe	if (error != B_OK)
24933bc4425SOliver Tappe		return error;
25033bc4425SOliver Tappe
25134d56c1bSOliver Tappe	// unarchive repository info
25234d56c1bSOliver Tappe	BMessage repositoryInfoArchive;
2531f633814SIngo Weinhold	error = repositoryInfoArchive.Unflatten((char*)repositoryInfoSection.data);
25433bc4425SOliver Tappe	if (error != B_OK) {
25534d56c1bSOliver Tappe		ErrorOutput()->PrintError(
25634d56c1bSOliver Tappe			"Error: Unable to unflatten repository info archive!\n");
25733bc4425SOliver Tappe		return error;
25833bc4425SOliver Tappe	}
25934d56c1bSOliver Tappe	error = fRepositoryInfo.SetTo(&repositoryInfoArchive);
26034d56c1bSOliver Tappe	if (error != B_OK) {
26134d56c1bSOliver Tappe		ErrorOutput()->PrintError(
26234d56c1bSOliver Tappe			"Error: Unable to unarchive repository info!\n");
26333bc4425SOliver Tappe		return error;
26433bc4425SOliver Tappe	}
26533bc4425SOliver Tappe
26633bc4425SOliver Tappe	return B_OK;
26733bc4425SOliver Tappe}
26833bc4425SOliver Tappe
26933bc4425SOliver Tappe
27033bc4425SOliver Tappestatus_t
27134d56c1bSOliver TappeRepositoryReaderImpl::GetRepositoryInfo(BRepositoryInfo* _repositoryInfo) const
27233bc4425SOliver Tappe{
27334d56c1bSOliver Tappe	if (_repositoryInfo == NULL)
27434d56c1bSOliver Tappe		return B_BAD_VALUE;
27533bc4425SOliver Tappe
27634d56c1bSOliver Tappe	*_repositoryInfo = fRepositoryInfo;
27733bc4425SOliver Tappe	return B_OK;
27833bc4425SOliver Tappe}
27933bc4425SOliver Tappe
28033bc4425SOliver Tappe
28133bc4425SOliver Tappestatus_t
2822b6e6760SOliver TappeRepositoryReaderImpl::ParseContent(BRepositoryContentHandler* contentHandler)
28333bc4425SOliver Tappe{
2842b6e6760SOliver Tappe	status_t result = contentHandler->HandleRepositoryInfo(fRepositoryInfo);
28597aabbedSIngo Weinhold	if (result == B_OK) {
286e8533402SIngo Weinhold		PackageContentHandlerAdapter contentHandlerAdapter(contentHandler);
287e8533402SIngo Weinhold		AttributeHandlerContext context(ErrorOutput(),
288e8533402SIngo Weinhold			contentHandler != NULL ? &contentHandlerAdapter : NULL,
28947039b85SIngo Weinhold			B_HPKG_SECTION_PACKAGE_ATTRIBUTES,
29047039b85SIngo Weinhold			MinorFormatVersion() > B_HPKG_REPO_MINOR_VERSION);
291e8533402SIngo Weinhold		PackagesAttributeHandler rootAttributeHandler(contentHandler);
2922b6e6760SOliver Tappe		result = ParsePackageAttributesSection(&context, &rootAttributeHandler);
29397aabbedSIngo Weinhold	}
2942b6e6760SOliver Tappe	return result;
29533bc4425SOliver Tappe}
29633bc4425SOliver Tappe
29733bc4425SOliver Tappe
29833bc4425SOliver Tappe}	// namespace BPrivate
29933bc4425SOliver Tappe
30033bc4425SOliver Tappe}	// namespace BHPKG
30133bc4425SOliver Tappe
30233bc4425SOliver Tappe}	// namespace BPackageKit
303