blob: f8b077c616adb806b3ed89ddf859b1d07443de27 [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_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_