refactor: use file_access abstraction in filesystem_extractor

This commit is contained in:
Marcus Holland-Moritz 2025-05-27 10:57:05 +02:00
parent 19fcdbdd03
commit 938677302e
4 changed files with 66 additions and 13 deletions

View File

@ -38,6 +38,7 @@
namespace dwarfs {
class file_access;
class glob_matcher;
class library_dependencies;
class logger;
@ -67,7 +68,8 @@ struct filesystem_extractor_archive_format {
class filesystem_extractor {
public:
filesystem_extractor(logger& lgr, os_access const& os);
filesystem_extractor(logger& lgr, os_access const& os,
std::shared_ptr<file_access const> fa = nullptr);
static void add_library_dependencies(library_dependencies& deps);

View File

@ -53,6 +53,7 @@
#include <folly/system/ThreadName.h>
#include <dwarfs/config.h>
#include <dwarfs/file_access.h>
#include <dwarfs/file_stat.h>
#include <dwarfs/fstypes.h>
#include <dwarfs/glob_matcher.h>
@ -112,9 +113,11 @@ class archive_error : public std::runtime_error {
template <typename LoggerPolicy>
class filesystem_extractor_ final : public filesystem_extractor::impl {
public:
explicit filesystem_extractor_(logger& lgr, os_access const& os)
explicit filesystem_extractor_(logger& lgr, os_access const& os,
std::shared_ptr<file_access const> fa)
: LOG_PROXY_INIT(lgr)
, os_{os} {}
, os_{os}
, fa_{std::move(fa)} {}
~filesystem_extractor_() override {
try {
@ -139,13 +142,13 @@ class filesystem_extractor_ final : public filesystem_extractor::impl {
configure_format(format, &output);
#ifdef _WIN32
check_result(::archive_write_open_filename_w(
a_, output.empty() ? nullptr : output.wstring().c_str()));
#else
check_result(::archive_write_open_filename(
a_, output.empty() ? nullptr : output.string().c_str()));
#endif
if (output.empty()) {
check_result(::archive_write_open_filename(a_, nullptr));
} else {
out_ = fa_->open_output_binary(output);
check_result(::archive_write_open2(a_, this, nullptr, on_stream_write,
on_stream_close, on_stream_free));
}
#endif
}
@ -219,6 +222,26 @@ class filesystem_extractor_ final : public filesystem_extractor::impl {
filesystem_extractor_options const& opts) override;
private:
static la_ssize_t on_stream_write(struct archive* /*a*/, void* client_data,
void const* buffer, size_t length) {
auto self = static_cast<filesystem_extractor_*>(client_data);
auto& os = self->out_->os();
os.write(static_cast<char const*>(buffer), length);
return os.good() ? static_cast<la_ssize_t>(length) : -1;
}
static int on_stream_close(struct archive* /*a*/, void* client_data) {
auto self = static_cast<filesystem_extractor_*>(client_data);
self->out_->close();
return ARCHIVE_OK;
}
static int on_stream_free(struct archive* /*a*/, void* client_data) {
auto self = static_cast<filesystem_extractor_*>(client_data);
self->out_.reset();
return ARCHIVE_OK;
}
void configure_format(filesystem_extractor_archive_format const& format
[[maybe_unused]],
std::filesystem::path const* output
@ -301,7 +324,9 @@ class filesystem_extractor_ final : public filesystem_extractor::impl {
LOG_PROXY_DECL(debug_logger_policy);
os_access const& os_;
std::shared_ptr<file_access const> fa_;
struct ::archive* a_{nullptr};
std::unique_ptr<output_stream> out_;
std::array<int, 2> pipefd_{-1, -1};
std::unique_ptr<std::thread> iot_;
};
@ -560,10 +585,12 @@ std::string filesystem_extractor_archive_format::description() const {
return desc;
}
filesystem_extractor::filesystem_extractor(logger& lgr, os_access const& os)
filesystem_extractor::filesystem_extractor(
logger& lgr, os_access const& os, std::shared_ptr<file_access const> fa)
: impl_(make_unique_logging_object<filesystem_extractor::impl,
internal::filesystem_extractor_,
logger_policies>(lgr, os)) {}
logger_policies>(lgr, os,
std::move(fa))) {}
void filesystem_extractor::add_library_dependencies(
library_dependencies& deps) {

View File

@ -2289,6 +2289,30 @@ TEST(dwarfsextract_test, filters) {
EXPECT_EQ(ARCHIVE_OK, ::archive_read_free(ar)) << ::archive_error_string(ar);
}
TEST(dwarfsextract_test, auto_format) {
auto t = dwarfsextract_tester::create_with_image();
ASSERT_EQ(0, t.run({"-i", "image.dwarfs", "-f", "auto", "-o", "image.tar"}))
<< t.err();
auto out = t.fa->get_file("image.tar").value();
auto ar = ::archive_read_new();
ASSERT_EQ(ARCHIVE_OK, ::archive_read_support_format_all(ar))
<< ::archive_error_string(ar);
ASSERT_EQ(ARCHIVE_OK, ::archive_read_open_memory(ar, out.data(), out.size()))
<< ::archive_error_string(ar);
struct archive_entry* entry;
int ret = ::archive_read_next_header(ar, &entry);
EXPECT_EQ(ARCHIVE_OK, ret) << ::archive_error_string(ar);
auto fmt = ::archive_format(ar);
EXPECT_EQ(ARCHIVE_FORMAT_TAR, fmt & ARCHIVE_FORMAT_BASE_MASK) << fmt::format(
"expected TAR ({:08x}), got {:08x}", ARCHIVE_FORMAT_TAR, fmt);
EXPECT_EQ(ARCHIVE_OK, ::archive_read_free(ar)) << ::archive_error_string(ar);
}
TEST(dwarfsextract_test, patterns) {
auto mkdt = mkdwarfs_tester::create_empty();
mkdt.add_test_file_tree();

View File

@ -211,7 +211,7 @@ int dwarfsextract_main(int argc, sys_char** argv, iolayer const& iol) {
#endif
reader::filesystem_v2_lite fs(lgr, *iol.os, fs_image, fsopts, perfmon);
utility::filesystem_extractor fsx(lgr, *iol.os);
utility::filesystem_extractor fsx(lgr, *iol.os, iol.file);
#ifndef DWARFS_FILESYSTEM_EXTRACTOR_NO_OPEN_FORMAT
if (format.name.empty()) {