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/v1/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/v1/HPKGDefsPrivate.h> 24 25 #include <package/hpkg/DataOutput.h> 26 #include <package/hpkg/ErrorOutput.h> 27 #include <package/hpkg/v1/PackageData.h> 28 #include <package/hpkg/v1/PackageEntry.h> 29 #include <package/hpkg/v1/PackageEntryAttribute.h> 30 #include <package/hpkg/ZlibDecompressor.h> 31 32 33 namespace BPackageKit { 34 35 namespace BHPKG { 36 37 namespace V1 { 38 39 namespace BPrivate { 40 41 42 //#define TRACE(format...) printf(format) 43 #define TRACE(format...) do {} while (false) 44 45 46 // maximum TOC size we support reading 47 static const size_t kMaxTOCSize = 64 * 1024 * 1024; 48 49 // maximum package attributes size we support reading 50 static const size_t kMaxPackageAttributesSize = 1 * 1024 * 1024; 51 52 53 // #pragma mark - DataAttributeHandler 54 55 56 struct PackageReaderImpl::DataAttributeHandler : AttributeHandler { 57 DataAttributeHandler(BPackageData* data) 58 : 59 fData(data) 60 { 61 } 62 63 static status_t InitData(AttributeHandlerContext* context, 64 BPackageData* data, const AttributeValue& value) 65 { 66 if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) 67 data->SetData(value.data.size, value.data.raw); 68 else 69 data->SetData(value.data.size, value.data.offset); 70 71 data->SetUncompressedSize(value.data.size); 72 73 return B_OK; 74 } 75 76 static status_t Create(AttributeHandlerContext* context, 77 BPackageData* data, const AttributeValue& value, 78 AttributeHandler*& _handler) 79 { 80 DataAttributeHandler* handler = new(std::nothrow) DataAttributeHandler( 81 data); 82 if (handler == NULL) 83 return B_NO_MEMORY; 84 85 InitData(context, data, value); 86 87 _handler = handler; 88 return B_OK; 89 } 90 91 virtual status_t HandleAttribute(AttributeHandlerContext* context, 92 uint8 id, const AttributeValue& value, AttributeHandler** _handler) 93 { 94 switch (id) { 95 case B_HPKG_ATTRIBUTE_ID_DATA_SIZE: 96 fData->SetUncompressedSize(value.unsignedInt); 97 return B_OK; 98 99 case B_HPKG_ATTRIBUTE_ID_DATA_COMPRESSION: 100 { 101 switch (value.unsignedInt) { 102 case B_HPKG_COMPRESSION_NONE: 103 case B_HPKG_COMPRESSION_ZLIB: 104 break; 105 default: 106 context->errorOutput->PrintError("Error: Invalid " 107 "compression type for data (%llu)\n", 108 value.unsignedInt); 109 return B_BAD_DATA; 110 } 111 112 fData->SetCompression(value.unsignedInt); 113 return B_OK; 114 } 115 116 case B_HPKG_ATTRIBUTE_ID_DATA_CHUNK_SIZE: 117 fData->SetChunkSize(value.unsignedInt); 118 return B_OK; 119 } 120 121 return AttributeHandler::HandleAttribute(context, id, value, _handler); 122 } 123 124 private: 125 BPackageData* fData; 126 }; 127 128 129 // #pragma mark - AttributeAttributeHandler 130 131 132 struct PackageReaderImpl::AttributeAttributeHandler : AttributeHandler { 133 AttributeAttributeHandler(BPackageEntry* entry, const char* name) 134 : 135 fEntry(entry), 136 fAttribute(name) 137 { 138 } 139 140 virtual status_t HandleAttribute(AttributeHandlerContext* context, 141 uint8 id, const AttributeValue& value, AttributeHandler** _handler) 142 { 143 switch (id) { 144 case B_HPKG_ATTRIBUTE_ID_DATA: 145 if (_handler != NULL) { 146 return DataAttributeHandler::Create(context, 147 &fAttribute.Data(), value, *_handler); 148 } 149 return DataAttributeHandler::InitData(context, 150 &fAttribute.Data(), value); 151 152 case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE_TYPE: 153 fAttribute.SetType(value.unsignedInt); 154 return B_OK; 155 } 156 157 return AttributeHandler::HandleAttribute(context, id, value, _handler); 158 } 159 160 virtual status_t Delete(AttributeHandlerContext* context) 161 { 162 status_t error = context->packageContentHandler->HandleEntryAttribute( 163 fEntry, &fAttribute); 164 165 delete this; 166 return error; 167 } 168 169 private: 170 BPackageEntry* fEntry; 171 BPackageEntryAttribute fAttribute; 172 }; 173 174 175 // #pragma mark - EntryAttributeHandler 176 177 178 struct PackageReaderImpl::EntryAttributeHandler : AttributeHandler { 179 EntryAttributeHandler(AttributeHandlerContext* context, 180 BPackageEntry* parentEntry, const char* name) 181 : 182 fEntry(parentEntry, name), 183 fNotified(false) 184 { 185 _SetFileType(context, B_HPKG_DEFAULT_FILE_TYPE); 186 } 187 188 static status_t Create(AttributeHandlerContext* context, 189 BPackageEntry* parentEntry, const char* name, 190 AttributeHandler*& _handler) 191 { 192 // check name 193 if (name[0] == '\0' || strcmp(name, ".") == 0 194 || strcmp(name, "..") == 0 || strchr(name, '/') != NULL) { 195 context->errorOutput->PrintError("Error: Invalid package: Invalid " 196 "entry name: \"%s\"\n", name); 197 return B_BAD_DATA; 198 } 199 200 // create handler 201 EntryAttributeHandler* handler = new(std::nothrow) 202 EntryAttributeHandler(context, parentEntry, name); 203 if (handler == NULL) 204 return B_NO_MEMORY; 205 206 _handler = handler; 207 return B_OK; 208 } 209 210 virtual status_t HandleAttribute(AttributeHandlerContext* context, 211 uint8 id, const AttributeValue& value, AttributeHandler** _handler) 212 { 213 switch (id) { 214 case B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY: 215 { 216 status_t error = _Notify(context); 217 if (error != B_OK) 218 return error; 219 220 //TRACE("%*sentry \"%s\"\n", fLevel * 2, "", value.string); 221 if (_handler != NULL) { 222 return EntryAttributeHandler::Create(context, &fEntry, 223 value.string, *_handler); 224 } 225 return B_OK; 226 } 227 228 case B_HPKG_ATTRIBUTE_ID_FILE_TYPE: 229 return _SetFileType(context, value.unsignedInt); 230 231 case B_HPKG_ATTRIBUTE_ID_FILE_PERMISSIONS: 232 fEntry.SetPermissions(value.unsignedInt); 233 return B_OK; 234 235 case B_HPKG_ATTRIBUTE_ID_FILE_USER: 236 case B_HPKG_ATTRIBUTE_ID_FILE_GROUP: 237 // TODO:... 238 break; 239 240 case B_HPKG_ATTRIBUTE_ID_FILE_ATIME: 241 fEntry.SetAccessTime(value.unsignedInt); 242 return B_OK; 243 244 case B_HPKG_ATTRIBUTE_ID_FILE_MTIME: 245 fEntry.SetModifiedTime(value.unsignedInt); 246 return B_OK; 247 248 case B_HPKG_ATTRIBUTE_ID_FILE_CRTIME: 249 fEntry.SetCreationTime(value.unsignedInt); 250 return B_OK; 251 252 case B_HPKG_ATTRIBUTE_ID_FILE_ATIME_NANOS: 253 fEntry.SetAccessTimeNanos(value.unsignedInt); 254 return B_OK; 255 256 case B_HPKG_ATTRIBUTE_ID_FILE_MTIME_NANOS: 257 fEntry.SetModifiedTimeNanos(value.unsignedInt); 258 return B_OK; 259 260 case B_HPKG_ATTRIBUTE_ID_FILE_CRTIM_NANOS: 261 fEntry.SetCreationTimeNanos(value.unsignedInt); 262 return B_OK; 263 264 case B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE: 265 { 266 status_t error = _Notify(context); 267 if (error != B_OK) 268 return error; 269 270 if (_handler != NULL) { 271 *_handler = new(std::nothrow) AttributeAttributeHandler( 272 &fEntry, value.string); 273 if (*_handler == NULL) 274 return B_NO_MEMORY; 275 return B_OK; 276 } else { 277 BPackageEntryAttribute attribute(value.string); 278 return context->packageContentHandler->HandleEntryAttribute( 279 &fEntry, &attribute); 280 } 281 } 282 283 case B_HPKG_ATTRIBUTE_ID_DATA: 284 if (_handler != NULL) { 285 return DataAttributeHandler::Create(context, &fEntry.Data(), 286 value, *_handler); 287 } 288 return DataAttributeHandler::InitData(context, &fEntry.Data(), 289 value); 290 291 case B_HPKG_ATTRIBUTE_ID_SYMLINK_PATH: 292 fEntry.SetSymlinkPath(value.string); 293 return B_OK; 294 } 295 296 return AttributeHandler::HandleAttribute(context, id, value, _handler); 297 } 298 299 virtual status_t Delete(AttributeHandlerContext* context) 300 { 301 // notify if not done yet 302 status_t error = _Notify(context); 303 304 // notify done 305 if (error == B_OK) 306 error = context->packageContentHandler->HandleEntryDone(&fEntry); 307 else 308 context->packageContentHandler->HandleEntryDone(&fEntry); 309 310 delete this; 311 return error; 312 } 313 314 private: 315 status_t _Notify(AttributeHandlerContext* context) 316 { 317 if (fNotified) 318 return B_OK; 319 320 fNotified = true; 321 return context->packageContentHandler->HandleEntry(&fEntry); 322 } 323 324 status_t _SetFileType(AttributeHandlerContext* context, uint64 fileType) 325 { 326 switch (fileType) { 327 case B_HPKG_FILE_TYPE_FILE: 328 fEntry.SetType(S_IFREG); 329 fEntry.SetPermissions(B_HPKG_DEFAULT_FILE_PERMISSIONS); 330 break; 331 332 case B_HPKG_FILE_TYPE_DIRECTORY: 333 fEntry.SetType(S_IFDIR); 334 fEntry.SetPermissions(B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS); 335 break; 336 337 case B_HPKG_FILE_TYPE_SYMLINK: 338 fEntry.SetType(S_IFLNK); 339 fEntry.SetPermissions(B_HPKG_DEFAULT_SYMLINK_PERMISSIONS); 340 break; 341 342 default: 343 context->errorOutput->PrintError("Error: Invalid file type for " 344 "package entry (%llu)\n", fileType); 345 return B_BAD_DATA; 346 } 347 return B_OK; 348 } 349 350 private: 351 BPackageEntry fEntry; 352 bool fNotified; 353 }; 354 355 356 // #pragma mark - RootAttributeHandler 357 358 359 struct PackageReaderImpl::RootAttributeHandler : PackageAttributeHandler { 360 typedef PackageAttributeHandler inherited; 361 362 virtual status_t HandleAttribute(AttributeHandlerContext* context, 363 uint8 id, const AttributeValue& value, AttributeHandler** _handler) 364 { 365 if (id == B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY) { 366 if (_handler != NULL) { 367 return EntryAttributeHandler::Create(context, NULL, 368 value.string, *_handler); 369 } 370 return B_OK; 371 } 372 373 return inherited::HandleAttribute(context, id, value, _handler); 374 } 375 }; 376 377 378 // #pragma mark - PackageReaderImpl 379 380 381 PackageReaderImpl::PackageReaderImpl(BErrorOutput* errorOutput) 382 : 383 inherited(errorOutput), 384 fTOCSection("TOC") 385 { 386 } 387 388 389 PackageReaderImpl::~PackageReaderImpl() 390 { 391 } 392 393 394 status_t 395 PackageReaderImpl::Init(const char* fileName) 396 { 397 // open file 398 int fd = open(fileName, O_RDONLY); 399 if (fd < 0) { 400 ErrorOutput()->PrintError("Error: Failed to open package file \"%s\": " 401 "%s\n", fileName, strerror(errno)); 402 return errno; 403 } 404 405 return Init(fd, true); 406 } 407 408 409 status_t 410 PackageReaderImpl::Init(int fd, bool keepFD) 411 { 412 status_t error = inherited::Init(fd, keepFD); 413 if (error != B_OK) 414 return error; 415 416 // stat it 417 struct stat st; 418 if (fstat(FD(), &st) < 0) { 419 ErrorOutput()->PrintError("Error: Failed to access package file: %s\n", 420 strerror(errno)); 421 return errno; 422 } 423 424 // read the header 425 hpkg_header header; 426 if ((error = ReadBuffer(0, &header, sizeof(header))) != B_OK) 427 return error; 428 429 // check the header 430 431 // magic 432 if (B_BENDIAN_TO_HOST_INT32(header.magic) != B_HPKG_MAGIC) { 433 ErrorOutput()->PrintError("Error: Invalid package file: Invalid " 434 "magic\n"); 435 return B_BAD_DATA; 436 } 437 438 // version 439 if (B_BENDIAN_TO_HOST_INT16(header.version) != B_HPKG_VERSION) { 440 ErrorOutput()->PrintError("Error: Invalid/unsupported package file " 441 "version (%d)\n", B_BENDIAN_TO_HOST_INT16(header.version)); 442 return B_MISMATCHED_VALUES; 443 } 444 445 // header size 446 fHeapOffset = B_BENDIAN_TO_HOST_INT16(header.header_size); 447 if ((size_t)fHeapOffset < sizeof(hpkg_header)) { 448 ErrorOutput()->PrintError("Error: Invalid package file: Invalid header " 449 "size (%llu)\n", fHeapOffset); 450 return B_BAD_DATA; 451 } 452 453 // total size 454 fTotalSize = B_BENDIAN_TO_HOST_INT64(header.total_size); 455 if (fTotalSize != (uint64)st.st_size) { 456 ErrorOutput()->PrintError("Error: Invalid package file: Total size in " 457 "header (%llu) doesn't agree with total file size (%lld)\n", 458 fTotalSize, st.st_size); 459 return B_BAD_DATA; 460 } 461 462 // package attributes length and compression 463 fPackageAttributesSection.compression 464 = B_BENDIAN_TO_HOST_INT32(header.attributes_compression); 465 fPackageAttributesSection.compressedLength 466 = B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed); 467 fPackageAttributesSection.uncompressedLength 468 = B_BENDIAN_TO_HOST_INT32(header.attributes_length_uncompressed); 469 fPackageAttributesSection.stringsLength 470 = B_BENDIAN_TO_HOST_INT32(header.attributes_strings_length); 471 fPackageAttributesSection.stringsCount 472 = B_BENDIAN_TO_HOST_INT32(header.attributes_strings_count); 473 474 if (const char* errorString = CheckCompression( 475 fPackageAttributesSection)) { 476 ErrorOutput()->PrintError("Error: Invalid package file: package " 477 "attributes section: %s\n", errorString); 478 return B_BAD_DATA; 479 } 480 481 // TOC length and compression 482 fTOCSection.compression = B_BENDIAN_TO_HOST_INT32(header.toc_compression); 483 fTOCSection.compressedLength 484 = B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed); 485 fTOCSection.uncompressedLength 486 = B_BENDIAN_TO_HOST_INT64(header.toc_length_uncompressed); 487 488 if (const char* errorString = CheckCompression(fTOCSection)) { 489 ErrorOutput()->PrintError("Error: Invalid package file: TOC section: " 490 "%s\n", errorString); 491 return B_BAD_DATA; 492 } 493 494 // TOC subsections 495 fTOCSection.stringsLength 496 = B_BENDIAN_TO_HOST_INT64(header.toc_strings_length); 497 fTOCSection.stringsCount 498 = B_BENDIAN_TO_HOST_INT64(header.toc_strings_count); 499 500 if (fTOCSection.stringsLength > fTOCSection.uncompressedLength 501 || fTOCSection.stringsCount > fTOCSection.stringsLength) { 502 ErrorOutput()->PrintError("Error: Invalid package file: Invalid TOC " 503 "subsections description\n"); 504 return B_BAD_DATA; 505 } 506 507 // check whether the sections fit together 508 if (fPackageAttributesSection.compressedLength > fTotalSize 509 || fTOCSection.compressedLength 510 > fTotalSize - fPackageAttributesSection.compressedLength 511 || fHeapOffset 512 > fTotalSize - fPackageAttributesSection.compressedLength 513 - fTOCSection.compressedLength) { 514 ErrorOutput()->PrintError("Error: Invalid package file: The sum of the " 515 "sections sizes is greater than the package size\n"); 516 return B_BAD_DATA; 517 } 518 519 fPackageAttributesSection.offset 520 = fTotalSize - fPackageAttributesSection.compressedLength; 521 fTOCSection.offset = fPackageAttributesSection.offset 522 - fTOCSection.compressedLength; 523 fHeapSize = fTOCSection.offset - fHeapOffset; 524 525 // TOC size sanity check 526 if (fTOCSection.uncompressedLength > kMaxTOCSize) { 527 ErrorOutput()->PrintError("Error: Package file TOC section size " 528 "is %llu bytes. This is beyond the reader's sanity limit\n", 529 fTOCSection.uncompressedLength); 530 return B_UNSUPPORTED; 531 } 532 533 // package attributes size sanity check 534 if (fPackageAttributesSection.uncompressedLength 535 > kMaxPackageAttributesSize) { 536 ErrorOutput()->PrintError( 537 "Error: Package file package attributes section size " 538 "is %llu bytes. This is beyond the reader's sanity limit\n", 539 fPackageAttributesSection.uncompressedLength); 540 return B_UNSUPPORTED; 541 } 542 543 // read in the complete TOC 544 fTOCSection.data 545 = new(std::nothrow) uint8[fTOCSection.uncompressedLength]; 546 if (fTOCSection.data == NULL) { 547 ErrorOutput()->PrintError("Error: Out of memory!\n"); 548 return B_NO_MEMORY; 549 } 550 error = ReadCompressedBuffer(fTOCSection); 551 if (error != B_OK) 552 return error; 553 554 // read in the complete package attributes section 555 fPackageAttributesSection.data 556 = new(std::nothrow) uint8[fPackageAttributesSection.uncompressedLength]; 557 if (fPackageAttributesSection.data == NULL) { 558 ErrorOutput()->PrintError("Error: Out of memory!\n"); 559 return B_NO_MEMORY; 560 } 561 error = ReadCompressedBuffer(fPackageAttributesSection); 562 if (error != B_OK) 563 return error; 564 565 // start parsing the TOC 566 fTOCSection.currentOffset = 0; 567 SetCurrentSection(&fTOCSection); 568 569 // strings 570 error = ParseStrings(); 571 if (error != B_OK) 572 return error; 573 574 // parse strings from package attributes section 575 fPackageAttributesSection.currentOffset = 0; 576 SetCurrentSection(&fPackageAttributesSection); 577 578 // strings 579 error = ParseStrings(); 580 if (error != B_OK) 581 return error; 582 583 SetCurrentSection(NULL); 584 585 return B_OK; 586 } 587 588 589 status_t 590 PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler) 591 { 592 AttributeHandlerContext context(ErrorOutput(), contentHandler, 593 B_HPKG_SECTION_PACKAGE_ATTRIBUTES); 594 RootAttributeHandler rootAttributeHandler; 595 596 status_t error 597 = ParsePackageAttributesSection(&context, &rootAttributeHandler); 598 599 if (error == B_OK) { 600 context.section = B_HPKG_SECTION_PACKAGE_TOC; 601 error = _ParseTOC(&context, &rootAttributeHandler); 602 } 603 604 return error; 605 } 606 607 608 status_t 609 PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler* contentHandler) 610 { 611 AttributeHandlerContext context(ErrorOutput(), contentHandler, 612 B_HPKG_SECTION_PACKAGE_ATTRIBUTES); 613 LowLevelAttributeHandler rootAttributeHandler; 614 615 status_t error 616 = ParsePackageAttributesSection(&context, &rootAttributeHandler); 617 618 if (error == B_OK) { 619 context.section = B_HPKG_SECTION_PACKAGE_TOC; 620 error = _ParseTOC(&context, &rootAttributeHandler); 621 } 622 623 return error; 624 } 625 626 627 status_t 628 PackageReaderImpl::_ParseTOC(AttributeHandlerContext* context, 629 AttributeHandler* rootAttributeHandler) 630 { 631 // parse the TOC 632 fTOCSection.currentOffset = fTOCSection.stringsLength; 633 SetCurrentSection(&fTOCSection); 634 635 // prepare attribute handler context 636 context->heapOffset = fHeapOffset; 637 context->heapSize = fHeapSize; 638 639 // init the attribute handler stack 640 rootAttributeHandler->SetLevel(0); 641 ClearAttributeHandlerStack(); 642 PushAttributeHandler(rootAttributeHandler); 643 644 bool sectionHandled; 645 status_t error = ParseAttributeTree(context, sectionHandled); 646 if (error == B_OK && sectionHandled) { 647 if (fTOCSection.currentOffset < fTOCSection.uncompressedLength) { 648 ErrorOutput()->PrintError("Error: %llu excess byte(s) in TOC " 649 "section\n", 650 fTOCSection.uncompressedLength - fTOCSection.currentOffset); 651 error = B_BAD_DATA; 652 } 653 } 654 655 // clean up on error 656 if (error != B_OK) { 657 context->ErrorOccurred(); 658 while (AttributeHandler* handler = PopAttributeHandler()) { 659 if (handler != rootAttributeHandler) 660 handler->Delete(context); 661 } 662 return error; 663 } 664 665 return B_OK; 666 } 667 668 669 status_t 670 PackageReaderImpl::ReadAttributeValue(uint8 type, uint8 encoding, 671 AttributeValue& _value) 672 { 673 switch (type) { 674 case B_HPKG_ATTRIBUTE_TYPE_RAW: 675 { 676 uint64 size; 677 status_t error = ReadUnsignedLEB128(size); 678 if (error != B_OK) 679 return error; 680 681 if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) { 682 uint64 offset; 683 error = ReadUnsignedLEB128(offset); 684 if (error != B_OK) 685 return error; 686 687 if (offset > fHeapSize || size > fHeapSize - offset) { 688 ErrorOutput()->PrintError("Error: Invalid %s section: " 689 "invalid data reference\n", CurrentSection()->name); 690 return B_BAD_DATA; 691 } 692 693 _value.SetToData(size, fHeapOffset + offset); 694 } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) { 695 if (size > B_HPKG_MAX_INLINE_DATA_SIZE) { 696 ErrorOutput()->PrintError("Error: Invalid %s section: " 697 "inline data too long\n", CurrentSection()->name); 698 return B_BAD_DATA; 699 } 700 701 const void* buffer; 702 error = _GetTOCBuffer(size, buffer); 703 if (error != B_OK) 704 return error; 705 _value.SetToData(size, buffer); 706 } else { 707 ErrorOutput()->PrintError("Error: Invalid %s section: invalid " 708 "raw encoding (%u)\n", CurrentSection()->name, encoding); 709 return B_BAD_DATA; 710 } 711 712 return B_OK; 713 } 714 715 default: 716 return inherited::ReadAttributeValue(type, encoding, _value); 717 } 718 } 719 720 721 status_t 722 PackageReaderImpl::_GetTOCBuffer(size_t size, const void*& _buffer) 723 { 724 if (size > fTOCSection.uncompressedLength - fTOCSection.currentOffset) { 725 ErrorOutput()->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n", 726 size); 727 return B_BAD_DATA; 728 } 729 730 _buffer = fTOCSection.data + fTOCSection.currentOffset; 731 fTOCSection.currentOffset += size; 732 return B_OK; 733 } 734 735 736 } // namespace BPrivate 737 738 } // namespace V1 739 740 } // namespace BHPKG 741 742 } // namespace BPackageKit 743