blob: 85361066015a200f7806e683b630d95c3acdfb03 [file] [log] [blame]
// 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/pseudo_dir.h>
#include <mutex>
namespace vfs {
PseudoDir::PseudoDir() : next_node_id_(kDotId + 1) {}
PseudoDir::~PseudoDir() = default;
zx_status_t PseudoDir::AddSharedEntry(std::string name, std::shared_ptr<Node> vn) {
ZX_DEBUG_ASSERT(vn);
auto id = next_node_id_++;
return AddEntry(std::make_unique<SharedEntry>(id, std::move(name), std::move(vn)));
}
zx_status_t PseudoDir::AddEntry(std::string name, std::unique_ptr<Node> vn) {
ZX_DEBUG_ASSERT(vn);
auto id = next_node_id_++;
return AddEntry(std::make_unique<UniqueEntry>(id, std::move(name), std::move(vn)));
}
zx_status_t PseudoDir::AddEntry(std::unique_ptr<Entry> entry) {
ZX_DEBUG_ASSERT(entry);
if (!vfs::internal::IsValidName(entry->name())) {
return ZX_ERR_INVALID_ARGS;
}
std::lock_guard<std::mutex> guard(mutex_);
if (entries_by_name_.find(entry->name()) != entries_by_name_.end()) {
return ZX_ERR_ALREADY_EXISTS;
}
entries_by_name_[entry->name()] = entry.get();
auto id = entry->id();
entries_by_id_.emplace_hint(entries_by_id_.end(), id, std::move(entry));
return ZX_OK;
}
zx_status_t PseudoDir::RemoveEntry(const std::string& name) {
std::lock_guard<std::mutex> guard(mutex_);
auto entry = entries_by_name_.find(name);
if (entry == entries_by_name_.end()) {
return ZX_ERR_NOT_FOUND;
}
entries_by_id_.erase(entry->second->id());
entries_by_name_.erase(name);
return ZX_OK;
}
zx_status_t PseudoDir::RemoveEntry(const std::string& name, Node* node) {
std::lock_guard<std::mutex> guard(mutex_);
auto entry = entries_by_name_.find(name);
if (entry == entries_by_name_.end() || entry->second->node() != node) {
return ZX_ERR_NOT_FOUND;
}
entries_by_id_.erase(entry->second->id());
entries_by_name_.erase(name);
return ZX_OK;
}
zx_status_t PseudoDir::Lookup(const std::string& name, vfs::internal::Node** out_node) const {
std::lock_guard<std::mutex> guard(mutex_);
auto search = entries_by_name_.find(name);
if (search != entries_by_name_.end()) {
*out_node = search->second->node();
return ZX_OK;
} else {
return ZX_ERR_NOT_FOUND;
}
}
zx_status_t PseudoDir::Readdir(uint64_t offset, void* data, uint64_t len, uint64_t* out_offset,
uint64_t* out_actual) {
vfs::internal::DirentFiller df(data, len);
*out_actual = 0;
*out_offset = offset;
if (offset < kDotId) {
if (df.Next(".", 1, fuchsia::io::DIRENT_TYPE_DIRECTORY, fuchsia::io::INO_UNKNOWN) != ZX_OK) {
*out_actual = df.GetBytesFilled();
return ZX_ERR_INVALID_ARGS; // out_actual would be 0
}
(*out_offset)++;
}
std::lock_guard<std::mutex> guard(mutex_);
for (auto it = entries_by_id_.upper_bound(*out_offset); it != entries_by_id_.end(); ++it) {
fuchsia::io::NodeAttributes attr;
auto d_type = fuchsia::io::DIRENT_TYPE_UNKNOWN;
auto ino = fuchsia::io::INO_UNKNOWN;
if (it->second->node()->GetAttr(&attr) == ZX_OK) {
d_type = ((fuchsia::io::MODE_TYPE_MASK & attr.mode) >> 12);
ino = attr.id;
}
if (df.Next(it->second->name(), d_type, ino) != ZX_OK) {
*out_actual = df.GetBytesFilled();
if (*out_actual == 0) {
// no space to fill even 1 dentry
return ZX_ERR_INVALID_ARGS;
}
return ZX_OK;
}
*out_offset = it->second->id();
}
*out_actual = df.GetBytesFilled();
return ZX_OK;
}
bool PseudoDir::IsEmpty() const {
std::lock_guard<std::mutex> guard(mutex_);
return entries_by_name_.size() == 0;
}
PseudoDir::Entry::Entry(uint64_t id, std::string name) : id_(id), name_(std::move(name)) {}
PseudoDir::Entry::~Entry() = default;
PseudoDir::SharedEntry::SharedEntry(uint64_t id, std::string name, std::shared_ptr<Node> node)
: Entry(id, std::move(name)), node_(std::move(node)) {}
vfs::internal::Node* PseudoDir::SharedEntry::node() const { return node_.get(); }
PseudoDir::SharedEntry::~SharedEntry() = default;
PseudoDir::UniqueEntry::UniqueEntry(uint64_t id, std::string name, std::unique_ptr<Node> node)
: Entry(id, std::move(name)), node_(std::move(node)) {}
vfs::internal::Node* PseudoDir::UniqueEntry::node() const { return node_.get(); }
PseudoDir::UniqueEntry::~UniqueEntry() = default;
} // namespace vfs