blob: f470a901920e8f2b3f97962a20f244b45e50b7a8 [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 <fbl/auto_call.h>
#include <fbl/auto_lock.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include <fbl/string.h>
#include <fbl/string_buffer.h>
#include <fbl/string_piece.h>
#include <lib/zx/channel.h>
#include <zircon/types.h>
#include "local-vnode.h"
namespace fdio_internal {
fbl::RefPtr<LocalVnode> LocalVnode::Create(fbl::RefPtr<LocalVnode> parent,
zx::channel remote, fbl::String name) {
auto vn = fbl::AdoptRef(new LocalVnode(std::move(parent), std::move(remote),
std::move(name)));
if (vn->parent_ != nullptr) {
vn->parent_->children_.push_back(vn);
}
return vn;
}
void LocalVnode::Unlink() {
UnlinkChildren();
UnlinkFromParent();
}
zx_status_t LocalVnode::SetRemote(zx::channel remote) {
if (remote_.is_valid()) {
// Cannot re-bind after initial bind.
return ZX_ERR_ALREADY_EXISTS;
}
if (!children_.is_empty()) {
// Overlay remotes are disallowed.
return ZX_ERR_NOT_SUPPORTED;
}
remote_ = std::move(remote);
return ZX_OK;
}
// Returns a child if it has the name |name|.
// Otherwise, returns nullptr.
fbl::RefPtr<LocalVnode> LocalVnode::Lookup(const fbl::StringPiece& name) const {
auto vn = children_.find_if([&name](const LocalVnode& elem) -> bool {
return fbl::StringPiece(elem.Name()) == name;
});
return vn != children_.end() ? vn.CopyPointer() : nullptr;
}
LocalVnode::LocalVnode(fbl::RefPtr<LocalVnode> parent, zx::channel remote, fbl::String name)
: parent_(std::move(parent)), remote_(std::move(remote)), name_(std::move(name)) {}
void LocalVnode::UnlinkChildren() {
while (!children_.is_empty()) {
auto child = children_.pop_front();
child->UnlinkChildren();
child->parent_ = nullptr;
}
}
void LocalVnode::UnlinkFromParent() {
if (parent_) {
parent_->children_.erase(*this);
}
parent_ = nullptr;
}
zx_status_t EnumerateInternal(const LocalVnode& vn, fbl::StringBuffer<PATH_MAX>* path,
const EnumerateCallback& func) {
size_t original_length = path->length();
// Add this current node to the path, and enumerate it if it has a remote
// object.
path->Append(vn.Name().data(), vn.Name().length());
if (vn.Remote().is_valid()) {
func(fbl::StringPiece(path->data(), path->length()), vn.Remote());
}
// If we added a non-null path, add a separator and enumerate all the
// children.
if (vn.Name().length() > 0) {
path->Append('/');
}
vn.ForAllChildren([&path, &func](const LocalVnode& child) {
return EnumerateInternal(child, path, func);
});
// To re-use the same prefix buffer, restore the original buffer length
// after enumeration has completed.
path->Resize(original_length);
return ZX_OK;
}
zx_status_t EnumerateRemotes(const LocalVnode& vn, const EnumerateCallback& func) {
fbl::StringBuffer<PATH_MAX> path;
path.Append('/');
return EnumerateInternal(vn, &path, func);
}
} // namespace fdio_internal