| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIB_FDIO_NAMESPACE_LOCAL_VNODE_H_ |
| #define LIB_FDIO_NAMESPACE_LOCAL_VNODE_H_ |
| |
| #include <fidl/fuchsia.io/cpp/wire.h> |
| #include <lib/fdio/cleanpath.h> |
| #include <lib/fdio/namespace.h> |
| #include <lib/fit/function.h> |
| #include <lib/zx/channel.h> |
| #include <lib/zx/result.h> |
| #include <lib/zxio/types.h> |
| #include <limits.h> |
| #include <zircon/types.h> |
| |
| #include <utility> |
| |
| #include <fbl/intrusive_wavl_tree.h> |
| #include <fbl/macros.h> |
| #include <fbl/mutex.h> |
| #include <fbl/ref_counted.h> |
| #include <fbl/ref_ptr.h> |
| #include <fbl/string.h> |
| #include <fbl/string_buffer.h> |
| |
| #include "sdk/lib/fdio/internal.h" |
| |
| namespace fdio_internal { |
| |
| using EnumerateCallback = fit::function<zx_status_t(std::string_view path, zxio_t* entry)>; |
| |
| // Represents a mapping from a string name to a remote connection. |
| // |
| // Each LocalVnode may have named children, which themselves may also |
| // optionally represent remote connections. |
| // |
| // This class is thread-compatible. |
| class LocalVnode : public fbl::RefCounted<LocalVnode> { |
| public: |
| DISALLOW_COPY_ASSIGN_AND_MOVE(LocalVnode); |
| |
| // Initializes a new vnode with a remote node_type, and attaches a reference to it |
| // inside an (optional) parent. |
| template <class T, class... Args> |
| static zx::result<fbl::RefPtr<LocalVnode>> Create(fbl::RefPtr<LocalVnode> parent, |
| fbl::String name, |
| std::in_place_type_t<T> in_place, |
| Args&&... args) { |
| fbl::RefPtr vn = fbl::AdoptRef( |
| new LocalVnode(std::move(parent), std::move(name), in_place, std::forward<Args>(args)...)); |
| |
| if (vn->parent_ != nullptr) { |
| zx_status_t status = vn->parent_->AddChild(vn); |
| if (status != ZX_OK) { |
| return zx::error(status); |
| } |
| } |
| |
| return zx::ok(vn); |
| } |
| |
| // Recursively unlinks this Vnode's children, and detaches this node from |
| // its parent. |
| void Unlink(); |
| |
| // Detaches this vnode from its parent. The Vnode's own children are not unlinked. |
| void UnlinkFromParent(); |
| |
| // Returns the next child vnode from the list of children, assuming that |
| // |last_seen| is the ID of the last returned vnode. At the same time, |
| // |last_seen| is updated to reflect the current ID. |
| // |
| // If the end of iteration is reached, |out_vnode| is set to nullptr. |
| zx_status_t Readdir(uint64_t* last_seen, fbl::RefPtr<LocalVnode>* out_vnode) const; |
| |
| // Invoke |func| on the (path, channel) pairs for all remote nodes found in the |
| // node hierarchy rooted at `this`. |
| zx_status_t EnumerateRemotes(const EnumerateCallback& func) const; |
| |
| const fbl::String& Name() const { return name_; } |
| |
| struct IdTreeTag {}; |
| struct NameTreeTag {}; |
| |
| class Entry : public fbl::ContainableBaseClasses< |
| fbl::TaggedWAVLTreeContainable<std::unique_ptr<Entry>, IdTreeTag, |
| fbl::NodeOptions::AllowMultiContainerUptr>, |
| fbl::TaggedWAVLTreeContainable<Entry*, NameTreeTag>> { |
| public: |
| Entry(uint64_t id, fbl::RefPtr<LocalVnode> node) : id_(id), node_(std::move(node)) {} |
| ~Entry() = default; |
| |
| uint64_t id() const { return id_; } |
| const fbl::String& name() const { return node_->name_; } |
| const fbl::RefPtr<LocalVnode>& node() const { return node_; } |
| |
| private: |
| uint64_t const id_; |
| fbl::RefPtr<LocalVnode> node_; |
| }; |
| |
| struct KeyByIdTraits { |
| static uint64_t GetKey(const Entry& entry) { return entry.id(); } |
| static bool LessThan(uint64_t key1, uint64_t key2) { return key1 < key2; } |
| static bool EqualTo(uint64_t key1, uint64_t key2) { return key1 == key2; } |
| }; |
| |
| struct KeyByNameTraits { |
| static fbl::String GetKey(const Entry& entry) { return entry.name(); } |
| static bool LessThan(const fbl::String& key1, const fbl::String& key2) { return key1 < key2; } |
| static bool EqualTo(const fbl::String& key1, const fbl::String& key2) { return key1 == key2; } |
| }; |
| |
| using EntryByIdMap = |
| fbl::TaggedWAVLTree<uint64_t, std::unique_ptr<Entry>, IdTreeTag, KeyByIdTraits>; |
| using EntryByNameMap = fbl::TaggedWAVLTree<fbl::String, Entry*, NameTreeTag, KeyByNameTraits>; |
| |
| class Intermediate { |
| public: |
| bool has_children() const { return !entries_by_id_.is_empty(); } |
| void AddEntry(fbl::RefPtr<LocalVnode> vn); |
| void RemoveEntry(LocalVnode* vn); |
| void UnlinkEntries(); |
| |
| const EntryByIdMap& GetEntriesById() const { return entries_by_id_; } |
| |
| // Returns a child if it has the name |name|. |
| // Otherwise, returns nullptr. |
| fbl::RefPtr<LocalVnode> Lookup(std::string_view name) const; |
| |
| // Invoke |Fn()| on all entries in this Intermediate node_type. |
| // May be used as a const visitor-pattern for all entries. |
| // |
| // Any status other than ZX_OK returned from |Fn()| will halt iteration |
| // immediately and return. |
| template <typename Fn> |
| zx_status_t ForAllEntries(Fn fn) const; |
| |
| private: |
| uint64_t next_node_id_ = 1; |
| EntryByNameMap entries_by_name_; |
| EntryByIdMap entries_by_id_; |
| }; |
| |
| class Local { |
| public: |
| Local(fdio_open_local_func_t on_open, void* context); |
| zx::result<fdio_ptr> Open(); |
| void Unlink(); |
| |
| private: |
| fbl::Mutex lock_; |
| fdio_open_local_func_t on_open_ __TA_GUARDED(lock_); |
| void* context_ __TA_GUARDED(lock_); |
| }; |
| |
| class Remote { |
| public: |
| explicit Remote(zxio_storage_t remote_storage) : remote_storage_(remote_storage) {} |
| zxio_t* Connection() const { return const_cast<zxio_t*>(&remote_storage_.io); } |
| |
| private: |
| const zxio_storage_t remote_storage_; |
| }; |
| |
| std::variant<Local, Intermediate, Remote>& NodeType() { return node_type_; } |
| |
| private: |
| friend class fbl::RefPtr<LocalVnode>; |
| |
| zx_status_t AddChild(fbl::RefPtr<LocalVnode> child); |
| zx_status_t RemoveChild(LocalVnode* child); |
| |
| zx_status_t EnumerateInternal(PathBuffer* path, const EnumerateCallback& func) const; |
| |
| template <class T, class... Args> |
| LocalVnode(fbl::RefPtr<LocalVnode> parent, fbl::String name, std::in_place_type_t<T> in_place, |
| Args&&... args) |
| : node_type_(in_place, std::forward<Args>(args)...), |
| parent_(std::move(parent)), |
| name_(std::move(name)) {} |
| ~LocalVnode(); |
| |
| std::variant<Local, Intermediate, Remote> node_type_; |
| fbl::RefPtr<LocalVnode> parent_; |
| const fbl::String name_; |
| }; |
| |
| } // namespace fdio_internal |
| |
| #endif // LIB_FDIO_NAMESPACE_LOCAL_VNODE_H_ |