From a80792d1d5d046f429abbb0726a7b3315fa8aff4 Mon Sep 17 00:00:00 2001 From: Simon Quigley Date: Wed, 18 Dec 2024 16:46:00 -0600 Subject: [PATCH] Try working with libarchive better --- cpp/common.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 11 deletions(-) diff --git a/cpp/common.cpp b/cpp/common.cpp index 965a3aa..7eb58f1 100644 --- a/cpp/common.cpp +++ b/cpp/common.cpp @@ -14,8 +14,14 @@ // along with this program. If not, see . #include "common.h" -#include -#include + +// Wrap libarchive headers with extern "C" to prevent C++ name mangling +extern "C" { + #include + #include +} + +#include // For permission macros like S_IRUSR #include #include #include @@ -25,12 +31,14 @@ #include #include #include +#include // For std::optional namespace fs = std::filesystem; static void log_info(const std::string &msg) { std::cout << "[INFO] " << msg << "\n"; } + static void log_error(const std::string &msg) { std::cerr << "[ERROR] " << msg << "\n"; } @@ -119,13 +127,27 @@ void create_tarball(const std::string& tarballPath, const std::string& directory std::cout << "[INFO] Creating tarball: " << tarballPath << std::endl; struct archive* a = archive_write_new(); + if (!a) { + throw std::runtime_error("Failed to create archive object."); + } + struct archive_entry* entry = nullptr; - // Initialize the tarball - archive_write_add_filter_gzip(a); - archive_write_set_format_pax_restricted(a); + // Initialize the tarball with gzip filter and pax restricted format + if (archive_write_add_filter_gzip(a) != ARCHIVE_OK) { + archive_write_free(a); + throw std::runtime_error("Failed to add gzip filter: " + std::string(archive_error_string(a))); + } + + if (archive_write_set_format_pax_restricted(a) != ARCHIVE_OK) { + archive_write_free(a); + throw std::runtime_error("Failed to set pax restricted format: " + std::string(archive_error_string(a))); + } + if (archive_write_open_filename(a, tarballPath.c_str()) != ARCHIVE_OK) { - throw std::runtime_error("Could not open tarball for writing: " + std::string(archive_error_string(a))); + std::string error_msg = "Could not open tarball for writing: " + std::string(archive_error_string(a)); + archive_write_free(a); + throw std::runtime_error(error_msg); } for (const auto& file : fs::recursive_directory_iterator(directory)) { @@ -144,24 +166,69 @@ void create_tarball(const std::string& tarballPath, const std::string& directory if (!fs::is_directory(path)) { // Add the file to the tarball entry = archive_entry_new(); + if (!entry) { + archive_write_free(a); + throw std::runtime_error("Failed to create archive entry for " + relativePath); + } + archive_entry_set_pathname(entry, relativePath.c_str()); archive_entry_set_size(entry, fs::file_size(path)); archive_entry_set_filetype(entry, AE_IFREG); - archive_entry_set_perm(entry, static_cast(fs::status(path).permissions())); - archive_write_header(a, entry); + // Convert std::filesystem::perms to mode_t + std::filesystem::perms p = fs::status(path).permissions(); + mode_t mode = 0; + if ((p & fs::perms::owner_read) != fs::perms::none) mode |= S_IRUSR; + if ((p & fs::perms::owner_write) != fs::perms::none) mode |= S_IWUSR; + if ((p & fs::perms::owner_exec) != fs::perms::none) mode |= S_IXUSR; + if ((p & fs::perms::group_read) != fs::perms::none) mode |= S_IRGRP; + if ((p & fs::perms::group_write) != fs::perms::none) mode |= S_IWGRP; + if ((p & fs::perms::group_exec) != fs::perms::none) mode |= S_IXGRP; + if ((p & fs::perms::others_read) != fs::perms::none) mode |= S_IROTH; + if ((p & fs::perms::others_write) != fs::perms::none) mode |= S_IWOTH; + if ((p & fs::perms::others_exec) != fs::perms::none) mode |= S_IXOTH; + + archive_entry_set_perm(entry, mode); + + if (archive_write_header(a, entry) != ARCHIVE_OK) { + std::string error_msg = "Could not write header for " + relativePath + ": " + std::string(archive_error_string(a)); + archive_entry_free(entry); + archive_write_free(a); + throw std::runtime_error(error_msg); + } // Write file contents std::ifstream fileStream(path, std::ios::binary); - std::vector buffer((std::istreambuf_iterator(fileStream)), std::istreambuf_iterator()); - archive_write_data(a, buffer.data(), buffer.size()); + if (!fileStream) { + std::string error_msg = "Could not open file " + relativePath + " for reading"; + archive_entry_free(entry); + archive_write_free(a); + throw std::runtime_error(error_msg); + } + + // Read the file in chunks to handle large files efficiently + const std::size_t buffer_size = 8192; + char buffer[buffer_size]; + while (fileStream.read(buffer, buffer_size) || fileStream.gcount() > 0) { + ssize_t bytes_written = archive_write_data(a, buffer, fileStream.gcount()); + if (bytes_written < 0) { + std::string error_msg = "Could not write data for " + relativePath + ": " + std::string(archive_error_string(a)); + archive_entry_free(entry); + archive_write_free(a); + throw std::runtime_error(error_msg); + } + } archive_entry_free(entry); } } // Finalize and clean up - archive_write_close(a); + if (archive_write_close(a) != ARCHIVE_OK) { + std::string error_msg = "Could not close archive: " + std::string(archive_error_string(a)); + archive_write_free(a); + throw std::runtime_error(error_msg); + } archive_write_free(a); std::cout << "[INFO] Tarball created and compressed: " << tarballPath << std::endl;