1 // Copyright 2018 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/lazy-dir.h>
6 #include <fuchsia/io/c/fidl.h>
7
8 namespace fs {
9
10 namespace {
CompareLazyDirPtrs(const void * a,const void * b)11 int CompareLazyDirPtrs(const void* a, const void* b) {
12 auto a_id = static_cast<const LazyDir::LazyEntry*>(a)->id;
13 auto b_id = static_cast<const LazyDir::LazyEntry*>(b)->id;
14 if (a_id == b_id) {
15 return 0;
16 }
17 return a_id < b_id ? -1 : 1;
18 }
19
DoDot(vdircookie_t * cookie)20 bool DoDot(vdircookie_t* cookie) {
21 if (cookie->p == 0) {
22 cookie->p = (void*)1;
23 return true;
24 }
25 return false;
26 }
27 } // namespace
28
LazyDir()29 LazyDir::LazyDir() {}
30 LazyDir::~LazyDir() = default;
31
Open(uint32_t flags,fbl::RefPtr<Vnode> * out_redirect)32 zx_status_t LazyDir::Open(uint32_t flags, fbl::RefPtr<Vnode>* out_redirect) {
33 return ZX_OK;
34 }
35
Getattr(vnattr_t * out_attr)36 zx_status_t LazyDir::Getattr(vnattr_t* out_attr) {
37 memset(out_attr, 0, sizeof(vnattr_t));
38 out_attr->mode = V_TYPE_DIR | V_IRUSR;
39 out_attr->nlink = 1;
40 return ZX_OK;
41 }
42
Lookup(fbl::RefPtr<fs::Vnode> * out_vnode,fbl::StringPiece name)43 zx_status_t LazyDir::Lookup(fbl::RefPtr<fs::Vnode>* out_vnode, fbl::StringPiece name) {
44 LazyEntryVector entries;
45 GetContents(&entries);
46 for (const auto& entry : entries) {
47 if (name.compare(entry.name) == 0) {
48 return GetFile(out_vnode, entry.id, entry.name);
49 }
50 }
51 return ZX_ERR_NOT_FOUND;
52 }
53
Readdir(vdircookie_t * cookie,void * dirents,size_t len,size_t * out_actual)54 zx_status_t LazyDir::Readdir(vdircookie_t* cookie, void* dirents, size_t len, size_t* out_actual) {
55 LazyEntryVector entries;
56 GetContents(&entries);
57 qsort(entries.get(), entries.size(), sizeof(LazyEntry), CompareLazyDirPtrs);
58
59 fs::DirentFiller df(dirents, len);
60 zx_status_t r = 0;
61
62 const uint64_t ino = fuchsia_io_INO_UNKNOWN;
63 if (DoDot(cookie)) {
64 if ((r = df.Next(".", VTYPE_TO_DTYPE(V_TYPE_DIR), ino)) != ZX_OK) {
65 *out_actual = df.BytesFilled();
66 return r;
67 }
68 }
69
70 for (auto it = fbl::lower_bound(entries.begin(), entries.end(), cookie->n,
71 [](const LazyEntry&a, uint64_t b_id) { return a.id < b_id; });
72 it < entries.end();
73 ++it) {
74 if (cookie->n >= it->id) {
75 continue;
76 }
77 if ((r = df.Next(it->name, VTYPE_TO_DTYPE(it->type), ino)) != ZX_OK) {
78 *out_actual = df.BytesFilled();
79 return r;
80 }
81 cookie->n = it->id;
82 }
83 *out_actual = df.BytesFilled();
84 return ZX_OK;
85 }
86
87 } // namespace fs
88