| // 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_VFS_CPP_PSEUDO_DIR_H_ |
| #define LIB_VFS_CPP_PSEUDO_DIR_H_ |
| |
| #include <lib/vfs/cpp/internal/directory.h> |
| |
| #include <map> |
| #include <mutex> |
| |
| namespace vfs { |
| |
| // A pseudo-directory is a directory-like object whose entries are constructed |
| // by a program at runtime. The client can lookup, enumerate, and watch(not yet |
| // implemented) these directory entries but it cannot create, remove, or rename |
| // them. |
| // |
| // This class is thread-hostile, as are the |Nodes| it manages. |
| // |
| // # Simple usage |
| // |
| // Instances of this class should be owned and managed on the same thread |
| // that services their connections. |
| // |
| // # Advanced usage |
| // |
| // You can use a background thread to service connections provided: (a) the |
| // contents of the directory are configured prior to starting to service |
| // connections, (b) all modifications to the directory occur while the |
| // async_dispatcher_t for the background thread is stopped or suspended, and |
| // (c) async_dispatcher_t for the background thread is stopped or suspended |
| // prior to destroying the directory. |
| class PseudoDir : public vfs::internal::Directory { |
| public: |
| // Creates a directory which is initially empty. |
| PseudoDir(); |
| |
| // Destroys the directory and releases the nodes it contains. |
| ~PseudoDir() override; |
| |
| // Adds a directory entry associating the given |name| with |vn|. |
| // It is ok to add the same Node multiple times with different names. |
| // |
| // Returns |ZX_OK| on success. |
| // Returns |ZX_ERR_ALREADY_EXISTS| if there is already a node with the given |
| // name. |
| zx_status_t AddSharedEntry(std::string name, std::shared_ptr<Node> vn); |
| |
| // Adds a directory entry associating the given |name| with |vn|. |
| // |
| // Returns |ZX_OK| on success. |
| // Returns |ZX_ERR_ALREADY_EXISTS| if there is already a node with the given |
| // name. |
| zx_status_t AddEntry(std::string name, std::unique_ptr<Node> vn); |
| |
| // Removes a directory entry with the given |name|. |
| // |
| // Returns |ZX_OK| on success. |
| // Returns |ZX_ERR_NOT_FOUND| if there is no node with the given name. |
| zx_status_t RemoveEntry(const std::string& name); |
| |
| // Removes a directory entry with the given |name| and |node|. |
| // |
| // Returns |ZX_OK| on success. |
| // Returns |ZX_ERR_NOT_FOUND| if there is no node with the given |name| and |
| // matching |node| pointer. |
| zx_status_t RemoveEntry(const std::string& name, Node* node); |
| |
| // Removes all directory entries. |
| void RemoveAllEntries(); |
| |
| // Checks if directory is empty. |
| // Be careful while using this function if using this Dir in multiple |
| // threads. |
| bool IsEmpty() const; |
| |
| // |Directory| implementation: |
| zx_status_t Lookup(const std::string& name, vfs::internal::Node** out_node) const final; |
| |
| zx_status_t Readdir(uint64_t offset, void* data, uint64_t len, uint64_t* out_offset, |
| uint64_t* out_actual) override; |
| |
| private: |
| class Entry { |
| public: |
| Entry(uint64_t id, std::string name); |
| virtual ~Entry(); |
| |
| uint64_t id() const { return id_; } |
| const std::string& name() const { return name_; } |
| virtual Node* node() const = 0; |
| |
| private: |
| uint64_t const id_; |
| std::string name_; |
| }; |
| |
| class SharedEntry : public Entry { |
| public: |
| SharedEntry(uint64_t id, std::string name, std::shared_ptr<Node> node); |
| ~SharedEntry() override; |
| |
| Node* node() const override; |
| |
| private: |
| std::shared_ptr<Node> node_; |
| }; |
| |
| class UniqueEntry : public Entry { |
| public: |
| UniqueEntry(uint64_t id, std::string name, std::unique_ptr<Node> node); |
| ~UniqueEntry() override; |
| |
| Node* node() const override; |
| |
| private: |
| std::unique_ptr<Node> node_; |
| }; |
| |
| zx_status_t AddEntry(std::unique_ptr<Entry> entry); |
| |
| static constexpr uint64_t kDotId = 1u; |
| |
| mutable std::mutex mutex_; |
| |
| std::atomic_uint64_t next_node_id_; |
| |
| // for enumeration |
| std::map<uint64_t, std::unique_ptr<Entry>> entries_by_id_ __TA_GUARDED(mutex_); |
| |
| // for lookup |
| std::map<std::string, Entry*> entries_by_name_ __TA_GUARDED(mutex_); |
| }; |
| |
| } // namespace vfs |
| #endif // LIB_VFS_CPP_PSEUDO_DIR_H_ |