diff --git a/include/dwarfs/metadata_v2.h b/include/dwarfs/metadata_v2.h index eb68ac34..79a5f216 100644 --- a/include/dwarfs/metadata_v2.h +++ b/include/dwarfs/metadata_v2.h @@ -66,10 +66,20 @@ class entry_view class directory_view : public ::apache::thrift::frozen::View { public: - directory_view(::apache::thrift::frozen::View dv) - : ::apache::thrift::frozen::View(dv) {} + directory_view( + ::apache::thrift::frozen::View dv, + ::apache::thrift::frozen::MappedFrozen const* + meta) + : ::apache::thrift::frozen::View(dv) + , meta_(meta) {} boost::integer_range entry_range() const; + + uint32_t self_inode(); + + private: + ::apache::thrift::frozen::MappedFrozen const* + meta_; }; class metadata_v2 { @@ -115,6 +125,11 @@ class metadata_v2 { return impl_->opendir(de); } + std::optional> + readdir(directory_view d, size_t offset) const { + return impl_->readdir(d, offset); + } + #if 0 size_t block_size() const { return impl_->block_size(); } @@ -124,11 +139,6 @@ class metadata_v2 { return impl_->access(de, mode, uid, gid); } - entry_view - readdir(directory_view d, size_t offset, std::string* name) const { - return impl_->readdir(d, offset, name); - } - size_t dirsize(directory_view d) const { return impl_->dirsize(d); } int readlink(entry_view de, char* buf, size_t size) const { @@ -170,13 +180,14 @@ class metadata_v2 { virtual std::optional opendir(entry_view de) const = 0; + virtual std::optional> + readdir(directory_view d, size_t offset) const = 0; + #if 0 virtual size_t block_size() const = 0; virtual unsigned block_size_bits() const = 0; virtual int access(entry_view de, int mode, uid_t uid, gid_t gid) const = 0; - virtual entry_view - readdir(directory_view d, size_t offset, std::string* name) const = 0; virtual size_t dirsize(directory_view d) const = 0; virtual int readlink(entry_view de, char* buf, size_t size) const = 0; virtual int readlink(entry_view de, std::string* buf) const = 0; diff --git a/src/dwarfs/metadata_v2.cpp b/src/dwarfs/metadata_v2.cpp index 492e304e..d51c0628 100644 --- a/src/dwarfs/metadata_v2.cpp +++ b/src/dwarfs/metadata_v2.cpp @@ -21,7 +21,7 @@ #include -#include +#include #include @@ -54,6 +54,17 @@ boost::integer_range directory_view::entry_range() const { return boost::irange(first, first + entry_count()); } +uint32_t directory_view::self_inode() { + auto pos = getPosition().bitOffset; + if (pos > 0) { + // XXX: this is evil trickery... + auto one = meta_->directories()[1].getPosition().bitOffset; + assert(pos % one == 0); + pos /= one; + } + return pos; +} + template class metadata_v2_ : public metadata_v2::impl { public: @@ -96,6 +107,9 @@ class metadata_v2_ : public metadata_v2::impl { std::optional opendir(entry_view entry) const override; + std::optional> + readdir(directory_view dir, size_t offset) const override; + #if 0 size_t block_size() const override { return static_cast(1) << cfg_->block_size_bits; @@ -105,8 +119,6 @@ class metadata_v2_ : public metadata_v2::impl { int access(entry_view entry, int mode, uid_t uid, gid_t gid) const override; - entry_view - readdir(directory_view d, size_t offset, std::string* name) const override; size_t dirsize(directory_view d) const override { return d->count + 2; // adds '.' and '..', which we fake in ;-) } @@ -123,8 +135,12 @@ class metadata_v2_ : public metadata_v2::impl { return entry_view(meta_.entries()[index], &meta_); } + entry_view make_entry_view_from_inode(uint32_t inode) const { + return make_entry_view(meta_.entry_index()[inode]); + } + directory_view make_directory_view(size_t index) const { - return directory_view(meta_.directories()[index]); + return directory_view(meta_.directories()[index], &meta_); } void dump(std::ostream& os, const std::string& indent, entry_view entry, @@ -170,7 +186,7 @@ class metadata_v2_ : public metadata_v2::impl { inode -= inode_offset_; std::optional rv; if (inode >= 0 && inode < int(meta_.entry_index().size())) { - rv = make_entry_view(meta_.entry_index()[inode]); + rv = make_entry_view_from_inode(inode); } return rv; } @@ -228,7 +244,9 @@ void metadata_v2_::dump( std::function const& icb) const { auto count = dir.entry_count(); auto first = dir.first_entry(); - os << indent << "(" << count << ") entries\n"; + + os << indent << "(" << count << ") entries [" << dir.self_inode() << ":" + << dir.parent_inode() << "]\n"; for (size_t i = 0; i < count; ++i) { dump(os, indent, make_entry_view(first + i), icb); @@ -380,6 +398,31 @@ metadata_v2_::opendir(entry_view entry) const { return rv; } +template +std::optional> +metadata_v2_::readdir(directory_view dir, size_t offset) const { + switch (offset) { + case 0: + return std::pair(make_entry_view_from_inode(dir.self_inode()), "."); + + case 1: + return std::pair(make_entry_view_from_inode(dir.parent_inode()), ".."); + + default: + offset -= 2; + + if (offset >= dir.entry_count()) { + break; + } + + auto entry = make_entry_view(dir.first_entry() + offset); + + return std::pair(entry, entry.name()); + } + + return std::nullopt; +} + #if 0 template int metadata_v2_::access(entry_view entry, int mode, uid_t uid, @@ -396,44 +439,6 @@ int metadata_v2_::open(entry_view entry) const { return -1; } -template -entry_view -metadata_v2_::readdir(directory_view d, size_t offset, - std::string* name) const { - entry_view entry; - - switch (offset) { - case 0: - entry = as(d->self); - - if (name) { - name->assign("."); - } - break; - - case 1: - entry = as(d->parent); - - if (name) { - name->assign(".."); - } - break; - - default: - offset -= 2; - - if (offset < d->count) { - entry = dir_reader_->readdir(d, offset, name); - } else { - return nullptr; - } - - break; - } - - return entry; -} - template int metadata_v2_::readlink(entry_view entry, char* buf, size_t size) const {