BPicture: Fix archive constructor.
[haiku.git] / src / kits / package / hpkg / PackageReaderImpl.cpp
blobac04ccd53c47b56e21adb6ba9da3d339a9d8e30d
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 */
8 #include <package/hpkg/PackageReaderImpl.h>
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>
18 #include <algorithm>
19 #include <new>
21 #include <ByteOrder.h>
23 #include <FdIO.h>
25 #include <package/hpkg/HPKGDefsPrivate.h>
27 #include <package/hpkg/PackageData.h>
28 #include <package/hpkg/PackageEntry.h>
29 #include <package/hpkg/PackageEntryAttribute.h>
32 namespace BPackageKit {
34 namespace BHPKG {
36 namespace BPrivate {
39 //#define TRACE(format...) printf(format)
40 #define TRACE(format...) do {} while (false)
43 // maximum TOC size we support reading
44 static const size_t kMaxTOCSize = 64 * 1024 * 1024;
46 // maximum package attributes size we support reading
47 static const size_t kMaxPackageAttributesSize = 1 * 1024 * 1024;
50 static status_t
51 set_package_data_from_attribute_value(const BPackageAttributeValue& value,
52 BPackageData& data)
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;
62 // #pragma mark - AttributeAttributeHandler
65 struct PackageReaderImpl::AttributeAttributeHandler : AttributeHandler {
66 AttributeAttributeHandler(BPackageEntry* entry, const char* name)
68 fEntry(entry),
69 fAttribute(name)
73 virtual status_t HandleAttribute(AttributeHandlerContext* context,
74 uint8 id, const AttributeValue& value, AttributeHandler** _handler)
76 switch (id) {
77 case B_HPKG_ATTRIBUTE_ID_DATA:
78 return set_package_data_from_attribute_value(value,
79 fAttribute.Data());
81 case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE_TYPE:
82 fAttribute.SetType(value.unsignedInt);
83 return B_OK;
86 return AttributeHandler::HandleAttribute(context, id, value, _handler);
89 virtual status_t Delete(AttributeHandlerContext* context)
91 status_t error = context->packageContentHandler->HandleEntryAttribute(
92 fEntry, &fAttribute);
94 delete this;
95 return error;
98 private:
99 BPackageEntry* fEntry;
100 BPackageEntryAttribute fAttribute;
104 // #pragma mark - EntryAttributeHandler
107 struct PackageReaderImpl::EntryAttributeHandler : AttributeHandler {
108 EntryAttributeHandler(AttributeHandlerContext* context,
109 BPackageEntry* parentEntry, const char* name)
111 fEntry(parentEntry, name),
112 fNotified(false)
114 _SetFileType(context, B_HPKG_DEFAULT_FILE_TYPE);
117 static status_t Create(AttributeHandlerContext* context,
118 BPackageEntry* parentEntry, const char* name,
119 AttributeHandler*& _handler)
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;
129 // create handler
130 EntryAttributeHandler* handler = new(std::nothrow)
131 EntryAttributeHandler(context, parentEntry, name);
132 if (handler == NULL)
133 return B_NO_MEMORY;
135 _handler = handler;
136 return B_OK;
139 virtual status_t HandleAttribute(AttributeHandlerContext* context,
140 uint8 id, const AttributeValue& value, AttributeHandler** _handler)
142 switch (id) {
143 case B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY:
145 status_t error = _Notify(context);
146 if (error != B_OK)
147 return error;
149 //TRACE("%*sentry \"%s\"\n", fLevel * 2, "", value.string);
150 if (_handler != NULL) {
151 return EntryAttributeHandler::Create(context, &fEntry,
152 value.string, *_handler);
154 return B_OK;
157 case B_HPKG_ATTRIBUTE_ID_FILE_TYPE:
158 return _SetFileType(context, value.unsignedInt);
160 case B_HPKG_ATTRIBUTE_ID_FILE_PERMISSIONS:
161 fEntry.SetPermissions(value.unsignedInt);
162 return B_OK;
164 case B_HPKG_ATTRIBUTE_ID_FILE_USER:
165 case B_HPKG_ATTRIBUTE_ID_FILE_GROUP:
166 // TODO:...
167 break;
169 case B_HPKG_ATTRIBUTE_ID_FILE_ATIME:
170 fEntry.SetAccessTime(value.unsignedInt);
171 return B_OK;
173 case B_HPKG_ATTRIBUTE_ID_FILE_MTIME:
174 fEntry.SetModifiedTime(value.unsignedInt);
175 return B_OK;
177 case B_HPKG_ATTRIBUTE_ID_FILE_CRTIME:
178 fEntry.SetCreationTime(value.unsignedInt);
179 return B_OK;
181 case B_HPKG_ATTRIBUTE_ID_FILE_ATIME_NANOS:
182 fEntry.SetAccessTimeNanos(value.unsignedInt);
183 return B_OK;
185 case B_HPKG_ATTRIBUTE_ID_FILE_MTIME_NANOS:
186 fEntry.SetModifiedTimeNanos(value.unsignedInt);
187 return B_OK;
189 case B_HPKG_ATTRIBUTE_ID_FILE_CRTIM_NANOS:
190 fEntry.SetCreationTimeNanos(value.unsignedInt);
191 return B_OK;
193 case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE:
195 status_t error = _Notify(context);
196 if (error != B_OK)
197 return error;
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);
212 case B_HPKG_ATTRIBUTE_ID_DATA:
213 return set_package_data_from_attribute_value(value,
214 fEntry.Data());
216 case B_HPKG_ATTRIBUTE_ID_SYMLINK_PATH:
217 fEntry.SetSymlinkPath(value.string);
218 return B_OK;
221 return AttributeHandler::HandleAttribute(context, id, value, _handler);
224 virtual status_t Delete(AttributeHandlerContext* context)
226 // notify if not done yet
227 status_t error = _Notify(context);
229 // notify done
230 if (error == B_OK)
231 error = context->packageContentHandler->HandleEntryDone(&fEntry);
232 else
233 context->packageContentHandler->HandleEntryDone(&fEntry);
235 delete this;
236 return error;
239 private:
240 status_t _Notify(AttributeHandlerContext* context)
242 if (fNotified)
243 return B_OK;
245 fNotified = true;
246 return context->packageContentHandler->HandleEntry(&fEntry);
249 status_t _SetFileType(AttributeHandlerContext* context, uint64 fileType)
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;
257 case B_HPKG_FILE_TYPE_DIRECTORY:
258 fEntry.SetType(S_IFDIR);
259 fEntry.SetPermissions(B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS);
260 break;
262 case B_HPKG_FILE_TYPE_SYMLINK:
263 fEntry.SetType(S_IFLNK);
264 fEntry.SetPermissions(B_HPKG_DEFAULT_SYMLINK_PERMISSIONS);
265 break;
267 default:
268 context->errorOutput->PrintError("Error: Invalid file type for "
269 "package entry (%llu)\n", fileType);
270 return B_BAD_DATA;
272 return B_OK;
275 private:
276 BPackageEntry fEntry;
277 bool fNotified;
281 // #pragma mark - RootAttributeHandler
284 struct PackageReaderImpl::RootAttributeHandler : PackageAttributeHandler {
285 typedef PackageAttributeHandler inherited;
287 virtual status_t HandleAttribute(AttributeHandlerContext* context,
288 uint8 id, const AttributeValue& value, AttributeHandler** _handler)
290 if (id == B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY) {
291 if (_handler != NULL) {
292 return EntryAttributeHandler::Create(context, NULL,
293 value.string, *_handler);
295 return B_OK;
298 return inherited::HandleAttribute(context, id, value, _handler);
303 // #pragma mark - PackageReaderImpl
306 PackageReaderImpl::PackageReaderImpl(BErrorOutput* errorOutput)
308 inherited("package", errorOutput),
309 fTOCSection("TOC")
314 PackageReaderImpl::~PackageReaderImpl()
319 status_t
320 PackageReaderImpl::Init(const char* fileName, uint32 flags)
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;
330 return Init(fd, true, flags);
334 status_t
335 PackageReaderImpl::Init(int fd, bool keepFD, uint32 flags)
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;
344 return Init(file, true, flags);
348 status_t
349 PackageReaderImpl::Init(BPositionIO* file, bool keepFile, uint32 flags,
350 hpkg_header* _header)
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();
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;
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;
376 if (_header != NULL)
377 *_header = header;
379 return B_OK;
383 status_t
384 PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler)
386 status_t error = _PrepareSections();
387 if (error != B_OK)
388 return error;
390 AttributeHandlerContext context(ErrorOutput(), contentHandler,
391 B_HPKG_SECTION_PACKAGE_ATTRIBUTES,
392 MinorFormatVersion() > B_HPKG_MINOR_VERSION);
393 RootAttributeHandler rootAttributeHandler;
395 error = ParsePackageAttributesSection(&context, &rootAttributeHandler);
397 if (error == B_OK) {
398 context.section = B_HPKG_SECTION_PACKAGE_TOC;
399 error = _ParseTOC(&context, &rootAttributeHandler);
402 return error;
406 status_t
407 PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler* contentHandler)
409 status_t error = _PrepareSections();
410 if (error != B_OK)
411 return error;
413 AttributeHandlerContext context(ErrorOutput(), contentHandler,
414 B_HPKG_SECTION_PACKAGE_ATTRIBUTES,
415 MinorFormatVersion() > B_HPKG_MINOR_VERSION);
416 LowLevelAttributeHandler rootAttributeHandler;
418 error = ParsePackageAttributesSection(&context, &rootAttributeHandler);
420 if (error == B_OK) {
421 context.section = B_HPKG_SECTION_PACKAGE_TOC;
422 error = _ParseTOC(&context, &rootAttributeHandler);
425 return error;
429 status_t
430 PackageReaderImpl::_PrepareSections()
432 status_t error = PrepareSection(fTOCSection);
433 if (error != B_OK)
434 return error;
436 error = PrepareSection(fPackageAttributesSection);
437 if (error != B_OK)
438 return error;
440 return B_OK;
444 status_t
445 PackageReaderImpl::_ParseTOC(AttributeHandlerContext* context,
446 AttributeHandler* rootAttributeHandler)
448 // parse the TOC
449 fTOCSection.currentOffset = fTOCSection.stringsLength;
450 SetCurrentSection(&fTOCSection);
452 // init the attribute handler stack
453 rootAttributeHandler->SetLevel(0);
454 ClearAttributeHandlerStack();
455 PushAttributeHandler(rootAttributeHandler);
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;
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);
475 return error;
478 return B_OK;
482 status_t
483 PackageReaderImpl::ReadAttributeValue(uint8 type, uint8 encoding,
484 AttributeValue& _value)
486 switch (type) {
487 case B_HPKG_ATTRIBUTE_TYPE_RAW:
489 uint64 size;
490 status_t error = ReadUnsignedLEB128(size);
491 if (error != B_OK)
492 return error;
494 if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
495 uint64 offset;
496 error = ReadUnsignedLEB128(offset);
497 if (error != B_OK)
498 return error;
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;
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;
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;
525 return B_OK;
528 default:
529 return inherited::ReadAttributeValue(type, encoding, _value);
534 status_t
535 PackageReaderImpl::_GetTOCBuffer(size_t size, const void*& _buffer)
537 if (size > fTOCSection.uncompressedLength - fTOCSection.currentOffset) {
538 ErrorOutput()->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n",
539 size);
540 return B_BAD_DATA;
543 _buffer = fTOCSection.data + fTOCSection.currentOffset;
544 fTOCSection.currentOffset += size;
545 return B_OK;
549 } // namespace BPrivate
551 } // namespace BHPKG
553 } // namespace BPackageKit