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