From 34b3de12c2fa3003aa951d497f94f91ebaa7aa30 Mon Sep 17 00:00:00 2001 From: Marcus Holland-Moritz Date: Thu, 3 Dec 2020 00:50:51 +0100 Subject: [PATCH] Add --remove-empty-dirs option to mkdwarfs --- include/dwarfs/entry.h | 2 ++ include/dwarfs/options.h | 3 ++- src/dwarfs.cpp | 16 +++++++++------- src/dwarfs/entry.cpp | 18 ++++++++++++++++++ src/dwarfs/scanner.cpp | 6 ++++++ src/mkdwarfs.cpp | 3 +++ 6 files changed, 40 insertions(+), 8 deletions(-) diff --git a/include/dwarfs/entry.h b/include/dwarfs/entry.h index 7eec1e25..e2bbab9d 100644 --- a/include/dwarfs/entry.h +++ b/include/dwarfs/entry.h @@ -134,6 +134,8 @@ class dir : public entry { global_entry_data const& data) const; uint32_t inode_num() const override { return inode_; } void scan(os_access& os, progress& prog) override; + bool empty() const { return entries_.empty(); } + void remove_empty_dirs(progress& prog); private: using entry_ptr = std::shared_ptr; diff --git a/include/dwarfs/options.h b/include/dwarfs/options.h index dd9ea502..f8c8ac14 100644 --- a/include/dwarfs/options.h +++ b/include/dwarfs/options.h @@ -49,10 +49,11 @@ struct filesystem_options { enum class file_order_mode { NONE, PATH, SCRIPT, SIMILARITY }; struct scanner_options { - file_order_mode file_order; + file_order_mode file_order{file_order_mode::NONE}; std::optional uid; std::optional gid; std::optional timestamp; + bool remove_empty_dirs{false}; }; std::ostream& operator<<(std::ostream& os, file_order_mode mode); diff --git a/src/dwarfs.cpp b/src/dwarfs.cpp index c6a38aac..840928c5 100644 --- a/src/dwarfs.cpp +++ b/src/dwarfs.cpp @@ -501,18 +501,20 @@ int main(int argc, char* argv[]) { fuse_opt_parse(&args, &s_opts, dwarfs_opts, option_hdl); - s_opts.cachesize = s_opts.cachesize_str ? parse_size_with_unit(s_opts.cachesize_str) - : (static_cast(512) << 20); + s_opts.cachesize = s_opts.cachesize_str + ? parse_size_with_unit(s_opts.cachesize_str) + : (static_cast(512) << 20); // TODO: foreground mode, stderr vs. syslog? s_opts.debuglevel = s_opts.debuglevel_str - ? logger::parse_level(s_opts.debuglevel_str) - : logger::INFO; - s_opts.workers = s_opts.workers_str ? folly::to(s_opts.workers_str) : 2; + ? logger::parse_level(s_opts.debuglevel_str) + : logger::INFO; + s_opts.workers = + s_opts.workers_str ? folly::to(s_opts.workers_str) : 2; s_opts.lock_mode = s_opts.mlock_str ? parse_mlock_mode(s_opts.mlock_str) : mlock_mode::NONE; s_opts.decompress_ratio = s_opts.decompress_ratio_str - ? folly::to(s_opts.decompress_ratio_str) - : 0.8; + ? folly::to(s_opts.decompress_ratio_str) + : 0.8; s_lgr.set_threshold(s_opts.debuglevel); log_proxy log(s_lgr); diff --git a/src/dwarfs/entry.cpp b/src/dwarfs/entry.cpp index d6de18f5..ba0101ad 100644 --- a/src/dwarfs/entry.cpp +++ b/src/dwarfs/entry.cpp @@ -211,6 +211,24 @@ void dir::pack(thrift::metadata::metadata& mv2, } } +void dir::remove_empty_dirs(progress& prog) { + auto last = std::remove_if(entries_.begin(), entries_.end(), + [&](std::shared_ptr const& e) { + if (auto d = dynamic_cast(e.get())) { + d->remove_empty_dirs(prog); + return d->empty(); + } + return false; + }); + + if (last != entries_.end()) { + auto num = std::distance(last, entries_.end()); + prog.dirs_scanned -= num; + prog.dirs_found -= num; + entries_.erase(last, entries_.end()); + } +} + entry::type_t link::type() const { return E_LINK; } const std::string& link::linkname() const { return link_; } diff --git a/src/dwarfs/scanner.cpp b/src/dwarfs/scanner.cpp index 6414f7f1..19527c71 100644 --- a/src/dwarfs/scanner.cpp +++ b/src/dwarfs/scanner.cpp @@ -451,6 +451,12 @@ void scanner_::scan(filesystem_writer& fsw, auto root = scan_tree(path, prog); + if (options_.remove_empty_dirs) { + log_.info() << "removing empty directories..."; + auto d = dynamic_cast(root.get()); + d->remove_empty_dirs(prog); + } + // now scan all files scan_files_visitor sfv(wg_, *os_, prog); root->accept(sfv); diff --git a/src/mkdwarfs.cpp b/src/mkdwarfs.cpp index 1ee71418..3a245621 100644 --- a/src/mkdwarfs.cpp +++ b/src/mkdwarfs.cpp @@ -328,6 +328,9 @@ int mkdwarfs(int argc, char** argv) { po::value(&cfg.window_increment_shift) ->default_value(1), "window increment (as right shift of size)") + ("remove-empty-dirs", + po::value(&options.remove_empty_dirs)->zero_tokens(), + "remove empty directories in file system") ("log-level", po::value(&log_level)->default_value("info"), "log level (error, warn, info, debug, trace)")