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