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