blob: 5a70bc60fee3100cd844e23264db4e9bb561b635 [file] [log] [blame]
// Copyright 2022 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/fs_management/cpp/volumes.h"
#include <fidl/fuchsia.fxfs/cpp/markers.h>
#include <fidl/fuchsia.io/cpp/markers.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <fidl/fuchsia.io/cpp/wire_types.h>
#include <fidl/fuchsia.unknown/cpp/markers.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fidl/cpp/wire/channel.h>
#include <lib/fidl/cpp/wire/connect_service.h>
#include <lib/fidl/cpp/wire/string_view.h>
#include <lib/fit/defer.h>
#include <lib/zx/result.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <zircon/errors.h>
#include <zircon/types.h>
namespace fs_management {
namespace {
zx::result<> CheckExists(fidl::UnownedClientEnd<fuchsia_io::Directory> exposed_dir,
const std::string& path) {
// Check if the volume exists. This way, we can return an explicit NOT_FOUND if absent.
// TODO(https://fxbug.dev/42174810): Check the epitaph of the call to Mount instead.
auto [client, server] = fidl::Endpoints<fuchsia_io::Node>::Create();
auto res = fidl::WireCall(exposed_dir)
->Open(fuchsia_io::wire::OpenFlags::kNodeReference, {},
fidl::StringView::FromExternal(path), std::move(server));
if (!res.ok()) {
return zx::error(res.error().status());
}
auto query_res = fidl::WireCall(client)->Query();
if (!query_res.ok()) {
return zx::error(ZX_ERR_NOT_FOUND);
}
return zx::ok();
}
} // namespace
__EXPORT
zx::result<> CreateVolume(fidl::UnownedClientEnd<fuchsia_io::Directory> exposed_dir,
std::string_view name,
fidl::ServerEnd<fuchsia_io::Directory> outgoing_dir,
fuchsia_fxfs::wire::MountOptions options) {
auto client = component::ConnectAt<fuchsia_fxfs::Volumes>(exposed_dir);
if (client.is_error())
return client.take_error();
auto result = fidl::WireCall(*client)->Create(fidl::StringView::FromExternal(name),
std::move(outgoing_dir), std::move(options));
if (!result.ok())
return zx::error(result.error().status());
if (result->is_error())
return result->take_error();
return zx::ok();
}
__EXPORT
zx::result<> OpenVolume(fidl::UnownedClientEnd<fuchsia_io::Directory> exposed_dir,
std::string_view name, fidl::ServerEnd<fuchsia_io::Directory> outgoing_dir,
fuchsia_fxfs::wire::MountOptions options) {
std::string path = "volumes/" + std::string(name);
if (auto status = CheckExists(exposed_dir, path); status.is_error()) {
return status.take_error();
}
auto client = component::ConnectAt<fuchsia_fxfs::Volume>(exposed_dir, path.c_str());
if (client.is_error())
return client.take_error();
auto result = fidl::WireCall(*client)->Mount(std::move(outgoing_dir), std::move(options));
if (!result.ok())
return zx::error(result.error().status());
if (result->is_error())
return result->take_error();
return zx::ok();
}
__EXPORT zx::result<> CheckVolume(fidl::UnownedClientEnd<fuchsia_io::Directory> exposed_dir,
std::string_view name, zx::channel crypt_client) {
std::string path = "volumes/" + std::string(name);
if (auto status = CheckExists(exposed_dir, path); status.is_error()) {
return status.take_error();
}
auto client = component::ConnectAt<fuchsia_fxfs::Volume>(exposed_dir, path.c_str());
if (client.is_error())
return client.take_error();
fuchsia_fxfs::wire::CheckOptions options{
.crypt = fidl::ClientEnd<fuchsia_fxfs::Crypt>(std::move(crypt_client)),
};
auto result = fidl::WireCall(*client)->Check(std::move(options));
if (!result.ok())
return zx::error(result.error().status());
if (result->is_error())
return result->take_error();
return zx::ok();
}
__EXPORT bool HasVolume(fidl::UnownedClientEnd<fuchsia_io::Directory> exposed_dir,
std::string_view name) {
std::string path = "volumes/" + std::string(name);
if (auto status = CheckExists(exposed_dir, path); status.is_error()) {
return false;
}
return true;
}
} // namespace fs_management