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/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/HPKGDefsPrivate.h> 24 25 #include <package/hpkg/BufferDataOutput.h> 26 #include <package/hpkg/PackageData.h> 27 #include <package/hpkg/PackageEntry.h> 28 #include <package/hpkg/PackageEntryAttribute.h> 29 #include <ZlibDecompressor.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 hpkg_header header; 338 status_t error = inherited::Init<hpkg_header, B_HPKG_MAGIC, B_HPKG_VERSION, 339 B_HPKG_MINOR_VERSION>(fd, keepFD, header, flags); 340 if (error != B_OK) 341 return error; 342 fHeapSize = UncompressedHeapSize(); 343 344 // init package attributes section 345 error = InitSection(fPackageAttributesSection, fHeapSize, 346 B_BENDIAN_TO_HOST_INT32(header.attributes_length), 347 kMaxPackageAttributesSize, 348 B_BENDIAN_TO_HOST_INT32(header.attributes_strings_length), 349 B_BENDIAN_TO_HOST_INT32(header.attributes_strings_count)); 350 if (error != B_OK) 351 return error; 352 353 // init TOC section 354 error = InitSection(fTOCSection, fPackageAttributesSection.offset, 355 B_BENDIAN_TO_HOST_INT64(header.toc_length), kMaxTOCSize, 356 B_BENDIAN_TO_HOST_INT64(header.toc_strings_length), 357 B_BENDIAN_TO_HOST_INT64(header.toc_strings_count)); 358 if (error != B_OK) 359 return error; 360 361 // prepare the sections for use 362 error = PrepareSection(fTOCSection); 363 if (error != B_OK) 364 return error; 365 366 error = PrepareSection(fPackageAttributesSection); 367 if (error != B_OK) 368 return error; 369 370 return B_OK; 371 } 372 373 374 status_t 375 PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler) 376 { 377 AttributeHandlerContext context(ErrorOutput(), contentHandler, 378 B_HPKG_SECTION_PACKAGE_ATTRIBUTES, 379 MinorFormatVersion() > B_HPKG_MINOR_VERSION); 380 RootAttributeHandler rootAttributeHandler; 381 382 status_t error 383 = ParsePackageAttributesSection(&context, &rootAttributeHandler); 384 385 if (error == B_OK) { 386 context.section = B_HPKG_SECTION_PACKAGE_TOC; 387 error = _ParseTOC(&context, &rootAttributeHandler); 388 } 389 390 return error; 391 } 392 393 394 status_t 395 PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler* contentHandler) 396 { 397 AttributeHandlerContext context(ErrorOutput(), contentHandler, 398 B_HPKG_SECTION_PACKAGE_ATTRIBUTES, 399 MinorFormatVersion() > B_HPKG_MINOR_VERSION); 400 LowLevelAttributeHandler rootAttributeHandler; 401 402 status_t error 403 = ParsePackageAttributesSection(&context, &rootAttributeHandler); 404 405 if (error == B_OK) { 406 context.section = B_HPKG_SECTION_PACKAGE_TOC; 407 error = _ParseTOC(&context, &rootAttributeHandler); 408 } 409 410 return error; 411 } 412 413 414 status_t 415 PackageReaderImpl::_ParseTOC(AttributeHandlerContext* context, 416 AttributeHandler* rootAttributeHandler) 417 { 418 // parse the TOC 419 fTOCSection.currentOffset = fTOCSection.stringsLength; 420 SetCurrentSection(&fTOCSection); 421 422 // init the attribute handler stack 423 rootAttributeHandler->SetLevel(0); 424 ClearAttributeHandlerStack(); 425 PushAttributeHandler(rootAttributeHandler); 426 427 bool sectionHandled; 428 status_t error = ParseAttributeTree(context, sectionHandled); 429 if (error == B_OK && sectionHandled) { 430 if (fTOCSection.currentOffset < fTOCSection.uncompressedLength) { 431 ErrorOutput()->PrintError("Error: %llu excess byte(s) in TOC " 432 "section\n", 433 fTOCSection.uncompressedLength - fTOCSection.currentOffset); 434 error = B_BAD_DATA; 435 } 436 } 437 438 // clean up on error 439 if (error != B_OK) { 440 context->ErrorOccurred(); 441 while (AttributeHandler* handler = PopAttributeHandler()) { 442 if (handler != rootAttributeHandler) 443 handler->Delete(context); 444 } 445 return error; 446 } 447 448 return B_OK; 449 } 450 451 452 status_t 453 PackageReaderImpl::ReadAttributeValue(uint8 type, uint8 encoding, 454 AttributeValue& _value) 455 { 456 switch (type) { 457 case B_HPKG_ATTRIBUTE_TYPE_RAW: 458 { 459 uint64 size; 460 status_t error = ReadUnsignedLEB128(size); 461 if (error != B_OK) 462 return error; 463 464 if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) { 465 uint64 offset; 466 error = ReadUnsignedLEB128(offset); 467 if (error != B_OK) 468 return error; 469 470 if (offset > fHeapSize || size > fHeapSize - offset) { 471 ErrorOutput()->PrintError("Error: Invalid %s section: " 472 "invalid data reference\n", CurrentSection()->name); 473 return B_BAD_DATA; 474 } 475 476 _value.SetToData(size, offset); 477 } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) { 478 if (size > B_HPKG_MAX_INLINE_DATA_SIZE) { 479 ErrorOutput()->PrintError("Error: Invalid %s section: " 480 "inline data too long\n", CurrentSection()->name); 481 return B_BAD_DATA; 482 } 483 484 const void* buffer; 485 error = _GetTOCBuffer(size, buffer); 486 if (error != B_OK) 487 return error; 488 _value.SetToData(size, buffer); 489 } else { 490 ErrorOutput()->PrintError("Error: Invalid %s section: invalid " 491 "raw encoding (%u)\n", CurrentSection()->name, encoding); 492 return B_BAD_DATA; 493 } 494 495 return B_OK; 496 } 497 498 default: 499 return inherited::ReadAttributeValue(type, encoding, _value); 500 } 501 } 502 503 504 status_t 505 PackageReaderImpl::_GetTOCBuffer(size_t size, const void*& _buffer) 506 { 507 if (size > fTOCSection.uncompressedLength - fTOCSection.currentOffset) { 508 ErrorOutput()->PrintError("_GetTOCBuffer(%lu): read beyond TOC end\n", 509 size); 510 return B_BAD_DATA; 511 } 512 513 _buffer = fTOCSection.data + fTOCSection.currentOffset; 514 fTOCSection.currentOffset += size; 515 return B_OK; 516 } 517 518 519 } // namespace BPrivate 520 521 } // namespace BHPKG 522 523 } // namespace BPackageKit 524