| // Copyright 2018 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. |
| |
| #include "src/storage/lib/vfs/cpp/lazy_dir.h" |
| |
| #include <fidl/fuchsia.io/cpp/wire.h> |
| |
| #include <algorithm> |
| #include <string_view> |
| |
| #include "src/storage/lib/vfs/cpp/vfs.h" |
| #include "src/storage/lib/vfs/cpp/vfs_types.h" |
| #include "src/storage/lib/vfs/cpp/vnode.h" |
| |
| namespace fio = fuchsia_io; |
| |
| namespace fs { |
| |
| namespace { |
| int CompareLazyDirPtrs(const void* a, const void* b) { |
| auto a_id = static_cast<const LazyDir::LazyEntry*>(a)->id; |
| auto b_id = static_cast<const LazyDir::LazyEntry*>(b)->id; |
| if (a_id == b_id) { |
| return 0; |
| } |
| return a_id < b_id ? -1 : 1; |
| } |
| |
| bool DoDot(VdirCookie* cookie) { |
| if (cookie->p == 0) { |
| cookie->p = (void*)1; |
| return true; |
| } |
| return false; |
| } |
| } // namespace |
| |
| LazyDir::LazyDir() = default; |
| LazyDir::~LazyDir() = default; |
| |
| fuchsia_io::NodeProtocolKinds LazyDir::GetProtocols() const { |
| return fuchsia_io::NodeProtocolKinds::kDirectory; |
| } |
| |
| zx::result<fs::VnodeAttributes> LazyDir::GetAttributes() const { |
| return zx::ok(VnodeAttributes{ |
| .mode = V_TYPE_DIR | V_IRUSR, |
| }); |
| } |
| |
| zx_status_t LazyDir::Lookup(std::string_view name, fbl::RefPtr<fs::Vnode>* out_vnode) { |
| LazyEntryVector entries; |
| GetContents(&entries); |
| for (const auto& entry : entries) { |
| if (name.compare(entry.name) == 0) { |
| return GetFile(out_vnode, entry.id, entry.name); |
| } |
| } |
| return ZX_ERR_NOT_FOUND; |
| } |
| |
| zx_status_t LazyDir::Readdir(VdirCookie* cookie, void* dirents, size_t len, size_t* out_actual) { |
| LazyEntryVector entries; |
| GetContents(&entries); |
| qsort(entries.data(), entries.size(), sizeof(LazyEntry), CompareLazyDirPtrs); |
| |
| fs::DirentFiller df(dirents, len); |
| zx_status_t r = 0; |
| |
| const uint64_t ino = fio::wire::kInoUnknown; |
| if (DoDot(cookie)) { |
| if ((r = df.Next(".", VTYPE_TO_DTYPE(V_TYPE_DIR), ino)) != ZX_OK) { |
| *out_actual = df.BytesFilled(); |
| return r; |
| } |
| } |
| |
| for (auto it = std::lower_bound(entries.begin(), entries.end(), cookie->n, |
| [](const LazyEntry& a, uint64_t b_id) { return a.id < b_id; }); |
| it < entries.end(); ++it) { |
| if (cookie->n >= it->id) { |
| continue; |
| } |
| if ((r = df.Next(it->name, VTYPE_TO_DTYPE(it->type), ino)) != ZX_OK) { |
| *out_actual = df.BytesFilled(); |
| return r; |
| } |
| cookie->n = it->id; |
| } |
| *out_actual = df.BytesFilled(); |
| return ZX_OK; |
| } |
| |
| } // namespace fs |