1 // Copyright 2017 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 #include <fs/pseudo-dir.h>
6
7 #include <sys/stat.h>
8
9 #include <fbl/auto_lock.h>
10 #include <fuchsia/io/c/fidl.h>
11
12 #include <utility>
13
14 namespace fs {
15
16 PseudoDir::PseudoDir() = default;
17
~PseudoDir()18 PseudoDir::~PseudoDir() {
19 entries_by_name_.clear_unsafe();
20 entries_by_id_.clear();
21 }
22
Open(uint32_t flags,fbl::RefPtr<Vnode> * out_redirect)23 zx_status_t PseudoDir::Open(uint32_t flags, fbl::RefPtr<Vnode>* out_redirect) {
24 return ZX_OK;
25 }
26
Getattr(vnattr_t * attr)27 zx_status_t PseudoDir::Getattr(vnattr_t* attr) {
28 memset(attr, 0, sizeof(vnattr_t));
29 attr->mode = V_TYPE_DIR | V_IRUSR;
30 attr->nlink = 1;
31 return ZX_OK;
32 }
33
Lookup(fbl::RefPtr<fs::Vnode> * out,fbl::StringPiece name)34 zx_status_t PseudoDir::Lookup(fbl::RefPtr<fs::Vnode>* out, fbl::StringPiece name) {
35 fbl::AutoLock lock(&mutex_);
36
37 auto it = entries_by_name_.find(name);
38 if (it != entries_by_name_.end()) {
39 *out = it->node();
40 return ZX_OK;
41 }
42
43 return ZX_ERR_NOT_FOUND;
44 }
45
Notify(fbl::StringPiece name,unsigned event)46 void PseudoDir::Notify(fbl::StringPiece name, unsigned event) {
47 watcher_.Notify(name, event);
48 }
49
WatchDir(fs::Vfs * vfs,uint32_t mask,uint32_t options,zx::channel watcher)50 zx_status_t PseudoDir::WatchDir(fs::Vfs* vfs, uint32_t mask, uint32_t options,
51 zx::channel watcher) {
52 return watcher_.WatchDir(vfs, this, mask, options, std::move(watcher));
53 }
54
Readdir(vdircookie_t * cookie,void * data,size_t len,size_t * out_actual)55 zx_status_t PseudoDir::Readdir(vdircookie_t* cookie, void* data, size_t len, size_t* out_actual) {
56 fs::DirentFiller df(data, len);
57 zx_status_t r = 0;
58 if (cookie->n < kDotId) {
59 uint64_t ino = fuchsia_io_INO_UNKNOWN;
60 if ((r = df.Next(".", VTYPE_TO_DTYPE(V_TYPE_DIR), ino)) != ZX_OK) {
61 *out_actual = df.BytesFilled();
62 return r;
63 }
64 cookie->n = kDotId;
65 }
66
67 fbl::AutoLock lock(&mutex_);
68
69 for (auto it = entries_by_id_.lower_bound(cookie->n); it != entries_by_id_.end(); ++it) {
70 if (cookie->n >= it->id()) {
71 continue;
72 }
73 vnattr_t attr;
74 if ((r = it->node()->Getattr(&attr)) != ZX_OK) {
75 continue;
76 }
77 if (df.Next(it->name().ToStringPiece(),
78 VTYPE_TO_DTYPE(attr.mode), attr.inode) != ZX_OK) {
79 *out_actual = df.BytesFilled();
80 return ZX_OK;
81 }
82 cookie->n = it->id();
83 }
84
85 *out_actual = df.BytesFilled();
86 return ZX_OK;
87 }
88
AddEntry(fbl::String name,fbl::RefPtr<fs::Vnode> vn)89 zx_status_t PseudoDir::AddEntry(fbl::String name, fbl::RefPtr<fs::Vnode> vn) {
90 ZX_DEBUG_ASSERT(vn);
91
92 if (!vfs_valid_name(name.ToStringPiece())) {
93 return ZX_ERR_INVALID_ARGS;
94 }
95
96 fbl::AutoLock lock(&mutex_);
97
98 if (entries_by_name_.find(name) != entries_by_name_.end()) {
99 return ZX_ERR_ALREADY_EXISTS;
100 }
101
102 Notify(name.ToStringPiece(), fuchsia_io_WATCH_EVENT_ADDED);
103 auto entry = fbl::make_unique<Entry>(next_node_id_++,
104 std::move(name), std::move(vn));
105 entries_by_name_.insert(entry.get());
106 entries_by_id_.insert(std::move(entry));
107 return ZX_OK;
108 }
109
RemoveEntry(fbl::StringPiece name)110 zx_status_t PseudoDir::RemoveEntry(fbl::StringPiece name) {
111 fbl::AutoLock lock(&mutex_);
112
113 auto it = entries_by_name_.find(name);
114 if (it != entries_by_name_.end()) {
115 entries_by_name_.erase(it);
116 entries_by_id_.erase(it->id());
117 Notify(name, fuchsia_io_WATCH_EVENT_REMOVED);
118 return ZX_OK;
119 }
120
121 return ZX_ERR_NOT_FOUND;
122 }
123
RemoveAllEntries()124 void PseudoDir::RemoveAllEntries() {
125 fbl::AutoLock lock(&mutex_);
126
127 for (auto& entry : entries_by_name_) {
128 Notify(entry.name().ToStringPiece(), fuchsia_io_WATCH_EVENT_REMOVED);
129 }
130 entries_by_name_.clear();
131 entries_by_id_.clear();
132 }
133
IsEmpty() const134 bool PseudoDir::IsEmpty() const {
135 fbl::AutoLock lock(&mutex_);
136 return entries_by_name_.is_empty();
137 }
138
Entry(uint64_t id,fbl::String name,fbl::RefPtr<fs::Vnode> node)139 PseudoDir::Entry::Entry(uint64_t id, fbl::String name, fbl::RefPtr<fs::Vnode> node)
140 : id_(id), name_(std::move(name)), node_(std::move(node)) {
141 }
142
143 PseudoDir::Entry::~Entry() = default;
144
145 } // namespace fs
146