diff --git a/doc/dwarfsextract.md b/doc/dwarfsextract.md index 5390ca18..da03d12e 100644 --- a/doc/dwarfsextract.md +++ b/doc/dwarfsextract.md @@ -67,6 +67,12 @@ to disk: if no output directory is specified). For a full list of supported formats, see libarchive-formats(5). +- `--format-options=`*options*: + + Comma-separated libarchive options for the specific output format. + The options are passed to libarchive. For a full list of options for each + output format, see archive_write_set_options(3). + - `--continue-on-error`: Try to continue with extraction even when errors are encountered. This only applies to errors when reading from the file system image. Errors diff --git a/include/dwarfs/utility/filesystem_extractor.h b/include/dwarfs/utility/filesystem_extractor.h index 7d5c91d1..33ee7806 100644 --- a/include/dwarfs/utility/filesystem_extractor.h +++ b/include/dwarfs/utility/filesystem_extractor.h @@ -63,12 +63,14 @@ class filesystem_extractor { static void add_library_dependencies(library_dependencies& deps); void - open_archive(std::filesystem::path const& output, std::string const& format) { - impl_->open_archive(output, format); + open_archive(std::filesystem::path const& output, std::string const& format, + std::string const& format_options = "") { + impl_->open_archive(output, format, format_options); } - void open_stream(std::ostream& os, std::string const& format) { - impl_->open_stream(os, format); + void open_stream(std::ostream& os, std::string const& format, + std::string const& format_options = "") { + impl_->open_stream(os, format, format_options); } void open_disk(std::filesystem::path const& output) { @@ -94,9 +96,11 @@ class filesystem_extractor { public: virtual ~impl() = default; - virtual void open_archive(std::filesystem::path const& output, - std::string const& format) = 0; - virtual void open_stream(std::ostream& os, std::string const& format) = 0; + virtual void + open_archive(std::filesystem::path const& output, std::string const& format, + std::string const& format_options = "") = 0; + virtual void open_stream(std::ostream& os, std::string const& format, + std::string const& format_options) = 0; virtual void open_disk(std::filesystem::path const& output) = 0; virtual void close() = 0; virtual bool diff --git a/src/utility/filesystem_extractor.cpp b/src/utility/filesystem_extractor.cpp index dc60735c..9bef0c9e 100644 --- a/src/utility/filesystem_extractor.cpp +++ b/src/utility/filesystem_extractor.cpp @@ -122,16 +122,20 @@ class filesystem_extractor_ final : public filesystem_extractor::impl { } } - void open_archive(std::filesystem::path const& output [[maybe_unused]], - std::string const& format [[maybe_unused]]) override { + void + open_archive(std::filesystem::path const& output [[maybe_unused]], + std::string const& format [[maybe_unused]], + std::string const& format_options [[maybe_unused]]) override { #ifdef DWARFS_FILESYSTEM_EXTRACTOR_NO_OPEN_FORMAT DWARFS_THROW(runtime_error, "open_archive() not supported in this build"); #else - LOG_DEBUG << "opening archive file in " << format << " format"; + LOG_DEBUG << "opening archive file in " << format + << " format with options '" << format_options << "'"; a_ = ::archive_write_new(); check_result(::archive_write_set_format_by_name(a_, format.c_str())); + check_result(::archive_write_set_options(a_, format_options.c_str())); check_result(::archive_write_set_bytes_in_last_block(a_, 1)); #ifdef _WIN32 @@ -144,8 +148,10 @@ class filesystem_extractor_ final : public filesystem_extractor::impl { #endif } - void open_stream(std::ostream& os [[maybe_unused]], - std::string const& format [[maybe_unused]]) override { + void + open_stream(std::ostream& os [[maybe_unused]], + std::string const& format [[maybe_unused]], + std::string const& format_options [[maybe_unused]]) override { #ifdef DWARFS_FILESYSTEM_EXTRACTOR_NO_OPEN_FORMAT DWARFS_THROW(runtime_error, "open_stream() not supported in this build"); #else @@ -162,11 +168,13 @@ class filesystem_extractor_ final : public filesystem_extractor::impl { iot_ = std::make_unique( [this, &os, fd = pipefd_[0]] { pump(os, fd); }); - LOG_DEBUG << "opening archive stream in " << format << " format"; + LOG_DEBUG << "opening archive stream in " << format + << " format with options '" << format_options << "'"; a_ = ::archive_write_new(); check_result(::archive_write_set_format_by_name(a_, format.c_str())); + check_result(::archive_write_set_options(a_, format_options.c_str())); check_result(::archive_write_set_bytes_in_last_block(a_, 1)); check_result(::archive_write_open_fd(a_, pipefd_[1])); #endif diff --git a/test/manpage_test.cpp b/test/manpage_test.cpp index 5382c41a..94e0f405 100644 --- a/test/manpage_test.cpp +++ b/test/manpage_test.cpp @@ -194,6 +194,7 @@ TEST_P(manpage_coverage_test, options) { if (tool_name == "dwarfsextract") { #ifdef DWARFS_FILESYSTEM_EXTRACTOR_NO_OPEN_FORMAT man_opts.erase("format"); + man_opts.erase("format-options"); #endif man_opts.erase("pattern"); } diff --git a/test/tool_main_test.cpp b/test/tool_main_test.cpp index ca8a3611..d8a005a0 100644 --- a/test/tool_main_test.cpp +++ b/test/tool_main_test.cpp @@ -2253,11 +2253,14 @@ INSTANTIATE_TEST_SUITE_P(dwarfs, mkdwarfs_progress_test, #ifndef DWARFS_FILESYSTEM_EXTRACTOR_NO_OPEN_FORMAT TEST(dwarfsextract_test, mtree) { auto t = dwarfsextract_tester::create_with_image(); - ASSERT_EQ(0, t.run({"-i", "image.dwarfs", "-f", "mtree"})) << t.err(); + ASSERT_EQ(0, t.run({"-i", "image.dwarfs", "-f", "mtree", "--format-options", + "mtree:sha256"})) + << t.err(); auto out = t.out(); EXPECT_TRUE(out.starts_with("#mtree")) << out; EXPECT_THAT(out, ::testing::HasSubstr("type=dir")); EXPECT_THAT(out, ::testing::HasSubstr("type=file")); + EXPECT_THAT(out, ::testing::HasSubstr("sha256digest=")); } TEST(dwarfsextract_test, patterns) { diff --git a/tools/src/dwarfsextract_main.cpp b/tools/src/dwarfsextract_main.cpp index ab53be0a..5f464e08 100644 --- a/tools/src/dwarfsextract_main.cpp +++ b/tools/src/dwarfsextract_main.cpp @@ -72,7 +72,7 @@ int dwarfsextract_main(int argc, sys_char** argv, iolayer const& iol) { std::string cache_size_str, image_offset; logger_options logopts; #ifndef DWARFS_FILESYSTEM_EXTRACTOR_NO_OPEN_FORMAT - std::string format; + std::string format, format_options; #endif #if DWARFS_PERFMON_ENABLED std::string perfmon_str; @@ -100,6 +100,9 @@ int dwarfsextract_main(int argc, sys_char** argv, iolayer const& iol) { ("format,f", po::value(&format), "output format") + ("format-options", + po::value(&format_options), + "comma-separated libarchive options for the specific output format") #endif ("continue-on-error", po::value(&continue_on_error)->zero_tokens(), @@ -228,9 +231,9 @@ int dwarfsextract_main(int argc, sys_char** argv, iolayer const& iol) { } if (stream) { - fsx.open_stream(*stream, format); + fsx.open_stream(*stream, format, format_options); } else { - fsx.open_archive(iol.os->canonical(output), format); + fsx.open_archive(iol.os->canonical(output), format, format_options); } } #endif