1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#pragma once 6 7#include <limits.h> 8#include <string.h> 9 10#include <fs/vfs.h> 11#include <fs/vnode.h> 12#include <lib/fdio/vfs.h> 13#include <fbl/intrusive_double_list.h> 14#include <fbl/ref_counted.h> 15#include <fbl/ref_ptr.h> 16#include <fbl/unique_ptr.h> 17 18namespace memfs { 19 20class VnodeMemfs; 21 22constexpr size_t kDnodeNameMax = NAME_MAX; 23static_assert(NAME_MAX == 255, "NAME_MAX must be 255"); 24 25// Assert that kDnodeNameMax can be used as a bitmask 26static_assert(((kDnodeNameMax + 1) & kDnodeNameMax) == 0, 27 "Expected kDnodeNameMax to be one less than a power of two"); 28 29class Dnode : public fbl::RefCounted<Dnode> { 30public: 31 DISALLOW_COPY_ASSIGN_AND_MOVE(Dnode); 32 using NodeState = fbl::DoublyLinkedListNodeState<fbl::RefPtr<Dnode>>; 33 34 // ChildTraits is the state used for a Dnode to appear as the child 35 // of another dnode. 36 struct TypeChildTraits { static NodeState& node_state(Dnode& dn) { return dn.type_child_state_; }}; 37 using ChildList = fbl::DoublyLinkedList<fbl::RefPtr<Dnode>, Dnode::TypeChildTraits>; 38 39 // Allocates a dnode, attached to a vnode 40 static fbl::RefPtr<Dnode> Create(fbl::StringPiece name, fbl::RefPtr<VnodeMemfs> vn); 41 42 // Takes a parent-less node and makes it a child of the parent node. 43 // 44 // Increments child link count by one. 45 // If the child is a directory, increments the parent link count by one. 46 static void AddChild(fbl::RefPtr<Dnode> parent, fbl::RefPtr<Dnode> child); 47 48 // Removes a dnode from its parent (if dnode has a parent) 49 // Decrements parent link count by one. 50 void RemoveFromParent(); 51 52 // Detaches a dnode from its parent / vnode. 53 // Decrements dn->vnode link count by one (if it exists). 54 void Detach(); 55 56 bool HasChildren() const { return !children_.is_empty(); } 57 58 // Look up the child dnode (within a parent directory) by name. 59 // Returns ZX_OK if the child is found. 60 // 61 // If the looked up child is the current node, "out" is nullptr, and 62 // ZX_OK is still returned. 63 // If "out" is provided as "nullptr", the returned status appears the 64 // same, but the "out" argument is not touched. 65 zx_status_t Lookup(fbl::StringPiece name, fbl::RefPtr<Dnode>* out) const; 66 67 // Acquire a pointer to the vnode underneath this dnode. 68 // Acquires a reference to the underlying vnode. 69 fbl::RefPtr<VnodeMemfs> AcquireVnode() const; 70 71 // Returns ZX_OK if the dnode may be unlinked 72 zx_status_t CanUnlink() const; 73 74 // Read dirents (up to len bytes worth) into data. 75 // ReaddirStart reads the canned "." and ".." entries that should appear 76 // at the beginning of a directory. 77 // On success, return the number of bytes read. 78 static zx_status_t ReaddirStart(fs::DirentFiller* df, void* cookie); 79 void Readdir(fs::DirentFiller* df, void* cookie) const; 80 81 // Answers the question: "Is dn a subdirectory of this?" 82 bool IsSubdirectory(fbl::RefPtr<Dnode> dn) const; 83 84 // Functions to take / steal the allocated dnode name. 85 fbl::unique_ptr<char[]> TakeName(); 86 void PutName(fbl::unique_ptr<char[]> name, size_t len); 87 88 bool IsDirectory() const; 89 90private: 91 friend struct TypeChildTraits; 92 93 Dnode(fbl::RefPtr<VnodeMemfs> vn, fbl::unique_ptr<char[]> name, uint32_t flags); 94 95 size_t NameLen() const; 96 bool NameMatch(fbl::StringPiece name) const; 97 98 NodeState type_child_state_; 99 fbl::RefPtr<VnodeMemfs> vnode_; 100 fbl::RefPtr<Dnode> parent_; 101 // Used to impose an absolute order on dnodes within a directory. 102 size_t ordering_token_; 103 ChildList children_; 104 uint32_t flags_; 105 fbl::unique_ptr<char[]> name_; 106}; 107 108} // namespace memfs 109