blob: 8d95d557d48419db18e3854ca903fd27fc7c3e88 [file] [log] [blame] [edit]
// 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 <dirent.h>
#include <fidl/fuchsia.io/cpp/common_types.h>
#include <fidl/fuchsia.io/cpp/natural_types.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <string_view>
#include <fbl/ref_ptr.h>
#include "src/storage/lib/vfs/cpp/vfs.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;
}
} // namespace
LazyDir::LazyDir() = default;
LazyDir::~LazyDir() = default;
fio::NodeProtocolKinds LazyDir::GetProtocols() const { return fio::NodeProtocolKinds::kDirectory; }
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);
// The cookie's pointer is used as a bool to indicate whether "." should be output. nullptr
// indicates that "." should be output. Any non-nullptr value indicates that "." was already
// output.
if (cookie->p == nullptr) {
if (!df.Next(".", fio::DirentType::kDirectory, fio::kInoUnknown)) {
return ZX_ERR_BUFFER_TOO_SMALL;
}
cookie->p = this;
}
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;
}
const uint8_t d_type = IFTODT(it->type);
if (!df.Next(it->name, fio::DirentType{d_type}, fio::kInoUnknown)) {
*out_actual = df.BytesFilled();
return *out_actual == 0 ? ZX_ERR_BUFFER_TOO_SMALL : ZX_OK;
}
cookie->n = it->id;
}
*out_actual = df.BytesFilled();
return ZX_OK;
}
} // namespace fs