| 382 | |
| 383 | |
| 384 | static void archiveDirectory(const std::string& archivePath, std::vector<uint8_t>* archiveData, const std::string& dirPath, int compressionLevel) { |
| 385 | // Based on minitar.c create() in libarchive examples |
| 386 | int r; |
| 387 | |
| 388 | // Open archive for writing |
| 389 | struct archive* a = archive_write_new(); |
| 390 | DEFER({archive_write_free(a);}); |
| 391 | // For some reason libarchive adds 10k of padding to archive_write_open() (but not archive_write_open_filename()) unless this is set to 0. |
| 392 | archive_write_set_bytes_per_block(a, 0); |
| 393 | archive_write_set_format_pax_restricted(a); |
| 394 | archive_write_add_filter_zstd(a); |
| 395 | if (!(0 <= compressionLevel && compressionLevel <= 19)) |
| 396 | throw Exception("Invalid Zstandard compression level"); |
| 397 | r = archive_write_set_filter_option(a, NULL, "compression-level", std::to_string(compressionLevel).c_str()); |
| 398 | if (r < ARCHIVE_OK) |
| 399 | throw Exception("Archiver could not set filter option: %s", archive_error_string(a)); |
| 400 | |
| 401 | if (archiveData) { |
| 402 | // Open vector |
| 403 | archive_write_open(a, (void*) archiveData, NULL, archiveWriteVectorCallback, NULL); |
| 404 | } |
| 405 | else { |
| 406 | // Open file |
| 407 | #if defined ARCH_WIN |
| 408 | r = archive_write_open_filename_w(a, string::UTF8toUTF16(archivePath).c_str()); |
| 409 | #else |
| 410 | r = archive_write_open_filename(a, archivePath.c_str()); |
| 411 | #endif |
| 412 | if (r < ARCHIVE_OK) |
| 413 | throw Exception("Archiver could not open archive %s for writing: %s", archivePath.c_str(), archive_error_string(a)); |
| 414 | } |
| 415 | DEFER({archive_write_close(a);}); |
| 416 | |
| 417 | // Open dir for reading |
| 418 | struct archive* disk = archive_read_disk_new(); |
| 419 | DEFER({archive_read_free(disk);}); |
| 420 | #if defined ARCH_WIN |
| 421 | r = archive_read_disk_open_w(disk, string::UTF8toUTF16(dirPath).c_str()); |
| 422 | #else |
| 423 | r = archive_read_disk_open(disk, dirPath.c_str()); |
| 424 | #endif |
| 425 | if (r < ARCHIVE_OK) |
| 426 | throw Exception("Archiver could not open dir %s for reading: %s", dirPath.c_str(), archive_error_string(a)); |
| 427 | DEFER({archive_read_close(a);}); |
| 428 | |
| 429 | // Iterate dir |
| 430 | for (;;) { |
| 431 | struct archive_entry* entry = archive_entry_new(); |
| 432 | DEFER({archive_entry_free(entry);}); |
| 433 | |
| 434 | r = archive_read_next_header2(disk, entry); |
| 435 | if (r == ARCHIVE_EOF) |
| 436 | break; |
| 437 | if (r < ARCHIVE_OK) |
| 438 | throw Exception("Archiver could not get next entry from archive: %s", archive_error_string(disk)); |
| 439 | |
| 440 | // Recurse dirs |
| 441 | archive_read_disk_descend(disk); |
no test coverage detected