#include "../include/Archive.hpp" #include "../include/utils.hpp" #include #include #include using namespace std; class FileHandler { DISABLE_COPY(FileHandler) public: FileHandler(FILE *_file) : file(_file) { } FileHandler(FileHandler &&other) { file = other.file; other.file = nullptr; } ~FileHandler() { fclose(file); } FILE *file; }; // libarchive code is modified version of: https://github.com/libarchive/libarchive/wiki/Examples#A_Complete_Extractor namespace sibs { static int copy_data(struct archive *ar, struct archive *aw) { int r; const void *buff; size_t size; la_int64_t offset; while(true) { r = archive_read_data_block(ar, &buff, &size, &offset); if (r == ARCHIVE_EOF) return ARCHIVE_OK; else if (r < ARCHIVE_OK) return r; r = archive_write_data_block(aw, buff, size, offset); if (r < ARCHIVE_OK) return r; } } Result Archive::extract(const char *source, const char *destination) { struct archive *a; struct archive *ext; struct archive_entry *entry; int flags; int r; /* Select which attributes we want to restore. */ flags = ARCHIVE_EXTRACT_TIME; flags |= ARCHIVE_EXTRACT_PERM; flags |= ARCHIVE_EXTRACT_ACL; flags |= ARCHIVE_EXTRACT_FFLAGS; string rootName; a = archive_read_new(); archive_read_support_format_all(a); archive_read_support_compression_all(a); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); if ((r = archive_read_open_filename(a, source, 10240))) { string errMsg = "Failed to extract archive: "; errMsg += source; return Result::Err(errMsg); } while(true) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; else if (r < ARCHIVE_OK) { string errMsg = "Failed to extract archive: "; errMsg += source; errMsg += "; reason: "; errMsg += archive_error_string(a); return Result::Err(errMsg); } else if (r < ARCHIVE_WARN) { string errMsg = "Failed to extract archive: "; errMsg += source; errMsg += "; reason: "; errMsg += archive_error_string(a); return Result::Err(errMsg); } const char* currentFile = archive_entry_pathname(entry); if(rootName.empty()) rootName = currentFile; std::string fullOutputPath = destination; fullOutputPath += (currentFile + (rootName.empty() ? 0 : rootName.size() - 1)); archive_entry_set_pathname(entry, fullOutputPath.c_str()); r = archive_write_header(ext, entry); if (r < ARCHIVE_OK) { string errMsg = "Failed to extract archive: "; errMsg += source; errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); } else if (archive_entry_size(entry) > 0) { r = copy_data(a, ext); if (r < ARCHIVE_OK) { string errMsg = "Failed to extract archive: "; errMsg += source; errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); } else if (r < ARCHIVE_WARN) { string errMsg = "Failed to extract archive: "; errMsg += source; errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); } } r = archive_write_finish_entry(ext); if (r < ARCHIVE_OK) { string errMsg = "Failed to extract archive: "; errMsg += source; errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); } else if (r < ARCHIVE_WARN) { string errMsg = "Failed to extract archive: "; errMsg += source; errMsg += "; reason: "; errMsg += archive_error_string(ext); return Result::Err(errMsg); } } archive_read_close(a); archive_read_free(a); archive_write_close(ext); archive_write_free(ext); return Result::Ok(true); } }