| // Copyright 2019 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 <lib/fdio/vfs.h> |
| #include <lib/vfs/cpp/internal/dirent_filler.h> |
| #include <lib/vfs/cpp/lazy_dir.h> |
| |
| #include <algorithm> |
| |
| namespace vfs { |
| |
| bool LazyDir::LazyEntry::operator<(const LazyDir::LazyEntry& rhs) const { return id < rhs.id; } |
| |
| LazyDir::LazyDir() {} |
| |
| LazyDir::~LazyDir() = default; |
| |
| zx_status_t LazyDir::GetAttr(fuchsia::io::NodeAttributes* out_attributes) const { |
| out_attributes->mode = fuchsia::io::MODE_TYPE_DIRECTORY | V_IRUSR; |
| out_attributes->id = fuchsia::io::INO_UNKNOWN; |
| out_attributes->content_size = 0; |
| out_attributes->storage_size = 0; |
| out_attributes->link_count = 1; |
| out_attributes->creation_time = 0; |
| out_attributes->modification_time = 0; |
| return ZX_OK; |
| } |
| |
| zx_status_t LazyDir::Lookup(const std::string& name, Node** out_node) const { |
| LazyEntryVector entries; |
| GetContents(&entries); |
| for (const auto& entry : entries) { |
| if (name == entry.name) { |
| return GetFile(out_node, entry.id, entry.name); |
| } |
| } |
| return ZX_ERR_NOT_FOUND; |
| } |
| |
| zx_status_t LazyDir::Readdir(uint64_t offset, void* data, uint64_t len, uint64_t* out_offset, |
| uint64_t* out_actual) { |
| LazyEntryVector entries; |
| GetContents(&entries); |
| std::sort(entries.begin(), entries.end()); |
| |
| vfs::internal::DirentFiller filler(data, len); |
| |
| const uint64_t ino = fuchsia::io::INO_UNKNOWN; |
| if (offset < kDotId) { |
| if (filler.Next(".", 1, fuchsia::io::DIRENT_TYPE_DIRECTORY, ino) != ZX_OK) { |
| *out_actual = filler.GetBytesFilled(); |
| return ZX_ERR_INVALID_ARGS; // out_actual would be 0 |
| } |
| offset++; |
| *out_offset = kDotId; |
| } |
| for (auto it = std::upper_bound(entries.begin(), entries.end(), offset, |
| [](uint64_t b_id, const LazyEntry&a) { return b_id < a.id; }); |
| it != entries.end(); ++it) { |
| auto dtype = ((fuchsia::io::MODE_TYPE_MASK & it->type) >> 12); |
| if (filler.Next(it->name, dtype, ino) != ZX_OK) { |
| *out_actual = filler.GetBytesFilled(); |
| if (*out_actual == 0) { |
| // no space to fill even 1 dentry |
| return ZX_ERR_INVALID_ARGS; |
| } |
| return ZX_OK; |
| } |
| *out_offset = it->id; |
| } |
| |
| *out_actual = filler.GetBytesFilled(); |
| return ZX_OK; |
| } |
| |
| uint64_t LazyDir::GetStartingId() const { return kDotId + 1; } |
| |
| } // namespace vfs |