From 6fe9b69aad030d58267b97210989bdf08fb5c0f4 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 28 Aug 2021 10:27:45 -0700 Subject: [PATCH] Cleanup module.cpp --- native/jni/core/module.cpp | 199 +++++++++++++++++++------------------ 1 file changed, 102 insertions(+), 97 deletions(-) diff --git a/native/jni/core/module.cpp b/native/jni/core/module.cpp index 5b1c17999..913fc8a5e 100644 --- a/native/jni/core/module.cpp +++ b/native/jni/core/module.cpp @@ -15,11 +15,11 @@ using namespace std; #define TYPE_MIRROR (1 << 0) /* mount from mirror */ #define TYPE_INTER (1 << 1) /* intermediate node */ -#define TYPE_SKEL (1 << 2) /* replace with tmpfs */ +#define TYPE_TMPFS (1 << 2) /* replace with tmpfs */ #define TYPE_MODULE (1 << 3) /* mount from module */ #define TYPE_ROOT (1 << 4) /* partition root */ #define TYPE_CUSTOM (1 << 5) /* custom node type overrides all */ -#define TYPE_DIR (TYPE_INTER|TYPE_SKEL|TYPE_ROOT) +#define TYPE_DIR (TYPE_INTER|TYPE_TMPFS|TYPE_ROOT) static vector module_list; @@ -27,11 +27,10 @@ class node_entry; class dir_node; class inter_node; class mirror_node; -class skel_node; +class tmpfs_node; class module_node; class root_node; -static void merge_node(node_entry *a, node_entry *b); template static bool isa(node_entry *node); static int bind_mount(const char *from, const char *to) { int ret = xmount(from, to, nullptr, MS_BIND, nullptr); @@ -44,7 +43,7 @@ template uint8_t type_id() { return TYPE_CUSTOM; } template<> uint8_t type_id() { return TYPE_DIR; } template<> uint8_t type_id() { return TYPE_INTER; } template<> uint8_t type_id() { return TYPE_MIRROR; } -template<> uint8_t type_id() { return TYPE_SKEL; } +template<> uint8_t type_id() { return TYPE_TMPFS; } template<> uint8_t type_id() { return TYPE_MODULE; } template<> uint8_t type_id() { return TYPE_ROOT; } @@ -52,18 +51,18 @@ class node_entry { public: virtual ~node_entry() = default; + // Node info bool is_dir() { return file_type() == DT_DIR; } bool is_lnk() { return file_type() == DT_LNK; } bool is_reg() { return file_type() == DT_REG; } - uint8_t type() { return node_type; } const string &name() { return _name; } - - // Paths const string &node_path(); string mirror_path() { return mirror_dir + node_path(); } + // Tree methods dir_node *parent() { return _parent; } + void merge(node_entry *other); virtual void mount() = 0; @@ -76,20 +75,19 @@ protected: : _name(name), _file_type(file_type), node_type(type_id()) {} template - explicit node_entry(T*) : node_type(type_id()) {} + explicit node_entry(T*) : _file_type(0), node_type(type_id()) {} void create_and_mount(const string &src); - /* Use top bit of _file_type for node exist status */ + // Use top bit of _file_type for node exist status bool exist() { return static_cast(_file_type & (1 << 7)); } void set_exist(bool b) { if (b) _file_type |= (1 << 7); else _file_type &= ~(1 << 7); } uint8_t file_type() { return static_cast(_file_type & ~(1 << 7)); } private: - friend void merge_node(node_entry *a, node_entry *b); friend class dir_node; - bool need_skel_upgrade(node_entry *child); + static bool should_be_tmpfs(node_entry *child); // Node properties string _name; @@ -104,10 +102,10 @@ private: class dir_node : public node_entry { public: - friend void merge_node(node_entry *a, node_entry *b); + friend void node_entry::merge(node_entry *other); - typedef map map_type; - typedef map_type::iterator map_iter; + using map_type = map; + using iterator = map_type::iterator; ~dir_node() override { for (auto &it : children) @@ -134,7 +132,7 @@ public: bool is_empty() { return children.empty(); } template - T *child(string_view name) { return iter_to_node(children.find(name)); } + T *child(string_view name) { return iterator_to_node(children.find(name)); } // Lazy val root_node *root() { @@ -148,30 +146,28 @@ public: // Return false if rejected bool insert(node_entry *node) { - return node - ? iter_to_node(insert(children.find(node->_name), node->node_type, - [=](auto _) { return node; })) != nullptr - : false; + auto fn = [=](auto) { return node; }; + return node && iterator_to_node(insert(node->_name, node->node_type, fn)); } // Return inserted node or null if rejected template T *emplace(string_view name, Args &&...args) { - return iter_to_node(insert(children.find(name), type_id(), - [&](auto _) { return new T(std::forward(args)...); })); + auto fn = [&](auto) { return new T(std::forward(args)...); }; + return iterator_to_node(insert(name, type_id(), fn)); } - // Return inserted node, existing node with same rank, or null + // Return inserted node, existing node with same rank, or null if rejected template T *emplace_or_get(string_view name, Args &&...args) { - return iter_to_node(insert(children.find(name), type_id(), - [&](auto _) { return new T(std::forward(args)...); }, true)); + auto fn = [&](auto) { return new T(std::forward(args)...); }; + return iterator_to_node(insert(name, type_id(), fn, true)); } // Return upgraded node or null if rejected template T *upgrade(string_view name, Args &...args) { - return iter_to_node(upgrade(children.find(name), args...)); + return iterator_to_node(upgrade(children.find(name), args...)); } protected: @@ -183,7 +179,7 @@ protected: template dir_node(node_entry *node, T *self) : node_entry(self) { - merge_node(this, node); + merge(node); if constexpr (std::is_same_v) _root = self; } @@ -192,33 +188,27 @@ protected: dir_node(const char *name, T *self) : dir_node(name, DT_DIR, self) {} template - T *iter_to_node(const map_iter &it) { - return reinterpret_cast(it == children.end() ? nullptr : it->second); + T *iterator_to_node(iterator it) { + return static_cast(it == children.end() ? nullptr : it->second); } - /* fn signature: (node_ent *&) -> node_ent * - * fn gets reference to the existing node, may be null. - * If fn consumes input, need to set reference to null. - * Returns new node or null to reject the insertion. */ + // Emplace insert a new node, or upgrade if the requested type has a higher rank. + // Return iterator to new node or end() if insertion is rejected. + // If get_same is true and a node with the same rank exists, it will return that node instead. + // fn is the node construction callback. Signature: (node_ent *&) -> node_ent * + // fn gets a reference to the existing node pointer and returns a new node object. + // Input is null when there is no existing node. If returns null, the insertion is rejected. + // If fn consumes the input, it should set the reference to null. + template + iterator insert(iterator it, uint8_t type, const Func &fn, bool get_same); template - map_iter insert(map_iter it, uint8_t type, Func fn, bool allow_same = false); + iterator insert(string_view name, uint8_t type, const Func &fn, bool get_same = false) { + return insert(children.find(name), type, fn, get_same); + } template - map_iter upgrade(map_iter it, Args &&...args) { - return insert(it, type_id(), [&](node_entry *&ex) -> node_entry * { - if (!ex) - return nullptr; - if constexpr (!std::is_same_v) { - // Type check if specific type is selected - if (!isa(ex)) - return nullptr; - } - auto node = new To(reinterpret_cast(ex), std::forward(args)...); - ex = nullptr; - return node; - }); - } + iterator upgrade(iterator it, Args &&...args); // dir nodes host children map_type children; @@ -248,7 +238,7 @@ public: : node_entry(entry->d_name, entry->d_type, this), module(module) {} module_node(node_entry *node, const char *module) : node_entry(this), module(module) { - merge_node(this, node); + merge(node); } explicit module_node(inter_node *node) : module_node(node, node->module) {} @@ -266,9 +256,9 @@ public: } }; -class skel_node : public dir_node { +class tmpfs_node : public dir_node { public: - explicit skel_node(node_entry *node); + explicit tmpfs_node(node_entry *node); void mount() override; }; @@ -279,29 +269,29 @@ static bool isa(node_entry *node) { } template static T *dyn_cast(node_entry *node) { - return isa(node) ? reinterpret_cast(node) : nullptr; -} - -// Merge b -> a, b will be deleted -static void merge_node(node_entry *a, node_entry *b) { - a->_name.swap(b->_name); - a->_file_type = b->_file_type; - a->_parent = b->_parent; - - // Merge children if both is dir - if (auto aa = dyn_cast(a); aa) { - if (auto bb = dyn_cast(b); bb) { - aa->children.merge(bb->children); - for (auto &pair : aa->children) - pair.second->_parent = aa; - } - } - delete b; + return isa(node) ? static_cast(node) : nullptr; } string node_entry::module_mnt; string node_entry::mirror_dir; +// other will be deleted +void node_entry::merge(node_entry *other) { + _name.swap(other->_name); + _file_type = other->_file_type; + _parent = other->_parent; + + // Merge children if both is dir + if (auto a = dyn_cast(this)) { + if (auto b = dyn_cast(other)) { + a->children.merge(b->children); + for (auto &pair : a->children) + pair.second->_parent = a; + } + } + delete other; +} + const string &node_entry::node_path() { if (_parent && _node_path.empty()) _node_path = _parent->node_path() + '/' + _name; @@ -313,16 +303,16 @@ const string &node_entry::node_path() { *************************/ template -dir_node::map_iter dir_node::insert(dir_node::map_iter it, uint8_t type, Func fn, bool allow_same) { +dir_node::iterator dir_node::insert(iterator it, uint8_t type, const Func &fn, bool get_same) { node_entry *node = nullptr; if (it != children.end()) { + // Upgrade existing node only if higher rank if (it->second->node_type < type) { - // Upgrade existing node only if higher precedence node = fn(it->second); if (!node) return children.end(); if (it->second) - merge_node(node, it->second); + node->merge(it->second); it = children.erase(it); // Minor optimization to make insert O(1) by using hint if (it == children.begin()) @@ -330,20 +320,36 @@ dir_node::map_iter dir_node::insert(dir_node::map_iter it, uint8_t type, Func fn else it = children.emplace_hint(--it, node->_name, node); } else { - if (allow_same && it->second->node_type == type) + if (get_same && it->second->node_type == type) return it; return children.end(); } } else { node = fn(node); if (!node) - return it; + return children.end(); node->_parent = this; it = children.emplace(node->_name, node).first; } return it; } +template +dir_node::iterator dir_node::upgrade(iterator it, Args &&... args) { + return insert(it, type_id(), [&](node_entry *&ex) -> node_entry * { + if (!ex) + return nullptr; + if constexpr (!std::is_same_v) { + // Type check if type is specified + if (!isa(ex)) + return nullptr; + } + auto node = new To(static_cast(ex), std::forward(args)...); + ex = nullptr; + return node; + }, false); +} + node_entry* dir_node::extract(string_view name) { auto it = children.find(name); if (it != children.end()) { @@ -354,9 +360,9 @@ node_entry* dir_node::extract(string_view name) { return nullptr; } -skel_node::skel_node(node_entry *node) : dir_node(node, this) { +tmpfs_node::tmpfs_node(node_entry *node) : dir_node(node, this) { string mirror = mirror_path(); - if (auto dir = open_dir(mirror.data()); dir) { + if (auto dir = open_dir(mirror.data())) { set_exist(true); for (dirent *entry; (entry = xreaddir(dir.get()));) { // Insert mirror nodes @@ -370,40 +376,39 @@ skel_node::skel_node(node_entry *node) : dir_node(node, this) { } for (auto it = children.begin(); it != children.end(); ++it) { - // Need to upgrade all inter_node children to skel_node + // Need to upgrade all inter_node children to tmpfs_node if (isa(it->second)) - it = upgrade(it); + it = upgrade(it); } } -bool node_entry::need_skel_upgrade(node_entry *child) { - /* We need to upgrade to skeleton if: - * - Target does not exist - * - Source or target is a symlink */ - bool upgrade = false; +// We need to upgrade to tmpfs node if any child: +// - Target does not exist +// - Source or target is a symlink +bool node_entry::should_be_tmpfs(node_entry *child) { struct stat st; if (lstat(child->node_path().data(), &st) != 0) { - upgrade = true; + return true; } else { child->set_exist(true); if (child->is_lnk() || S_ISLNK(st.st_mode)) - upgrade = true; + return true; } - return upgrade; + return false; } bool dir_node::prepare() { - bool to_skel = false; + bool to_tmpfs = false; for (auto it = children.begin(); it != children.end();) { - if (need_skel_upgrade(it->second)) { - if (node_type > type_id()) { + if (should_be_tmpfs(it->second)) { + if (node_type > type_id()) { // Upgrade will fail, remove the unsupported child node delete it->second; it = children.erase(it); continue; } - // Tell parent to upgrade self to skel - to_skel = true; + // Tell parent to upgrade self to tmpfs + to_tmpfs = true; // If child is inter_node, upgrade to module if (auto nit = upgrade(it); nit != children.end()) { it = nit; @@ -411,13 +416,13 @@ bool dir_node::prepare() { } } if (auto dn = dyn_cast(it->second); dn && dn->is_dir() && !dn->prepare()) { - // Upgrade child to skeleton - it = upgrade(it); + // Upgrade child to tmpfs + it = upgrade(it); } next_node: ++it; } - return !to_skel; + return !to_tmpfs; } bool dir_node::collect_files(const char *module, int dfd) { @@ -469,13 +474,13 @@ void module_node::mount() { string src = module_mnt + module + parent()->root()->prefix + node_path(); if (exist()) clone_attr(mirror_path().data(), src.data()); - if (isa(parent())) + if (isa(parent())) create_and_mount(src); else if (is_dir() || is_reg()) bind_mount(src.data(), node_path().data()); } -void skel_node::mount() { +void tmpfs_node::mount() { if (!exist()) return; string src = mirror_path(); @@ -483,7 +488,7 @@ void skel_node::mount() { file_attr a; getattr(src.data(), &a); mkdir(dest.data(), 0); - if (!isa(parent())) { + if (!isa(parent())) { // We don't need another layer of tmpfs if parent is skel xmount("tmpfs", dest.data(), "tmpfs", 0, nullptr); VLOGD("mnt_tmp", "tmpfs", dest.data());