From 3f5c84a67a1e3520b61a009e1982a2ffa6a81d31 Mon Sep 17 00:00:00 2001 From: Marcus Holland-Moritz Date: Sun, 6 Dec 2020 16:53:00 +0100 Subject: [PATCH] Add metadata-as-JSON support to dwarfsck --- include/dwarfs/filesystem_v2.h | 6 +++ include/dwarfs/metadata_v2.h | 7 ++++ src/dwarfs/filesystem_v2.cpp | 6 +++ src/dwarfs/metadata_v2.cpp | 75 ++++++++++++++++++++++++++++++++++ src/dwarfsck.cpp | 12 +++++- 5 files changed, 105 insertions(+), 1 deletion(-) diff --git a/include/dwarfs/filesystem_v2.h b/include/dwarfs/filesystem_v2.h index 518d33c5..390974eb 100644 --- a/include/dwarfs/filesystem_v2.h +++ b/include/dwarfs/filesystem_v2.h @@ -33,6 +33,7 @@ #include +#include #include #include "dwarfs/metadata_types.h" @@ -69,6 +70,10 @@ class filesystem_v2 { impl_->dump(os, detail_level); } + folly::dynamic metadata_as_dynamic() const { + return impl_->metadata_as_dynamic(); + } + void walk(std::function const& func) const { impl_->walk(func); } @@ -128,6 +133,7 @@ class filesystem_v2 { virtual ~impl() = default; virtual void dump(std::ostream& os, int detail_level) const = 0; + virtual folly::dynamic metadata_as_dynamic() const = 0; virtual void walk(std::function const& func) const = 0; virtual std::optional find(const char* path) const = 0; virtual std::optional find(int inode) const = 0; diff --git a/include/dwarfs/metadata_v2.h b/include/dwarfs/metadata_v2.h index 2845ec58..f12fde1c 100644 --- a/include/dwarfs/metadata_v2.h +++ b/include/dwarfs/metadata_v2.h @@ -34,6 +34,7 @@ #include +#include #include #include @@ -68,6 +69,10 @@ class metadata_v2 { impl_->dump(os, detail_level, icb); } + folly::dynamic as_dynamic() const { + return impl_->as_dynamic(); + } + static void get_stat_defaults(struct ::stat* defaults); // TODO: check if this is needed @@ -138,6 +143,8 @@ class metadata_v2 { std::ostream& os, int detail_level, std::function const& icb) const = 0; + virtual folly::dynamic as_dynamic() const = 0; + virtual size_t size() const = 0; virtual bool empty() const = 0; diff --git a/src/dwarfs/filesystem_v2.cpp b/src/dwarfs/filesystem_v2.cpp index 1f884157..8fdc6f37 100644 --- a/src/dwarfs/filesystem_v2.cpp +++ b/src/dwarfs/filesystem_v2.cpp @@ -195,6 +195,7 @@ class filesystem_ : public filesystem_v2::impl { const struct ::stat* stat_defaults, int inode_offset); void dump(std::ostream& os, int detail_level) const override; + folly::dynamic metadata_as_dynamic() const override; void walk(std::function const& func) const override; std::optional find(const char* path) const override; std::optional find(int inode) const override; @@ -273,6 +274,11 @@ void filesystem_::dump(std::ostream& os, int detail_level) const { }); } +template +folly::dynamic filesystem_::metadata_as_dynamic() const { + return meta_.as_dynamic(); +} + template void filesystem_::walk( std::function const& func) const { diff --git a/src/dwarfs/metadata_v2.cpp b/src/dwarfs/metadata_v2.cpp index c4351739..e897dd83 100644 --- a/src/dwarfs/metadata_v2.cpp +++ b/src/dwarfs/metadata_v2.cpp @@ -158,6 +158,8 @@ class metadata_ : public metadata_v2::impl { std::function const& icb) const override; + folly::dynamic as_dynamic() const override; + size_t size() const override { return data_.size(); } bool empty() const override { return data_.empty(); } @@ -275,6 +277,9 @@ class metadata_ : public metadata_v2::impl { int detail_level, std::function const& icb) const; + folly::dynamic as_dynamic(entry_view entry) const; + folly::dynamic as_dynamic(directory_view dir) const; + std::optional find(directory_view dir, std::string_view name) const; @@ -439,6 +444,76 @@ void metadata_::dump( } } +template +folly::dynamic metadata_::as_dynamic(directory_view dir) const { + folly::dynamic obj = folly::dynamic::array; + + auto count = dir.entry_count(); + auto first = dir.first_entry(); + + for (size_t i = 0; i < count; ++i) { + obj.push_back(as_dynamic(make_entry_view(first + i))); + } + + return obj; +} + +template +folly::dynamic metadata_::as_dynamic(entry_view entry) const { + folly::dynamic obj = folly::dynamic::object; + + auto mode = entry.mode(); + auto inode = entry.inode(); + + obj["mode"] = mode; + obj["modestring"] = modestring(mode); + obj["inode"] = inode; + + if (inode > 0) { + obj["name"] = std::string(entry.name()); + } + + if (S_ISREG(mode)) { + obj["type"] = "file"; + obj["size"] = file_size(entry, mode); + } else if (S_ISDIR(mode)) { + obj["type"] = "directory"; + obj["entries"] = as_dynamic(make_directory_view(entry)); + } else if (S_ISLNK(mode)) { + obj["type"] = "link"; + obj["target"] = std::string(link_value(entry)); + } else if (S_ISBLK(mode)) { + obj["type"] = "blockdev"; + obj["device_id"] = get_device_id(inode); + } else if (S_ISCHR(mode)) { + obj["type"] = "chardev"; + obj["device_id"] = get_device_id(inode); + } else if (S_ISFIFO(mode)) { + obj["type"] = "fifo"; + } else if (S_ISSOCK(mode)) { + obj["type"] = "socket"; + } + + return obj; +} + +template +folly::dynamic metadata_::as_dynamic() const { + folly::dynamic obj = folly::dynamic::object; + + struct ::statvfs stbuf; + statvfs(&stbuf); + + obj["statvfs"] = folly::dynamic::object + ("f_bsize", stbuf.f_bsize) + ("f_files", stbuf.f_files) + ("f_blocks", stbuf.f_blocks); + + obj["root"] = as_dynamic(root_); + + return obj; +} + template std::string metadata_::modestring(uint16_t mode) const { std::ostringstream oss; diff --git a/src/dwarfsck.cpp b/src/dwarfsck.cpp index 6b0b12a8..1a602178 100644 --- a/src/dwarfsck.cpp +++ b/src/dwarfsck.cpp @@ -24,6 +24,7 @@ #include +#include #include #include "dwarfs/filesystem_v2.h" @@ -38,6 +39,7 @@ namespace po = boost::program_options; int dwarfsck(int argc, char** argv) { std::string log_level, input; int detail; + bool json; // clang-format off po::options_description opts("Command line options"); @@ -48,6 +50,9 @@ int dwarfsck(int argc, char** argv) { ("detail,d", po::value(&detail)->default_value(1), "detail level") + ("json", + po::value(&json)->zero_tokens(), + "print metadata in JSON format") ("log-level", po::value(&log_level)->default_value("info"), "log level (error, warn, info, debug, trace)") @@ -74,7 +79,12 @@ int dwarfsck(int argc, char** argv) { auto mm = std::make_shared(input); - dwarfs::filesystem_v2::identify(lgr, mm, std::cout, detail); + if (json) { + dwarfs::filesystem_v2 fs(lgr, mm); + std::cout << folly::toPrettyJson(fs.metadata_as_dynamic()) << std::endl; + } else { + dwarfs::filesystem_v2::identify(lgr, mm, std::cout, detail); + } return 0; }