blob: c43681b1e432b5fb534a8b57cfc4d9584acbd9f0 [file] [log] [blame] [edit]
// 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/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:
LocalVnode(const LocalVnode&) = delete;
LocalVnode(LocalVnode&&) = delete;
LocalVnode& operator=(const LocalVnode&) = delete;
LocalVnode& operator=(LocalVnode&&) = delete;
// 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, |ZX_ERR_NOT_FOUND| is returned.
zx::result<std::string_view> Readdir(uint64_t* last_seen) 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);
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::String name, fbl::RefPtr<LocalVnode> node)
: id_(id), name_(std::move(name)), node_(std::move(node)) {}
~Entry() = default;
uint64_t id() const { return id_; }
const fbl::String& name() const { return name_; }
const fbl::RefPtr<LocalVnode>& node() const { return node_; }
private:
const uint64_t id_;
const fbl::String name_;
const 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 const 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;
using ParentAndId = std::tuple<std::reference_wrapper<Intermediate>, uint64_t>;
class Intermediate {
public:
Intermediate(const Intermediate&) = delete;
Intermediate(Intermediate&&) = delete;
Intermediate& operator=(const Intermediate&) = delete;
Intermediate& operator=(Intermediate&&) = delete;
Intermediate() = default;
~Intermediate();
size_t num_children() const;
// Returns (child, false) if a child with |name| exists, otherwise creates a new child with
// |name| using |builder| and returns (child, true). Returns the error if |builder| fails.
zx::result<std::tuple<fbl::RefPtr<LocalVnode>, bool>> LookupOrInsert(
fbl::String name, fit::function<zx::result<fbl::RefPtr<LocalVnode>>(ParentAndId)> builder);
void RemoveEntry(LocalVnode* vn, uint64_t id);
// See |LocalVnode::Readdir|.
zx::result<std::string_view> Readdir(uint64_t* last_seen) const;
// Returns a child if it has the name |name|.
// Otherwise, returns nullptr.
fbl::RefPtr<LocalVnode> Lookup(const fbl::String& 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(const Local&) = delete;
Local(Local&&) = delete;
Local& operator=(const Local&) = delete;
Local& operator=(Local&&) = delete;
Local(fdio_open_local_func_t on_open, void* context);
zx::result<fdio_ptr> Open();
private:
const fdio_open_local_func_t on_open_;
void* const context_;
};
class Remote {
public:
Remote(const Remote&) = delete;
Remote(Remote&&) = delete;
Remote& operator=(const Remote&) = delete;
Remote& operator=(Remote&&) = delete;
explicit Remote(zxio_storage_t remote_storage) : remote_storage_(remote_storage) {}
~Remote();
zxio_t* Connection() { return &remote_storage_.io; }
private:
zxio_storage_t remote_storage_;
};
std::variant<Local, Intermediate, Remote>& NodeType() { return node_type_; }
private:
friend class fbl::internal::MakeRefCountedHelper<LocalVnode>;
friend class fbl::RefPtr<LocalVnode>;
zx_status_t EnumerateInternal(PathBuffer* path, std::string_view name,
const EnumerateCallback& func);
// The parent must outlive the child.
template <class T, class... Args>
LocalVnode(std::optional<ParentAndId> parent_and_id, std::in_place_type_t<T> in_place,
Args&&... args)
: node_type_(in_place, std::forward<Args>(args)...), parent_and_id_(parent_and_id) {}
std::variant<Local, Intermediate, Remote> node_type_;
std::optional<ParentAndId> parent_and_id_;
};
} // namespace fdio_internal
#endif // LIB_FDIO_NAMESPACE_LOCAL_VNODE_H_