aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/function/ArchiveFileOperator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/function/ArchiveFileOperator.cpp')
-rw-r--r--src/core/function/ArchiveFileOperator.cpp411
1 files changed, 204 insertions, 207 deletions
diff --git a/src/core/function/ArchiveFileOperator.cpp b/src/core/function/ArchiveFileOperator.cpp
index 8aad0500..f1345f87 100644
--- a/src/core/function/ArchiveFileOperator.cpp
+++ b/src/core/function/ArchiveFileOperator.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2021 Saturneric
+ * Copyright (C) 2021 Saturneric <[email protected]>
*
* This file is part of GpgFrontend.
*
@@ -20,7 +20,7 @@
* the gpg4usb project, which is under GPL-3.0-or-later.
*
* All the source code of GpgFrontend was modified and released by
- * Saturneric<[email protected]> starting on May 12, 2021.
+ * Saturneric <[email protected]> starting on May 12, 2021.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
@@ -28,7 +28,15 @@
#include "ArchiveFileOperator.h"
-int copy_data(struct archive *ar, struct archive *aw) {
+#include <archive.h>
+#include <archive_entry.h>
+#include <sys/fcntl.h>
+
+#include "core/utils/AsyncUtils.h"
+
+namespace GpgFrontend {
+
+auto CopyData(struct archive *ar, struct archive *aw) -> int {
int r;
const void *buff;
size_t size;
@@ -38,231 +46,218 @@ int copy_data(struct archive *ar, struct archive *aw) {
r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF) return (ARCHIVE_OK);
if (r != ARCHIVE_OK) {
- SPDLOG_ERROR("archive_read_data_block() failed: {}",
- archive_error_string(ar));
+ GF_CORE_LOG_ERROR("archive_read_data_block() failed: {}",
+ archive_error_string(ar));
return (r);
}
r = archive_write_data_block(aw, buff, size, offset);
if (r != ARCHIVE_OK) {
- SPDLOG_ERROR("archive_write_data_block() failed: {}",
- archive_error_string(aw));
+ GF_CORE_LOG_ERROR("archive_write_data_block() failed: {}",
+ archive_error_string(aw));
return (r);
}
}
}
-void GpgFrontend::ArchiveFileOperator::CreateArchive(
- const std::filesystem::path &base_path,
- const std::filesystem::path &archive_path, int compress,
- const std::vector<std::filesystem::path> &files) {
- SPDLOG_DEBUG("CreateArchive: {}", archive_path.u8string());
-
- auto current_base_path_backup = QDir::currentPath();
- QDir::setCurrent(base_path.u8string().c_str());
-
- auto relative_archive_path =
- std::filesystem::relative(archive_path, base_path);
-
- std::vector<std::filesystem::path> relative_files;
- relative_files.reserve(files.size());
- for (const auto &file : files) {
- relative_files.push_back(std::filesystem::relative(file, base_path));
- }
-
- struct archive *a;
- struct archive_entry *entry;
- ssize_t len;
- int fd;
-
- SPDLOG_DEBUG("compress: {}", compress);
-
- a = archive_write_new();
- switch (compress) {
-#ifndef NO_BZIP2_CREATE
- case 'j':
- case 'y':
- archive_write_add_filter_bzip2(a);
- break;
-#endif
-#ifndef NO_COMPRESS_CREATE
- case 'Z':
- archive_write_add_filter_compress(a);
- break;
-#endif
-#ifndef NO_GZIP_CREATE
- case 'z':
- archive_write_add_filter_gzip(a);
- break;
-#endif
- default:
- archive_write_add_filter_none(a);
- break;
- }
- archive_write_set_format_ustar(a);
- archive_write_set_format_pax_restricted(a);
-
- auto u8_filename = relative_archive_path.u8string();
-
- if (!u8_filename.empty() && u8_filename == u8"-")
- throw std::runtime_error("cannot write to stdout");
-
-#ifdef WINDOWS
- archive_write_open_filename_w(a, relative_archive_path.wstring().c_str());
-#else
- archive_write_open_filename(a, u8_filename.c_str());
-#endif
-
- for (const auto &file : relative_files) {
- struct archive *disk = archive_read_disk_new();
-#ifndef NO_LOOKUP
- archive_read_disk_set_standard_lookup(disk);
-#endif
- int r;
-
- SPDLOG_DEBUG("reading file: {}", file.u8string());
-
-#ifdef WINDOWS
- r = archive_read_disk_open_w(disk, file.wstring().c_str());
-#else
- r = archive_read_disk_open(disk, file.u8string().c_str());
-#endif
-
- SPDLOG_DEBUG("read file done: {}", file.u8string());
-
- if (r != ARCHIVE_OK) {
- SPDLOG_ERROR("{archive_read_disk_open() failed: {}",
- archive_error_string(disk));
- throw std::runtime_error("archive_read_disk_open() failed");
- }
+struct ArchiveReadClientData {
+ GFDataExchanger *ex;
+ std::array<std::byte, 1024> buf;
+ const std::byte *p_buf = buf.data();
+};
+
+auto ArchiveReadCallback(struct archive *, void *client_data,
+ const void **buffer) -> ssize_t {
+ auto *rdata = static_cast<ArchiveReadClientData *>(client_data);
+ *buffer = reinterpret_cast<const void *>(rdata->p_buf);
+ return rdata->ex->Read(rdata->buf.data(), rdata->buf.size());
+}
- for (;;) {
- entry = archive_entry_new();
- r = archive_read_next_header2(disk, entry);
-
- if (r == ARCHIVE_EOF) break;
- if (r != ARCHIVE_OK) {
- SPDLOG_ERROR("archive_read_next_header2() failed: {}",
- archive_error_string(disk));
- throw std::runtime_error("archive_read_next_header2() failed");
- }
- archive_read_disk_descend(disk);
-
- SPDLOG_DEBUG("Adding: {} size: {} bytes: {} file type: {}",
- archive_entry_pathname_utf8(entry),
- archive_entry_size(entry), archive_entry_filetype(entry));
-
- r = archive_write_header(a, entry);
- if (r < ARCHIVE_OK) {
- SPDLOG_ERROR("archive_write_header() failed: {}",
- archive_error_string(a));
- throw std::runtime_error("archive_write_header() failed");
- }
- if (r == ARCHIVE_FATAL) throw std::runtime_error("archive fatal");
- if (r > ARCHIVE_FAILED) {
- QByteArray buff;
-#ifdef WINDOWS
- FileOperator::ReadFile(
- QString::fromStdWString(archive_entry_sourcepath_w(entry)), buff);
-#else
- FileOperator::ReadFile(archive_entry_sourcepath(entry), buff);
-#endif
- archive_write_data(a, buff.data(), buff.size());
- }
- archive_entry_free(entry);
- }
- archive_read_close(disk);
- archive_read_free(disk);
- }
- archive_write_close(a);
- archive_write_free(a);
+auto ArchiveWriteCallback(struct archive *, void *client_data,
+ const void *buffer, size_t length) -> ssize_t {
+ auto *ex = static_cast<GFDataExchanger *>(client_data);
+ return ex->Write(static_cast<const std::byte *>(buffer), length);
+}
- QDir::setCurrent(current_base_path_backup);
+auto ArchiveCloseWriteCallback(struct archive *, void *client_data) -> int {
+ auto *ex = static_cast<GFDataExchanger *>(client_data);
+ ex->CloseWrite();
+ return 0;
}
-void GpgFrontend::ArchiveFileOperator::ExtractArchive(
- const std::filesystem::path &archive_path,
- const std::filesystem::path &base_path) {
- SPDLOG_DEBUG("ExtractArchive: {}", archive_path.u8string());
+void ArchiveFileOperator::NewArchive2DataExchanger(
+ const QString &target_directory, std::shared_ptr<GFDataExchanger> exchanger,
+ const OperationCallback &cb) {
+ RunIOOperaAsync(
+ [=](const DataObjectPtr &data_object) -> GFError {
+ std::array<char, 1024> buff{};
+ auto ret = 0;
+ const auto base_path = QDir(QDir(target_directory).absolutePath());
- auto current_base_path_backup = QDir::currentPath();
- QDir::setCurrent(base_path.u8string().c_str());
+ auto *archive = archive_write_new();
+ archive_write_add_filter_none(archive);
+ archive_write_set_format_pax_restricted(archive);
- struct archive *a;
- struct archive *ext;
- struct archive_entry *entry;
+ archive_write_open(archive, exchanger.get(), nullptr,
+ ArchiveWriteCallback, ArchiveCloseWriteCallback);
- a = archive_read_new();
- ext = archive_write_disk_new();
- archive_write_disk_set_options(ext, 0);
-#ifndef NO_BZIP2_EXTRACT
- archive_read_support_filter_bzip2(a);
-#endif
-#ifndef NO_GZIP_EXTRACT
- archive_read_support_filter_gzip(a);
-#endif
-#ifndef NO_COMPRESS_EXTRACT
- archive_read_support_filter_compress(a);
-#endif
-#ifndef NO_TAR_EXTRACT
- archive_read_support_format_tar(a);
-#endif
-#ifndef NO_CPIO_EXTRACT
- archive_read_support_format_cpio(a);
-#endif
-#ifndef NO_LOOKUP
- archive_write_disk_set_standard_lookup(ext);
-#endif
+ auto *disk = archive_read_disk_new();
+ archive_read_disk_set_standard_lookup(disk);
- auto filename = archive_path.u8string();
-
- if (!filename.empty() && filename == u8"-") {
- SPDLOG_ERROR("cannot read from stdin");
- }
#ifdef WINDOWS
- if (archive_read_open_filename_w(a, archive_path.wstring().c_str(), 10240) !=
- ARCHIVE_OK) {
+ auto r = archive_read_disk_open_w(
+ disk, target_directory.toStdWString().c_str());
#else
- if (archive_read_open_filename(a, archive_path.u8string().c_str(), 10240) !=
- ARCHIVE_OK) {
+ auto r = archive_read_disk_open(disk, target_directory.toUtf8());
#endif
- SPDLOG_ERROR("archive_read_open_filename() failed: {}",
- archive_error_string(a));
- throw std::runtime_error("archive_read_open_filename() failed");
- }
-
- for (;;) {
- int r = archive_read_next_header(a, &entry);
- if (r == ARCHIVE_EOF) break;
- if (r != ARCHIVE_OK) {
- SPDLOG_ERROR("archive_read_next_header() failed: {}",
- archive_error_string(a));
- throw std::runtime_error("archive_read_next_header() failed");
- }
- SPDLOG_DEBUG("Adding: {} size: {} bytes: {} file type: {}",
- archive_entry_pathname_utf8(entry), archive_entry_size(entry),
- archive_entry_filetype(entry));
- r = archive_write_header(ext, entry);
- if (r != ARCHIVE_OK) {
- SPDLOG_ERROR("archive_write_header() failed: {}",
- archive_error_string(ext));
- } else {
- r = copy_data(a, ext);
- if (r != ARCHIVE_OK) {
- SPDLOG_ERROR("copy_data() failed: {}", archive_error_string(ext));
- }
- }
- }
- archive_read_close(a);
- archive_read_free(a);
- archive_write_close(ext);
- archive_write_free(ext);
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR("archive_read_disk_open() failed: {}, abort...",
+ archive_error_string(disk));
+ archive_read_free(disk);
+ archive_write_free(archive);
+ return -1;
+ }
+
+ for (;;) {
+ auto *entry = archive_entry_new();
+ r = archive_read_next_header2(disk, entry);
+ if (r == ARCHIVE_EOF) break;
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR(
+ "archive_read_next_header2() failed, ret: {}, explain: {}", r,
+ archive_error_string(disk));
+ ret = -1;
+ break;
+ }
+
+ archive_read_disk_descend(disk);
+
+ // turn absolute path to relative path
+ archive_entry_set_pathname(
+ entry,
+ base_path.relativeFilePath(QString(archive_entry_pathname(entry)))
+ .toUtf8());
+
+ r = archive_write_header(archive, entry);
+ if (r < ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR(
+ "archive_write_header() failed, ret: {}, explain: {} ", r,
+ archive_error_string(archive));
+ continue;
+ }
+
+ if (r == ARCHIVE_FATAL) {
+ GF_CORE_LOG_ERROR(
+ "archive_write_header() failed, ret: {}, explain: {}, "
+ "abort ...",
+ r, archive_error_string(archive));
+ ret = -1;
+ break;
+ }
+
+ if (r > ARCHIVE_FAILED) {
+ auto fd = open(archive_entry_sourcepath(entry), O_RDONLY);
+ auto len = read(fd, buff.data(), buff.size());
+ while (len > 0) {
+ archive_write_data(archive, buff.data(), len);
+ len = read(fd, buff.data(), buff.size());
+ }
+ close(fd);
+ }
+ archive_entry_free(entry);
+ }
+
+ archive_read_free(disk);
+ archive_write_free(archive);
+ return ret;
+ },
+ cb, "archive_write_new");
+}
- QDir::setCurrent(current_base_path_backup);
+void ArchiveFileOperator::ExtractArchiveFromDataExchanger(
+ std::shared_ptr<GFDataExchanger> ex, const QString &target_path,
+ const OperationCallback &cb) {
+ GF_CORE_LOG_INFO("target path: {}", target_path);
+ RunIOOperaAsync(
+ [=](const DataObjectPtr &data_object) -> GFError {
+ auto *archive = archive_read_new();
+ auto *ext = archive_write_disk_new();
+
+ auto r = archive_read_support_filter_all(archive);
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR(
+ "archive_read_support_filter_all(), ret: {}, reason: {}", r,
+ archive_error_string(archive));
+ return r;
+ }
+
+ r = archive_read_support_format_all(archive);
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR(
+ "archive_read_support_format_all(), ret: {}, reason: {}", r,
+ archive_error_string(archive));
+ return r;
+ }
+
+ auto rdata = ArchiveReadClientData{};
+ rdata.ex = ex.get();
+
+ r = archive_read_open(archive, &rdata, nullptr, ArchiveReadCallback,
+ nullptr);
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR("archive_read_open(), ret: {}, reason: {}", r,
+ archive_error_string(archive));
+ return r;
+ }
+
+ r = archive_write_disk_set_options(ext, 0);
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR(
+ "archive_write_disk_set_options(), ret: {}, reason: {}", r,
+ archive_error_string(archive));
+ return r;
+ }
+
+ for (;;) {
+ struct archive_entry *entry;
+ r = archive_read_next_header(archive, &entry);
+ if (r == ARCHIVE_EOF) break;
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR("archive_read_next_header(), ret: {}, reason: {}",
+ r, archive_error_string(archive));
+ break;
+ }
+
+ archive_entry_set_pathname(
+ entry,
+ (target_path + "/" + archive_entry_pathname(entry)).toUtf8());
+
+ r = archive_write_header(ext, entry);
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR("archive_write_header(), ret: {}, reason: {}", r,
+ archive_error_string(archive));
+ } else {
+ r = CopyData(archive, ext);
+ }
+ }
+
+ r = archive_read_free(archive);
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR("archive_read_free(), ret: {}, reason: {}", r,
+ archive_error_string(archive));
+ }
+ r = archive_write_free(ext);
+ if (r != ARCHIVE_OK) {
+ GF_CORE_LOG_ERROR("archive_read_free(), ret: {}, reason: {}", r,
+ archive_error_string(archive));
+ }
+
+ return 0;
+ },
+ cb, "archive_read_new");
}
-void GpgFrontend::ArchiveFileOperator::ListArchive(
- const std::filesystem::path &archive_path) {
+void ArchiveFileOperator::ListArchive(const QString &archive_path) {
struct archive *a;
struct archive_entry *entry;
int r;
@@ -270,14 +265,16 @@ void GpgFrontend::ArchiveFileOperator::ListArchive(
a = archive_read_new();
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
- r = archive_read_open_filename(a, archive_path.u8string().c_str(),
+ r = archive_read_open_filename(a, archive_path.toUtf8(),
10240); // Note 1
if (r != ARCHIVE_OK) return;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
- SPDLOG_DEBUG("File: {}", archive_entry_pathname(entry));
- SPDLOG_DEBUG("File Path: {}", archive_entry_pathname(entry));
+ GF_CORE_LOG_DEBUG("File: {}", archive_entry_pathname(entry));
+ GF_CORE_LOG_DEBUG("File Path: {}", archive_entry_pathname(entry));
archive_read_data_skip(a); // Note 2
}
r = archive_read_free(a); // Note 3
if (r != ARCHIVE_OK) return;
}
+
+} // namespace GpgFrontend \ No newline at end of file