xref: /haiku/src/kits/package/hpkg/PackageReaderImpl.cpp (revision 8e8f7748d39f8407894a5ab79f7b4f93bc4f4652)
1 /*
2  * Copyright 2009, 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 <package/hpkg/HPKGDefsPrivate.h>
24 
25 #include <package/hpkg/BufferDataOutput.h>
26 #include <package/hpkg/PackageData.h>
27 #include <package/hpkg/PackageEntry.h>
28 #include <package/hpkg/PackageEntryAttribute.h>
29 #include <ZlibDecompressor.h>
30 
31 
32 namespace BPackageKit {
33 
34 namespace BHPKG {
35 
36 namespace 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
44 static const size_t kMaxTOCSize					= 64 * 1024 * 1024;
45 
46 // maximum package attributes size we support reading
47 static const size_t kMaxPackageAttributesSize	= 1 * 1024 * 1024;
48 
49 
50 static status_t
51 set_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 
65 struct 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 
98 private:
99 	BPackageEntry*			fEntry;
100 	BPackageEntryAttribute	fAttribute;
101 };
102 
103 
104 // #pragma mark - EntryAttributeHandler
105 
106 
107 struct 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 
239 private:
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 
275 private:
276 	BPackageEntry	fEntry;
277 	bool			fNotified;
278 };
279 
280 
281 // #pragma mark - RootAttributeHandler
282 
283 
284 struct 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 
306 PackageReaderImpl::PackageReaderImpl(BErrorOutput* errorOutput)
307 	:
308 	inherited("package", errorOutput),
309 	fTOCSection("TOC")
310 {
311 }
312 
313 
314 PackageReaderImpl::~PackageReaderImpl()
315 {
316 }
317 
318 
319 status_t
320 PackageReaderImpl::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 
334 status_t
335 PackageReaderImpl::Init(int fd, bool keepFD, uint32 flags)
336 {
337 	hpkg_header header;
338 	status_t error = inherited::Init<hpkg_header, B_HPKG_MAGIC, B_HPKG_VERSION,
339 		B_HPKG_MINOR_VERSION>(fd, keepFD, header, flags);
340 	if (error != B_OK)
341 		return error;
342 	fHeapSize = UncompressedHeapSize();
343 
344 	// init package attributes section
345 	error = InitSection(fPackageAttributesSection, fHeapSize,
346 		B_BENDIAN_TO_HOST_INT32(header.attributes_length),
347 		kMaxPackageAttributesSize,
348 		B_BENDIAN_TO_HOST_INT32(header.attributes_strings_length),
349 		B_BENDIAN_TO_HOST_INT32(header.attributes_strings_count));
350 	if (error != B_OK)
351 		return error;
352 
353 	// init TOC section
354 	error = InitSection(fTOCSection, fPackageAttributesSection.offset,
355 		B_BENDIAN_TO_HOST_INT64(header.toc_length), kMaxTOCSize,
356 		B_BENDIAN_TO_HOST_INT64(header.toc_strings_length),
357 		B_BENDIAN_TO_HOST_INT64(header.toc_strings_count));
358 	if (error != B_OK)
359 		return error;
360 
361 	// prepare the sections for use
362 	error = PrepareSection(fTOCSection);
363 	if (error != B_OK)
364 		return error;
365 
366 	error = PrepareSection(fPackageAttributesSection);
367 	if (error != B_OK)
368 		return error;
369 
370 	return B_OK;
371 }
372 
373 
374 status_t
375 PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler)
376 {
377 	AttributeHandlerContext context(ErrorOutput(), contentHandler,
378 		B_HPKG_SECTION_PACKAGE_ATTRIBUTES,
379 		MinorFormatVersion() > B_HPKG_MINOR_VERSION);
380 	RootAttributeHandler rootAttributeHandler;
381 
382 	status_t error
383 		= ParsePackageAttributesSection(&context, &rootAttributeHandler);
384 
385 	if (error == B_OK) {
386 		context.section = B_HPKG_SECTION_PACKAGE_TOC;
387 		error = _ParseTOC(&context, &rootAttributeHandler);
388 	}
389 
390 	return error;
391 }
392 
393 
394 status_t
395 PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler* contentHandler)
396 {
397 	AttributeHandlerContext context(ErrorOutput(), contentHandler,
398 		B_HPKG_SECTION_PACKAGE_ATTRIBUTES,
399 		MinorFormatVersion() > B_HPKG_MINOR_VERSION);
400 	LowLevelAttributeHandler rootAttributeHandler;
401 
402 	status_t error
403 		= ParsePackageAttributesSection(&context, &rootAttributeHandler);
404 
405 	if (error == B_OK) {
406 		context.section = B_HPKG_SECTION_PACKAGE_TOC;
407 		error = _ParseTOC(&context, &rootAttributeHandler);
408 	}
409 
410 	return error;
411 }
412 
413 
414 status_t
415 PackageReaderImpl::_ParseTOC(AttributeHandlerContext* context,
416 	AttributeHandler* rootAttributeHandler)
417 {
418 	// parse the TOC
419 	fTOCSection.currentOffset = fTOCSection.stringsLength;
420 	SetCurrentSection(&fTOCSection);
421 
422 	// init the attribute handler stack
423 	rootAttributeHandler->SetLevel(0);
424 	ClearAttributeHandlerStack();
425 	PushAttributeHandler(rootAttributeHandler);
426 
427 	bool sectionHandled;
428 	status_t error = ParseAttributeTree(context, sectionHandled);
429 	if (error == B_OK && sectionHandled) {
430 		if (fTOCSection.currentOffset < fTOCSection.uncompressedLength) {
431 			ErrorOutput()->PrintError("Error: %llu excess byte(s) in TOC "
432 				"section\n",
433 				fTOCSection.uncompressedLength - fTOCSection.currentOffset);
434 			error = B_BAD_DATA;
435 		}
436 	}
437 
438 	// clean up on error
439 	if (error != B_OK) {
440 		context->ErrorOccurred();
441 		while (AttributeHandler* handler = PopAttributeHandler()) {
442 			if (handler != rootAttributeHandler)
443 				handler->Delete(context);
444 		}
445 		return error;
446 	}
447 
448 	return B_OK;
449 }
450 
451 
452 status_t
453 PackageReaderImpl::ReadAttributeValue(uint8 type, uint8 encoding,
454 	AttributeValue& _value)
455 {
456 	switch (type) {
457 		case B_HPKG_ATTRIBUTE_TYPE_RAW:
458 		{
459 			uint64 size;
460 			status_t error = ReadUnsignedLEB128(size);
461 			if (error != B_OK)
462 				return error;
463 
464 			if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
465 				uint64 offset;
466 				error = ReadUnsignedLEB128(offset);
467 				if (error != B_OK)
468 					return error;
469 
470 				if (offset > fHeapSize || size > fHeapSize - offset) {
471 					ErrorOutput()->PrintError("Error: Invalid %s section: "
472 						"invalid data reference\n", CurrentSection()->name);
473 					return B_BAD_DATA;
474 				}
475 
476 				_value.SetToData(size, offset);
477 			} else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) {
478 				if (size > B_HPKG_MAX_INLINE_DATA_SIZE) {
479 					ErrorOutput()->PrintError("Error: Invalid %s section: "
480 						"inline data too long\n", CurrentSection()->name);
481 					return B_BAD_DATA;
482 				}
483 
484 				const void* buffer;
485 				error = _GetTOCBuffer(size, buffer);
486 				if (error != B_OK)
487 					return error;
488 				_value.SetToData(size, buffer);
489 			} else {
490 				ErrorOutput()->PrintError("Error: Invalid %s section: invalid "
491 					"raw encoding (%u)\n", CurrentSection()->name, encoding);
492 				return B_BAD_DATA;
493 			}
494 
495 			return B_OK;
496 		}
497 
498 		default:
499 			return inherited::ReadAttributeValue(type, encoding, _value);
500 	}
501 }
502 
503 
504 status_t
505 PackageReaderImpl::_GetTOCBuffer(size_t size, const void*& _buffer)
506 {
507 	if (size > fTOCSection.uncompressedLength - fTOCSection.currentOffset) {
508 		ErrorOutput()->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n",
509 			size);
510 		return B_BAD_DATA;
511 	}
512 
513 	_buffer = fTOCSection.data + fTOCSection.currentOffset;
514 	fTOCSection.currentOffset += size;
515 	return B_OK;
516 }
517 
518 
519 }	// namespace BPrivate
520 
521 }	// namespace BHPKG
522 
523 }	// namespace BPackageKit
524