From 5e67a1f27b5bb335feb7fe0c17030a17f0270732 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 16 Jun 2022 15:42:08 +0200 Subject: [PATCH] sys: Refactor tar file operations into their own class --- lib/libimhex/CMakeLists.txt | 3 +- lib/libimhex/include/hex/helpers/fs.hpp | 6 ++ lib/libimhex/include/hex/helpers/tar.hpp | 35 ++++++ lib/libimhex/source/helpers/tar.cpp | 100 ++++++++++++++++++ .../source/content/views/view_store.cpp | 43 ++------ 5 files changed, 153 insertions(+), 34 deletions(-) create mode 100644 lib/libimhex/include/hex/helpers/tar.hpp create mode 100644 lib/libimhex/source/helpers/tar.cpp diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt index 48e2f1cf8..52f52edf2 100644 --- a/lib/libimhex/CMakeLists.txt +++ b/lib/libimhex/CMakeLists.txt @@ -125,12 +125,13 @@ set(LIBIMHEX_SOURCES source/helpers/encoding_file.cpp source/helpers/loader_script_handler.cpp source/helpers/logger.cpp + source/helpers/tar.cpp source/providers/provider.cpp source/ui/imgui_imhex_extensions.cpp source/ui/view.cpp -) + ) if (APPLE) set(OSX_11_0_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk) diff --git a/lib/libimhex/include/hex/helpers/fs.hpp b/lib/libimhex/include/hex/helpers/fs.hpp index d72d27807..0693760aa 100644 --- a/lib/libimhex/include/hex/helpers/fs.hpp +++ b/lib/libimhex/include/hex/helpers/fs.hpp @@ -50,6 +50,12 @@ namespace hex::fs { return std::filesystem::remove(path, error) && !error; } + [[maybe_unused]] + static inline bool removeAll(const std::fs::path &path) { + std::error_code error; + return std::filesystem::remove_all(path, error) && !error; + } + [[maybe_unused]] static inline uintmax_t getFileSize(const std::fs::path &path) { std::error_code error; diff --git a/lib/libimhex/include/hex/helpers/tar.hpp b/lib/libimhex/include/hex/helpers/tar.hpp new file mode 100644 index 000000000..e8d9f276d --- /dev/null +++ b/lib/libimhex/include/hex/helpers/tar.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include + +#include + +#include + +namespace hex { + + class Tar { + public: + enum class Mode { + Read, + Write, + Create + }; + + Tar() = default; + Tar(const std::fs::path &path, Mode mode); + ~Tar(); + + std::vector read(const std::fs::path &path); + void write(const std::fs::path &path, const std::vector &data); + + std::vector listEntries(); + + void extract(const std::fs::path &path, const std::fs::path &outputPath); + void extractAll(const std::fs::path &outputPath); + + private: + mtar_t m_ctx = { }; + }; + +} \ No newline at end of file diff --git a/lib/libimhex/source/helpers/tar.cpp b/lib/libimhex/source/helpers/tar.cpp new file mode 100644 index 000000000..5135c848f --- /dev/null +++ b/lib/libimhex/source/helpers/tar.cpp @@ -0,0 +1,100 @@ +#include +#include +#include + +namespace hex { + + using namespace hex::literals; + + Tar::Tar(const std::fs::path &path, Mode mode) { + if (mode == Tar::Mode::Read) + mtar_open(&this->m_ctx, path.string().c_str(), "r"); + else if (mode == Tar::Mode::Write) + mtar_open(&this->m_ctx, path.string().c_str(), "a"); + else if (mode == Tar::Mode::Create) + mtar_open(&this->m_ctx, path.string().c_str(), "w"); + } + + Tar::~Tar() { + mtar_finalize(&this->m_ctx); + mtar_close(&this->m_ctx); + } + + std::vector Tar::listEntries() { + std::vector result; + + const std::string PaxHeaderName = "@PaxHeader"; + mtar_header_t header; + while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) { + if (header.name != PaxHeaderName) { + result.emplace_back(header.name); + } + + mtar_next(&this->m_ctx); + } + + return result; + } + + std::vector Tar::read(const std::fs::path &path) { + mtar_header_t header; + mtar_find(&this->m_ctx, path.string().c_str(), &header); + + std::vector result(header.size, 0x00); + mtar_read_data(&this->m_ctx, result.data(), result.size()); + + return result; + } + + void Tar::write(const std::fs::path &path, const std::vector &data) { + if (path.has_parent_path()) { + std::fs::path pathPart; + for (const auto &part : path.parent_path()) { + pathPart /= part; + mtar_write_dir_header(&this->m_ctx, pathPart.string().c_str()); + } + } + + mtar_write_file_header(&this->m_ctx, path.string().c_str(), data.size()); + mtar_write_data(&this->m_ctx, data.data(), data.size()); + } + + void Tar::extract(const std::fs::path &path, const std::fs::path &outputPath) { + mtar_header_t header; + mtar_find(&this->m_ctx, path.string().c_str(), &header); + + constexpr static u64 BufferSize = 1_MiB; + + fs::File outputFile(outputPath, fs::File::Mode::Create); + + std::vector buffer(BufferSize, 0x00); + for (u64 offset = 0; offset < header.size; offset += BufferSize) { + mtar_read_data(&this->m_ctx, buffer.data(), std::min(BufferSize, header.size - offset)); + outputFile.write(buffer); + } + } + + void Tar::extractAll(const std::fs::path &outputPath) { + constexpr static u64 BufferSize = 1_MiB; + + mtar_header_t header; + while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) { + const auto filePath = std::fs::absolute(outputPath / std::fs::path(header.name)); + + if (filePath.filename() != "@PaxHeader") { + + std::fs::create_directories(filePath.parent_path()); + fs::File outputFile(filePath, fs::File::Mode::Create); + + std::vector buffer(BufferSize, 0x00); + for (u64 offset = 0; offset < header.size; offset += BufferSize) { + mtar_read_data(&this->m_ctx, buffer.data(), std::min(BufferSize, header.size - offset)); + outputFile.write(buffer); + } + } + + mtar_next(&this->m_ctx); + } + } + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/views/view_store.cpp b/plugins/builtin/source/content/views/view_store.cpp index 75c3c795c..efefe2f02 100644 --- a/plugins/builtin/source/content/views/view_store.cpp +++ b/plugins/builtin/source/content/views/view_store.cpp @@ -12,12 +12,12 @@ #include #include #include +#include #include #include #include #include -#include namespace hex::plugin::builtin { @@ -76,34 +76,8 @@ namespace hex::plugin::builtin { entry.hasUpdate = false; if (entry.isFolder) { - mtar_t ctx; - mtar_open(&ctx, this->m_downloadPath.string().c_str(), "r"); - - mtar_header_t header; - auto extractBasePath = this->m_downloadPath.parent_path() / this->m_downloadPath.stem(); - while (mtar_read_header(&ctx, &header) != MTAR_ENULLRECORD) { - auto filePath = extractBasePath / std::fs::path(header.name); - if (filePath.filename() == "@PaxHeader") { - mtar_next(&ctx); - continue; - } - - fs::createDirectories(filePath.parent_path()); - fs::File outputFile(filePath.string(), fs::File::Mode::Create); - - std::vector buffer(0x10000); - for (u64 offset = 0; offset < header.size; offset += buffer.size()) { - auto readSize = std::min(buffer.size(), header.size - offset); - mtar_read_data(&ctx, buffer.data(), readSize); - - buffer.resize(readSize); - outputFile.write(buffer); - } - mtar_next(&ctx); - } - - mtar_finalize(&ctx); - mtar_close(&ctx); + Tar tar(this->m_downloadPath, Tar::Mode::Read); + tar.extractAll(this->m_downloadPath.parent_path() / this->m_downloadPath.stem()); } downloadDoneCallback(entry); @@ -257,12 +231,15 @@ namespace hex::plugin::builtin { } bool ViewStore::remove(fs::ImHexPath pathType, const std::string &fileName) { - bool removed = false; + bool removed = true; for (const auto &path : fs::getDefaultPaths(pathType)) { - bool removedFile = fs::remove(path / std::fs::path(fileName)); - bool removedFolder = fs::remove(path / std::fs::path(fileName).stem()); + const auto filePath = path / fileName; + const auto folderPath = (path / std::fs::path(fileName).stem()); - removed = removed || removedFile || removedFolder; + fs::remove(filePath); + fs::removeAll(folderPath); + + removed = removed && !fs::exists(filePath) && !fs::exists(folderPath); } return removed;