1/*
2 * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <package/hpkg/PackageReaderImpl.h>
9
10#include <errno.h>
11#include <fcntl.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/stat.h>
16#include <unistd.h>
17
18#include <algorithm>
19#include <new>
20
21#include <ByteOrder.h>
22
23#include <FdIO.h>
24
25#include <package/hpkg/HPKGDefsPrivate.h>
26
27#include <package/hpkg/PackageData.h>
28#include <package/hpkg/PackageEntry.h>
29#include <package/hpkg/PackageEntryAttribute.h>
30
31
32namespace BPackageKit {
33
34namespace BHPKG {
35
36namespace BPrivate {
37
38
39//#define TRACE(format...)	printf(format)
40#define TRACE(format...)	do {} while (false)
41
42
43// maximum TOC size we support reading
44static const size_t kMaxTOCSize					= 64 * 1024 * 1024;
45
46// maximum package attributes size we support reading
47static const size_t kMaxPackageAttributesSize	= 1 * 1024 * 1024;
48
49
50static status_t
51set_package_data_from_attribute_value(const BPackageAttributeValue& value,
52	BPackageData& data)
53{
54	if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE)
55		data.SetData(value.data.size, value.data.raw);
56	else
57		data.SetData(value.data.size, value.data.offset);
58	return B_OK;
59}
60
61
62// #pragma mark - AttributeAttributeHandler
63
64
65struct PackageReaderImpl::AttributeAttributeHandler : AttributeHandler {
66	AttributeAttributeHandler(BPackageEntry* entry, const char* name)
67		:
68		fEntry(entry),
69		fAttribute(name)
70	{
71	}
72
73	virtual status_t HandleAttribute(AttributeHandlerContext* context,
74		uint8 id, const AttributeValue& value, AttributeHandler** _handler)
75	{
76		switch (id) {
77			case B_HPKG_ATTRIBUTE_ID_DATA:
78				return set_package_data_from_attribute_value(value,
79					fAttribute.Data());
80
81			case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE_TYPE:
82				fAttribute.SetType(value.unsignedInt);
83				return B_OK;
84		}
85
86		return AttributeHandler::HandleAttribute(context, id, value, _handler);
87	}
88
89	virtual status_t Delete(AttributeHandlerContext* context)
90	{
91		status_t error = context->packageContentHandler->HandleEntryAttribute(
92			fEntry, &fAttribute);
93
94		delete this;
95		return error;
96	}
97
98private:
99	BPackageEntry*			fEntry;
100	BPackageEntryAttribute	fAttribute;
101};
102
103
104// #pragma mark - EntryAttributeHandler
105
106
107struct PackageReaderImpl::EntryAttributeHandler : AttributeHandler {
108	EntryAttributeHandler(AttributeHandlerContext* context,
109		BPackageEntry* parentEntry, const char* name)
110		:
111		fEntry(parentEntry, name),
112		fNotified(false)
113	{
114		_SetFileType(context, B_HPKG_DEFAULT_FILE_TYPE);
115	}
116
117	static status_t Create(AttributeHandlerContext* context,
118		BPackageEntry* parentEntry, const char* name,
119		AttributeHandler*& _handler)
120	{
121		// check name
122		if (name[0] == '\0' || strcmp(name, ".") == 0
123			|| strcmp(name, "..") == 0 || strchr(name, '/') != NULL) {
124			context->errorOutput->PrintError("Error: Invalid package: Invalid "
125				"entry name: \"%s\"\n", name);
126			return B_BAD_DATA;
127		}
128
129		// create handler
130		EntryAttributeHandler* handler = new(std::nothrow)
131			EntryAttributeHandler(context, parentEntry, name);
132		if (handler == NULL)
133			return B_NO_MEMORY;
134
135		_handler = handler;
136		return B_OK;
137	}
138
139	virtual status_t HandleAttribute(AttributeHandlerContext* context,
140		uint8 id, const AttributeValue& value, AttributeHandler** _handler)
141	{
142		switch (id) {
143			case B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY:
144			{
145				status_t error = _Notify(context);
146				if (error != B_OK)
147					return error;
148
149//TRACE("%*sentry \"%s\"\n", fLevel * 2, "", value.string);
150				if (_handler != NULL) {
151					return EntryAttributeHandler::Create(context, &fEntry,
152						value.string, *_handler);
153				}
154				return B_OK;
155			}
156
157			case B_HPKG_ATTRIBUTE_ID_FILE_TYPE:
158				return _SetFileType(context, value.unsignedInt);
159
160			case B_HPKG_ATTRIBUTE_ID_FILE_PERMISSIONS:
161				fEntry.SetPermissions(value.unsignedInt);
162				return B_OK;
163
164			case B_HPKG_ATTRIBUTE_ID_FILE_USER:
165			case B_HPKG_ATTRIBUTE_ID_FILE_GROUP:
166				// TODO:...
167				break;
168
169			case B_HPKG_ATTRIBUTE_ID_FILE_ATIME:
170				fEntry.SetAccessTime(value.unsignedInt);
171				return B_OK;
172
173			case B_HPKG_ATTRIBUTE_ID_FILE_MTIME:
174				fEntry.SetModifiedTime(value.unsignedInt);
175				return B_OK;
176
177			case B_HPKG_ATTRIBUTE_ID_FILE_CRTIME:
178				fEntry.SetCreationTime(value.unsignedInt);
179				return B_OK;
180
181			case B_HPKG_ATTRIBUTE_ID_FILE_ATIME_NANOS:
182				fEntry.SetAccessTimeNanos(value.unsignedInt);
183				return B_OK;
184
185			case B_HPKG_ATTRIBUTE_ID_FILE_MTIME_NANOS:
186				fEntry.SetModifiedTimeNanos(value.unsignedInt);
187				return B_OK;
188
189			case B_HPKG_ATTRIBUTE_ID_FILE_CRTIM_NANOS:
190				fEntry.SetCreationTimeNanos(value.unsignedInt);
191				return B_OK;
192
193			case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE:
194			{
195				status_t error = _Notify(context);
196				if (error != B_OK)
197					return error;
198
199				if (_handler != NULL) {
200					*_handler = new(std::nothrow) AttributeAttributeHandler(
201						&fEntry, value.string);
202					if (*_handler == NULL)
203						return B_NO_MEMORY;
204					return B_OK;
205				} else {
206					BPackageEntryAttribute attribute(value.string);
207					return context->packageContentHandler->HandleEntryAttribute(
208						&fEntry, &attribute);
209				}
210			}
211
212			case B_HPKG_ATTRIBUTE_ID_DATA:
213				return set_package_data_from_attribute_value(value,
214					fEntry.Data());
215
216			case B_HPKG_ATTRIBUTE_ID_SYMLINK_PATH:
217				fEntry.SetSymlinkPath(value.string);
218				return B_OK;
219		}
220
221		return AttributeHandler::HandleAttribute(context, id, value, _handler);
222	}
223
224	virtual status_t Delete(AttributeHandlerContext* context)
225	{
226		// notify if not done yet
227		status_t error = _Notify(context);
228
229		// notify done
230		if (error == B_OK)
231			error = context->packageContentHandler->HandleEntryDone(&fEntry);
232		else
233			context->packageContentHandler->HandleEntryDone(&fEntry);
234
235		delete this;
236		return error;
237	}
238
239private:
240	status_t _Notify(AttributeHandlerContext* context)
241	{
242		if (fNotified)
243			return B_OK;
244
245		fNotified = true;
246		return context->packageContentHandler->HandleEntry(&fEntry);
247	}
248
249	status_t _SetFileType(AttributeHandlerContext* context, uint64 fileType)
250	{
251		switch (fileType) {
252			case B_HPKG_FILE_TYPE_FILE:
253				fEntry.SetType(S_IFREG);
254				fEntry.SetPermissions(B_HPKG_DEFAULT_FILE_PERMISSIONS);
255				break;
256
257			case B_HPKG_FILE_TYPE_DIRECTORY:
258				fEntry.SetType(S_IFDIR);
259				fEntry.SetPermissions(B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS);
260				break;
261
262			case B_HPKG_FILE_TYPE_SYMLINK:
263				fEntry.SetType(S_IFLNK);
264				fEntry.SetPermissions(B_HPKG_DEFAULT_SYMLINK_PERMISSIONS);
265				break;
266
267			default:
268				context->errorOutput->PrintError("Error: Invalid file type for "
269					"package entry (%llu)\n", fileType);
270				return B_BAD_DATA;
271		}
272		return B_OK;
273	}
274
275private:
276	BPackageEntry	fEntry;
277	bool			fNotified;
278};
279
280
281// #pragma mark - RootAttributeHandler
282
283
284struct PackageReaderImpl::RootAttributeHandler : PackageAttributeHandler {
285	typedef PackageAttributeHandler inherited;
286
287	virtual status_t HandleAttribute(AttributeHandlerContext* context,
288		uint8 id, const AttributeValue& value, AttributeHandler** _handler)
289	{
290		if (id == B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY) {
291			if (_handler != NULL) {
292				return EntryAttributeHandler::Create(context, NULL,
293					value.string, *_handler);
294			}
295			return B_OK;
296		}
297
298		return inherited::HandleAttribute(context, id, value, _handler);
299	}
300};
301
302
303// #pragma mark - PackageReaderImpl
304
305
306PackageReaderImpl::PackageReaderImpl(BErrorOutput* errorOutput)
307	:
308	inherited("package", errorOutput),
309	fTOCSection("TOC")
310{
311}
312
313
314PackageReaderImpl::~PackageReaderImpl()
315{
316}
317
318
319status_t
320PackageReaderImpl::Init(const char* fileName, uint32 flags)
321{
322	// open file
323	int fd = open(fileName, O_RDONLY);
324	if (fd < 0) {
325		ErrorOutput()->PrintError("Error: Failed to open package file \"%s\": "
326			"%s\n", fileName, strerror(errno));
327		return errno;
328	}
329
330	return Init(fd, true, flags);
331}
332
333
334status_t
335PackageReaderImpl::Init(int fd, bool keepFD, uint32 flags)
336{
337	BFdIO* file = new(std::nothrow) BFdIO(fd, keepFD);
338	if (file == NULL) {
339		if (keepFD && fd >= 0)
340			close(fd);
341		return B_NO_MEMORY;
342	}
343
344	return Init(file, true, flags);
345}
346
347
348status_t
349PackageReaderImpl::Init(BPositionIO* file, bool keepFile, uint32 flags,
350	hpkg_header* _header)
351{
352	hpkg_header header;
353	status_t error = inherited::Init<hpkg_header, B_HPKG_MAGIC, B_HPKG_VERSION,
354		B_HPKG_MINOR_VERSION>(file, keepFile, header, flags);
355	if (error != B_OK)
356		return error;
357	fHeapSize = UncompressedHeapSize();
358
359	// init package attributes section
360	error = InitSection(fPackageAttributesSection, fHeapSize,
361		B_BENDIAN_TO_HOST_INT32(header.attributes_length),
362		kMaxPackageAttributesSize,
363		B_BENDIAN_TO_HOST_INT32(header.attributes_strings_length),
364		B_BENDIAN_TO_HOST_INT32(header.attributes_strings_count));
365	if (error != B_OK)
366		return error;
367
368	// init TOC section
369	error = InitSection(fTOCSection, fPackageAttributesSection.offset,
370		B_BENDIAN_TO_HOST_INT64(header.toc_length), kMaxTOCSize,
371		B_BENDIAN_TO_HOST_INT64(header.toc_strings_length),
372		B_BENDIAN_TO_HOST_INT64(header.toc_strings_count));
373	if (error != B_OK)
374		return error;
375
376	if (_header != NULL)
377		*_header = header;
378
379	return B_OK;
380}
381
382
383status_t
384PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler)
385{
386	status_t error = _PrepareSections();
387	if (error != B_OK)
388		return error;
389
390	AttributeHandlerContext context(ErrorOutput(), contentHandler,
391		B_HPKG_SECTION_PACKAGE_ATTRIBUTES,
392		MinorFormatVersion() > B_HPKG_MINOR_VERSION);
393	RootAttributeHandler rootAttributeHandler;
394
395	error = ParsePackageAttributesSection(&context, &rootAttributeHandler);
396
397	if (error == B_OK) {
398		context.section = B_HPKG_SECTION_PACKAGE_TOC;
399		error = _ParseTOC(&context, &rootAttributeHandler);
400	}
401
402	return error;
403}
404
405
406status_t
407PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler* contentHandler)
408{
409	status_t error = _PrepareSections();
410	if (error != B_OK)
411		return error;
412
413	AttributeHandlerContext context(ErrorOutput(), contentHandler,
414		B_HPKG_SECTION_PACKAGE_ATTRIBUTES,
415		MinorFormatVersion() > B_HPKG_MINOR_VERSION);
416	LowLevelAttributeHandler rootAttributeHandler;
417
418	error = ParsePackageAttributesSection(&context, &rootAttributeHandler);
419
420	if (error == B_OK) {
421		context.section = B_HPKG_SECTION_PACKAGE_TOC;
422		error = _ParseTOC(&context, &rootAttributeHandler);
423	}
424
425	return error;
426}
427
428
429status_t
430PackageReaderImpl::_PrepareSections()
431{
432	status_t error = PrepareSection(fTOCSection);
433	if (error != B_OK)
434		return error;
435
436	error = PrepareSection(fPackageAttributesSection);
437	if (error != B_OK)
438		return error;
439
440	return B_OK;
441}
442
443
444status_t
445PackageReaderImpl::_ParseTOC(AttributeHandlerContext* context,
446	AttributeHandler* rootAttributeHandler)
447{
448	// parse the TOC
449	fTOCSection.currentOffset = fTOCSection.stringsLength;
450	SetCurrentSection(&fTOCSection);
451
452	// init the attribute handler stack
453	rootAttributeHandler->SetLevel(0);
454	ClearAttributeHandlerStack();
455	PushAttributeHandler(rootAttributeHandler);
456
457	bool sectionHandled;
458	status_t error = ParseAttributeTree(context, sectionHandled);
459	if (error == B_OK && sectionHandled) {
460		if (fTOCSection.currentOffset < fTOCSection.uncompressedLength) {
461			ErrorOutput()->PrintError("Error: %llu excess byte(s) in TOC "
462				"section\n",
463				fTOCSection.uncompressedLength - fTOCSection.currentOffset);
464			error = B_BAD_DATA;
465		}
466	}
467
468	// clean up on error
469	if (error != B_OK) {
470		context->ErrorOccurred();
471		while (AttributeHandler* handler = PopAttributeHandler()) {
472			if (handler != rootAttributeHandler)
473				handler->Delete(context);
474		}
475		return error;
476	}
477
478	return B_OK;
479}
480
481
482status_t
483PackageReaderImpl::ReadAttributeValue(uint8 type, uint8 encoding,
484	AttributeValue& _value)
485{
486	switch (type) {
487		case B_HPKG_ATTRIBUTE_TYPE_RAW:
488		{
489			uint64 size;
490			status_t error = ReadUnsignedLEB128(size);
491			if (error != B_OK)
492				return error;
493
494			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
495				uint64 offset;
496				error = ReadUnsignedLEB128(offset);
497				if (error != B_OK)
498					return error;
499
500				if (offset > fHeapSize || size > fHeapSize - offset) {
501					ErrorOutput()->PrintError("Error: Invalid %s section: "
502						"invalid data reference\n", CurrentSection()->name);
503					return B_BAD_DATA;
504				}
505
506				_value.SetToData(size, offset);
507			} else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) {
508				if (size > B_HPKG_MAX_INLINE_DATA_SIZE) {
509					ErrorOutput()->PrintError("Error: Invalid %s section: "
510						"inline data too long\n", CurrentSection()->name);
511					return B_BAD_DATA;
512				}
513
514				const void* buffer;
515				error = _GetTOCBuffer(size, buffer);
516				if (error != B_OK)
517					return error;
518				_value.SetToData(size, buffer);
519			} else {
520				ErrorOutput()->PrintError("Error: Invalid %s section: invalid "
521					"raw encoding (%u)\n", CurrentSection()->name, encoding);
522				return B_BAD_DATA;
523			}
524
525			return B_OK;
526		}
527
528		default:
529			return inherited::ReadAttributeValue(type, encoding, _value);
530	}
531}
532
533
534status_t
535PackageReaderImpl::_GetTOCBuffer(size_t size, const void*& _buffer)
536{
537	if (size > fTOCSection.uncompressedLength - fTOCSection.currentOffset) {
538		ErrorOutput()->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n",
539			size);
540		return B_BAD_DATA;
541	}
542
543	_buffer = fTOCSection.data + fTOCSection.currentOffset;
544	fTOCSection.currentOffset += size;
545	return B_OK;
546}
547
548
549}	// namespace BPrivate
550
551}	// namespace BHPKG
552
553}	// namespace BPackageKit
554