| 513 | } |
| 514 | |
| 515 | static void unarchiveToDirectory(const std::string& archivePath, const std::vector<uint8_t>* archiveData, const std::string& dirPathStr) { |
| 516 | #if defined ARCH_MAC |
| 517 | // libarchive depends on locale so set thread locale |
| 518 | // If locale is not found, returns NULL which resets thread to global locale |
| 519 | locale_t loc = newlocale(LC_CTYPE_MASK, "en_US.UTF-8", NULL); |
| 520 | locale_t oldLoc = uselocale(loc); |
| 521 | freelocale(loc); |
| 522 | DEFER({ |
| 523 | uselocale(oldLoc); |
| 524 | }); |
| 525 | #endif |
| 526 | |
| 527 | fs::path dirPath = fs::u8path(dirPathStr); |
| 528 | |
| 529 | // Based on minitar.c extract() in libarchive examples |
| 530 | int r; |
| 531 | |
| 532 | // Open archive for reading |
| 533 | struct archive* a = archive_read_new(); |
| 534 | if (!a) |
| 535 | throw Exception("Unarchiver could not be created"); |
| 536 | DEFER({archive_read_free(a);}); |
| 537 | archive_read_support_filter_zstd(a); |
| 538 | // archive_read_support_filter_all(a); |
| 539 | archive_read_support_format_tar(a); |
| 540 | // archive_read_support_format_all(a); |
| 541 | |
| 542 | ArchiveReadVectorData arvd; |
| 543 | if (archiveData) { |
| 544 | // Open vector |
| 545 | arvd.data = archiveData; |
| 546 | archive_read_open(a, &arvd, NULL, archiveReadVectorCallback, NULL); |
| 547 | } |
| 548 | else { |
| 549 | // Open file |
| 550 | const size_t blockSize = 1 << 16; |
| 551 | #if defined ARCH_WIN |
| 552 | r = archive_read_open_filename_w(a, string::UTF8toUTF16(archivePath).c_str(), blockSize); |
| 553 | #else |
| 554 | r = archive_read_open_filename(a, archivePath.c_str(), blockSize); |
| 555 | #endif |
| 556 | if (r < ARCHIVE_OK) |
| 557 | throw Exception("Unarchiver could not open archive %s: %s", archivePath.c_str(), archive_error_string(a)); |
| 558 | } |
| 559 | DEFER({archive_read_close(a);}); |
| 560 | |
| 561 | // Open dir for writing |
| 562 | struct archive* disk = archive_write_disk_new(); |
| 563 | DEFER({archive_write_free(disk);}); |
| 564 | // Don't restore timestamps |
| 565 | int flags = 0; |
| 566 | // Delete existing files instead of truncating and rewriting |
| 567 | flags |= ARCHIVE_EXTRACT_UNLINK; |
| 568 | archive_write_disk_set_options(disk, flags); |
| 569 | DEFER({archive_write_close(disk);}); |
| 570 | |
| 571 | // Iterate archive |
| 572 | for (;;) { |
no test coverage detected