xref: /haiku/src/kits/package/hpkg/PackageReaderImpl.cpp (revision 22440f4105cafc95cc1d49f9bc65bb395c527d86)
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 
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 	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 
348 status_t
349 PackageReaderImpl::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 
383 status_t
384 PackageReaderImpl::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 
406 status_t
407 PackageReaderImpl::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 
429 status_t
430 PackageReaderImpl::_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 
444 status_t
445 PackageReaderImpl::_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 
482 status_t
483 PackageReaderImpl::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 
534 status_t
535 PackageReaderImpl::_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