blob: 6c756205fc17512ceaf86b8543261801a43fa85f [file] [log] [blame]
// 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_