Try working with libarchive better
This commit is contained in:
parent
0ba157d434
commit
a80792d1d5
@ -14,8 +14,14 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "common.h"
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
// Wrap libarchive headers with extern "C" to prevent C++ name mangling
|
||||
extern "C" {
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
}
|
||||
|
||||
#include <sys/stat.h> // For permission macros like S_IRUSR
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@ -25,12 +31,14 @@
|
||||
#include <filesystem>
|
||||
#include <chrono>
|
||||
#include <regex>
|
||||
#include <optional> // 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<mode_t>(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<char> buffer((std::istreambuf_iterator<char>(fileStream)), std::istreambuf_iterator<char>());
|
||||
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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user