blob: 970c6ba61454edd26433795f61eb672e870ac04a [file] [log] [blame]
// Copyright 2017 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 "sdk/lib/fdio/namespace/namespace.h"
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/namespace.h>
#include <lib/zx/channel.h>
#include <zircon/types.h>
#include <cerrno>
#include <fbl/auto_lock.h>
#include <fbl/ref_ptr.h>
#include "fidl/fuchsia.io/cpp/wire_types.h"
#include "sdk/lib/fdio/cleanpath.h"
#include "sdk/lib/fdio/fdio_state.h"
#include "sdk/lib/fdio/fdio_unistd.h"
#include "sdk/lib/fdio/internal.h"
#include "sdk/lib/fdio/namespace/local-connection.h"
#include "sdk/lib/fdio/namespace/local-filesystem.h"
#include "sdk/lib/fdio/unistd.h"
namespace fio = fuchsia_io;
zx::result<fbl::RefPtr<fdio>> fdio_ns_open_root(fdio_ns_t* ns) { return ns->OpenRoot(); }
zx_status_t fdio_ns_set_root(fdio_ns_t* ns, fdio_t* io) { return ns->SetRoot(io); }
__BEGIN_CDECLS
__EXPORT
zx_status_t fdio_ns_connect(fdio_ns_t* ns, const char* path, uint32_t flags, zx_handle_t request) {
if (static_cast<fio::wire::OpenFlags>(flags) & fio::wire::OpenFlags::kDescribe) {
return ZX_ERR_INVALID_ARGS;
}
return fdio_ns_open(ns, path, flags, request);
}
__EXPORT
zx_status_t fdio_ns_open(fdio_ns_t* ns, const char* path, uint32_t flags, zx_handle_t request) {
if (path == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
fdio_internal::PathBuffer clean;
bool is_dir;
if (!fdio_internal::CleanPath(path, &clean, &is_dir)) {
return ZX_ERR_BAD_PATH;
}
auto remote = fidl::ServerEnd<fio::Node>(zx::channel(request));
return ns->Connect(clean, static_cast<fio::wire::OpenFlags>(flags), std::move(remote));
}
__EXPORT
zx_status_t fdio_ns_service_connect(fdio_ns_t* ns, const char* path, zx_handle_t request) {
return fdio_ns_open(ns, path, 0, request);
}
__EXPORT
zx_status_t fdio_ns_create(fdio_ns_t** out) {
// Create a ref-counted object, and leak the reference that is returned
// via the C API.
//
// This reference is reclaimed in fdio_ns_destroy.
fbl::RefPtr<fdio_namespace> ns = fdio_namespace::Create();
*out = fbl::ExportToRawPtr(&ns);
return ZX_OK;
}
__EXPORT
zx_status_t fdio_ns_destroy(fdio_ns_t* raw_ns) {
// This function reclaims a reference which was leaked in fdio_ns_create.
[[maybe_unused]] auto ns = fbl::ImportFromRawPtr<fdio_namespace>(raw_ns);
return ZX_OK;
}
__EXPORT
zx_status_t fdio_ns_bind_local(fdio_ns_t* ns, const char* path, fdio_open_local_func_t on_open,
void* context) {
if (path == nullptr || on_open == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
fdio_internal::PathBuffer clean;
bool is_dir;
if (!fdio_internal::CleanPath(path, &clean, &is_dir)) {
return ZX_ERR_BAD_PATH;
}
if (is_dir) {
// Local binding are always files.
return ZX_ERR_INVALID_ARGS;
}
return ns->Bind(clean, on_open, context);
}
__EXPORT
zx_status_t fdio_ns_bind(fdio_ns_t* ns, const char* path, zx_handle_t remote_raw) {
if (path == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
fdio_internal::PathBuffer clean;
bool is_dir;
if (!fdio_internal::CleanPath(path, &clean, &is_dir)) {
return ZX_ERR_BAD_PATH;
}
auto remote = fidl::ClientEnd<fio::Directory>(zx::channel(remote_raw));
return ns->Bind(clean, std::move(remote));
}
__EXPORT
zx_status_t fdio_ns_unbind(fdio_ns_t* ns, const char* path) {
if (path == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
fdio_internal::PathBuffer clean;
bool is_dir;
if (!fdio_internal::CleanPath(path, &clean, &is_dir)) {
return ZX_ERR_BAD_PATH;
}
return ns->Unbind(clean);
}
__EXPORT
bool fdio_ns_is_bound(fdio_ns_t* ns, const char* path) {
if (path == nullptr) {
return false;
}
fdio_internal::PathBuffer clean;
bool is_dir;
if (!fdio_internal::CleanPath(path, &clean, &is_dir)) {
return false;
}
return ns->IsBound(clean);
}
__EXPORT
zx_status_t fdio_ns_bind_fd(fdio_ns_t* ns, const char* path, int fd) {
zx_handle_t handle = ZX_HANDLE_INVALID;
zx_status_t status = fdio_fd_clone(fd, &handle);
if (status != ZX_OK) {
return status;
}
return fdio_ns_bind(ns, path, handle);
}
__EXPORT
int fdio_ns_opendir(fdio_ns_t* ns) {
zx::result io = ns->OpenRoot();
if (io.is_error()) {
errno = ENOMEM;
return -1;
}
std::optional fd = bind_to_fd(io.value());
if (fd.has_value()) {
return fd.value();
}
return ERRNO(EMFILE);
}
__EXPORT
zx_status_t fdio_ns_chdir(fdio_ns_t* ns) {
zx::result io = ns->OpenRoot();
if (io.is_error()) {
return ZX_ERR_NO_MEMORY;
}
fdio_chdir(io.value(), "/");
return ZX_OK;
}
__EXPORT
zx_status_t fdio_ns_export(fdio_ns_t* ns, fdio_flat_namespace_t** out) { return ns->Export(out); }
__EXPORT
zx_status_t fdio_ns_export_root(fdio_flat_namespace_t** out) {
fbl::AutoLock lock(&fdio_lock);
return fdio_ns_export(fdio_root_ns, out);
}
__EXPORT
void fdio_ns_free_flat_ns(fdio_flat_namespace_t* ns) {
zx_handle_close_many(ns->handle, ns->count);
free(ns);
}
__END_CDECLS