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.
8 #include <package/hpkg/PackageReaderImpl.h>
21 #include <ByteOrder.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
{
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;
51 set_package_data_from_attribute_value(const BPackageAttributeValue
& value
,
54 if (value
.encoding
== B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE
)
55 data
.SetData(value
.data
.size
, value
.data
.raw
);
57 data
.SetData(value
.data
.size
, value
.data
.offset
);
62 // #pragma mark - AttributeAttributeHandler
65 struct PackageReaderImpl::AttributeAttributeHandler
: AttributeHandler
{
66 AttributeAttributeHandler(BPackageEntry
* entry
, const char* name
)
73 virtual status_t
HandleAttribute(AttributeHandlerContext
* context
,
74 uint8 id
, const AttributeValue
& value
, AttributeHandler
** _handler
)
77 case B_HPKG_ATTRIBUTE_ID_DATA
:
78 return set_package_data_from_attribute_value(value
,
81 case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE_TYPE
:
82 fAttribute
.SetType(value
.unsignedInt
);
86 return AttributeHandler::HandleAttribute(context
, id
, value
, _handler
);
89 virtual status_t
Delete(AttributeHandlerContext
* context
)
91 status_t error
= context
->packageContentHandler
->HandleEntryAttribute(
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
),
114 _SetFileType(context
, B_HPKG_DEFAULT_FILE_TYPE
);
117 static status_t
Create(AttributeHandlerContext
* context
,
118 BPackageEntry
* parentEntry
, const char* name
,
119 AttributeHandler
*& _handler
)
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
);
130 EntryAttributeHandler
* handler
= new(std::nothrow
)
131 EntryAttributeHandler(context
, parentEntry
, name
);
139 virtual status_t
HandleAttribute(AttributeHandlerContext
* context
,
140 uint8 id
, const AttributeValue
& value
, AttributeHandler
** _handler
)
143 case B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY
:
145 status_t error
= _Notify(context
);
149 //TRACE("%*sentry \"%s\"\n", fLevel * 2, "", value.string);
150 if (_handler
!= NULL
) {
151 return EntryAttributeHandler::Create(context
, &fEntry
,
152 value
.string
, *_handler
);
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
);
164 case B_HPKG_ATTRIBUTE_ID_FILE_USER
:
165 case B_HPKG_ATTRIBUTE_ID_FILE_GROUP
:
169 case B_HPKG_ATTRIBUTE_ID_FILE_ATIME
:
170 fEntry
.SetAccessTime(value
.unsignedInt
);
173 case B_HPKG_ATTRIBUTE_ID_FILE_MTIME
:
174 fEntry
.SetModifiedTime(value
.unsignedInt
);
177 case B_HPKG_ATTRIBUTE_ID_FILE_CRTIME
:
178 fEntry
.SetCreationTime(value
.unsignedInt
);
181 case B_HPKG_ATTRIBUTE_ID_FILE_ATIME_NANOS
:
182 fEntry
.SetAccessTimeNanos(value
.unsignedInt
);
185 case B_HPKG_ATTRIBUTE_ID_FILE_MTIME_NANOS
:
186 fEntry
.SetModifiedTimeNanos(value
.unsignedInt
);
189 case B_HPKG_ATTRIBUTE_ID_FILE_CRTIM_NANOS
:
190 fEntry
.SetCreationTimeNanos(value
.unsignedInt
);
193 case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE
:
195 status_t error
= _Notify(context
);
199 if (_handler
!= NULL
) {
200 *_handler
= new(std::nothrow
) AttributeAttributeHandler(
201 &fEntry
, value
.string
);
202 if (*_handler
== NULL
)
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
,
216 case B_HPKG_ATTRIBUTE_ID_SYMLINK_PATH
:
217 fEntry
.SetSymlinkPath(value
.string
);
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
);
231 error
= context
->packageContentHandler
->HandleEntryDone(&fEntry
);
233 context
->packageContentHandler
->HandleEntryDone(&fEntry
);
240 status_t
_Notify(AttributeHandlerContext
* context
)
246 return context
->packageContentHandler
->HandleEntry(&fEntry
);
249 status_t
_SetFileType(AttributeHandlerContext
* context
, uint64 fileType
)
252 case B_HPKG_FILE_TYPE_FILE
:
253 fEntry
.SetType(S_IFREG
);
254 fEntry
.SetPermissions(B_HPKG_DEFAULT_FILE_PERMISSIONS
);
257 case B_HPKG_FILE_TYPE_DIRECTORY
:
258 fEntry
.SetType(S_IFDIR
);
259 fEntry
.SetPermissions(B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS
);
262 case B_HPKG_FILE_TYPE_SYMLINK
:
263 fEntry
.SetType(S_IFLNK
);
264 fEntry
.SetPermissions(B_HPKG_DEFAULT_SYMLINK_PERMISSIONS
);
268 context
->errorOutput
->PrintError("Error: Invalid file type for "
269 "package entry (%llu)\n", fileType
);
276 BPackageEntry fEntry
;
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
);
298 return inherited::HandleAttribute(context
, id
, value
, _handler
);
303 // #pragma mark - PackageReaderImpl
306 PackageReaderImpl::PackageReaderImpl(BErrorOutput
* errorOutput
)
308 inherited("package", errorOutput
),
314 PackageReaderImpl::~PackageReaderImpl()
320 PackageReaderImpl::Init(const char* fileName
, uint32 flags
)
323 int fd
= open(fileName
, O_RDONLY
);
325 ErrorOutput()->PrintError("Error: Failed to open package file \"%s\": "
326 "%s\n", fileName
, strerror(errno
));
330 return Init(fd
, true, flags
);
335 PackageReaderImpl::Init(int fd
, bool keepFD
, uint32 flags
)
337 BFdIO
* file
= new(std::nothrow
) BFdIO(fd
, keepFD
);
339 if (keepFD
&& fd
>= 0)
344 return Init(file
, true, flags
);
349 PackageReaderImpl::Init(BPositionIO
* file
, bool keepFile
, uint32 flags
,
350 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
);
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
));
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
));
384 PackageReaderImpl::ParseContent(BPackageContentHandler
* contentHandler
)
386 status_t error
= _PrepareSections();
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
);
398 context
.section
= B_HPKG_SECTION_PACKAGE_TOC
;
399 error
= _ParseTOC(&context
, &rootAttributeHandler
);
407 PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler
* contentHandler
)
409 status_t error
= _PrepareSections();
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
);
421 context
.section
= B_HPKG_SECTION_PACKAGE_TOC
;
422 error
= _ParseTOC(&context
, &rootAttributeHandler
);
430 PackageReaderImpl::_PrepareSections()
432 status_t error
= PrepareSection(fTOCSection
);
436 error
= PrepareSection(fPackageAttributesSection
);
445 PackageReaderImpl::_ParseTOC(AttributeHandlerContext
* context
,
446 AttributeHandler
* rootAttributeHandler
)
449 fTOCSection
.currentOffset
= fTOCSection
.stringsLength
;
450 SetCurrentSection(&fTOCSection
);
452 // init the attribute handler stack
453 rootAttributeHandler
->SetLevel(0);
454 ClearAttributeHandlerStack();
455 PushAttributeHandler(rootAttributeHandler
);
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 "
463 fTOCSection
.uncompressedLength
- fTOCSection
.currentOffset
);
470 context
->ErrorOccurred();
471 while (AttributeHandler
* handler
= PopAttributeHandler()) {
472 if (handler
!= rootAttributeHandler
)
473 handler
->Delete(context
);
483 PackageReaderImpl::ReadAttributeValue(uint8 type
, uint8 encoding
,
484 AttributeValue
& _value
)
487 case B_HPKG_ATTRIBUTE_TYPE_RAW
:
490 status_t error
= ReadUnsignedLEB128(size
);
494 if (encoding
== B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP
) {
496 error
= ReadUnsignedLEB128(offset
);
500 if (offset
> fHeapSize
|| size
> fHeapSize
- offset
) {
501 ErrorOutput()->PrintError("Error: Invalid %s section: "
502 "invalid data reference\n", CurrentSection()->name
);
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
);
515 error
= _GetTOCBuffer(size
, buffer
);
518 _value
.SetToData(size
, buffer
);
520 ErrorOutput()->PrintError("Error: Invalid %s section: invalid "
521 "raw encoding (%u)\n", CurrentSection()->name
, encoding
);
529 return inherited::ReadAttributeValue(type
, encoding
, _value
);
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",
543 _buffer
= fTOCSection
.data
+ fTOCSection
.currentOffset
;
544 fTOCSection
.currentOffset
+= size
;
549 } // namespace BPrivate
553 } // namespace BPackageKit