blob: de0c219d11f050d30e963557df9e94f499984be6 [file] [log] [blame]
// Copyright 2016 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.
#pragma once
#include <limits.h>
#include <string.h>
#include <fs/vfs.h>
#include <fs/vnode.h>
#include <lib/fdio/vfs.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include <fbl/unique_ptr.h>
namespace memfs {
class VnodeMemfs;
constexpr size_t kDnodeNameMax = NAME_MAX;
static_assert(NAME_MAX == 255, "NAME_MAX must be 255");
// Assert that kDnodeNameMax can be used as a bitmask
static_assert(((kDnodeNameMax + 1) & kDnodeNameMax) == 0,
"Expected kDnodeNameMax to be one less than a power of two");
class Dnode : public fbl::RefCounted<Dnode> {
public:
DISALLOW_COPY_ASSIGN_AND_MOVE(Dnode);
using NodeState = fbl::DoublyLinkedListNodeState<fbl::RefPtr<Dnode>>;
// ChildTraits is the state used for a Dnode to appear as the child
// of another dnode.
struct TypeChildTraits { static NodeState& node_state(Dnode& dn) { return dn.type_child_state_; }};
using ChildList = fbl::DoublyLinkedList<fbl::RefPtr<Dnode>, Dnode::TypeChildTraits>;
// Allocates a dnode, attached to a vnode
static fbl::RefPtr<Dnode> Create(fbl::StringPiece name, fbl::RefPtr<VnodeMemfs> vn);
// Takes a parent-less node and makes it a child of the parent node.
//
// Increments child link count by one.
// If the child is a directory, increments the parent link count by one.
static void AddChild(fbl::RefPtr<Dnode> parent, fbl::RefPtr<Dnode> child);
// Removes a dnode from its parent (if dnode has a parent)
// Decrements parent link count by one.
void RemoveFromParent();
// Detaches a dnode from its parent / vnode.
// Decrements dn->vnode link count by one (if it exists).
void Detach();
bool HasChildren() const { return !children_.is_empty(); }
// Look up the child dnode (within a parent directory) by name.
// Returns ZX_OK if the child is found.
//
// If the looked up child is the current node, "out" is nullptr, and
// ZX_OK is still returned.
// If "out" is provided as "nullptr", the returned status appears the
// same, but the "out" argument is not touched.
zx_status_t Lookup(fbl::StringPiece name, fbl::RefPtr<Dnode>* out) const;
// Acquire a pointer to the vnode underneath this dnode.
// Acquires a reference to the underlying vnode.
fbl::RefPtr<VnodeMemfs> AcquireVnode() const;
// Returns ZX_OK if the dnode may be unlinked
zx_status_t CanUnlink() const;
// Read dirents (up to len bytes worth) into data.
// ReaddirStart reads the canned "." and ".." entries that should appear
// at the beginning of a directory.
// On success, return the number of bytes read.
static zx_status_t ReaddirStart(fs::DirentFiller* df, void* cookie);
void Readdir(fs::DirentFiller* df, void* cookie) const;
// Answers the question: "Is dn a subdirectory of this?"
bool IsSubdirectory(fbl::RefPtr<Dnode> dn) const;
// Functions to take / steal the allocated dnode name.
fbl::unique_ptr<char[]> TakeName();
void PutName(fbl::unique_ptr<char[]> name, size_t len);
bool IsDirectory() const;
private:
friend struct TypeChildTraits;
Dnode(fbl::RefPtr<VnodeMemfs> vn, fbl::unique_ptr<char[]> name, uint32_t flags);
size_t NameLen() const;
bool NameMatch(fbl::StringPiece name) const;
NodeState type_child_state_;
fbl::RefPtr<VnodeMemfs> vnode_;
fbl::RefPtr<Dnode> parent_;
// Used to impose an absolute order on dnodes within a directory.
size_t ordering_token_;
ChildList children_;
uint32_t flags_;
fbl::unique_ptr<char[]> name_;
};
} // namespace memfs