blob: 677d6c4f726c15c66b34c63858acba8684e04b7f [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/fs_test/test_filesystem.h"
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/executor.h>
#include <lib/fdio/cpp/caller.h>
#include <lib/fdio/directory.h>
#include <lib/fidl/llcpp/channel.h>
#include <lib/inspect/service/cpp/reader.h>
#include "sdk/lib/syslog/cpp/macros.h"
#include "src/storage/fs_test/crypt_service.h"
namespace fs_test {
fs_management::MountOptions TestFilesystem::DefaultMountOptions() const {
fs_management::MountOptions options;
if (options_.blob_compression_algorithm) {
options.write_compression_algorithm =
blobfs::CompressionAlgorithmToString(*options_.blob_compression_algorithm);
}
if (GetTraits().uses_crypt)
options.crypt_client = [] { return *GetCryptService(); };
return options;
}
zx::status<TestFilesystem> TestFilesystem::FromInstance(
const TestFilesystemOptions& options, std::unique_ptr<FilesystemInstance> instance) {
static uint32_t mount_index;
TestFilesystem filesystem(options, std::move(instance),
std::string("/fs_test." + std::to_string(mount_index++) + "/"));
auto status = filesystem.Mount();
if (status.is_error()) {
return status.take_error();
}
return zx::ok(std::move(filesystem));
}
zx::status<TestFilesystem> TestFilesystem::Create(const TestFilesystemOptions& options) {
auto instance_or = options.filesystem->Make(options);
if (instance_or.is_error()) {
return instance_or.take_error();
}
return FromInstance(options, std::move(instance_or).value());
}
zx::status<TestFilesystem> TestFilesystem::Open(const TestFilesystemOptions& options) {
auto instance_or = options.filesystem->Open(options);
if (instance_or.is_error()) {
return instance_or.take_error();
}
return FromInstance(options, std::move(instance_or).value());
}
TestFilesystem::~TestFilesystem() {
if (filesystem_) {
if (mounted_) {
auto status = Unmount();
if (status.is_error()) {
FX_LOGS(WARNING) << "Failed to unmount: " << status.status_string() << std::endl;
}
}
rmdir(mount_path_.c_str());
}
}
zx::status<> TestFilesystem::Mount(const fs_management::MountOptions& options) {
auto status = filesystem_->Mount(mount_path_, options);
if (status.is_ok()) {
mounted_ = true;
}
return status;
}
zx::status<> TestFilesystem::Unmount() {
if (!filesystem_) {
return zx::ok();
}
auto status = filesystem_->Unmount(mount_path_);
if (status.is_ok()) {
mounted_ = false;
}
return status;
}
zx::status<> TestFilesystem::Fsck() { return filesystem_->Fsck(); }
zx::status<std::string> TestFilesystem::DevicePath() const { return filesystem_->DevicePath(); }
zx::status<fuchsia_io::wire::FilesystemInfo> TestFilesystem::GetFsInfo() const {
fbl::unique_fd root_fd = fbl::unique_fd(open(mount_path().c_str(), O_RDONLY | O_DIRECTORY));
fdio_cpp::UnownedFdioCaller root_connection(root_fd);
const auto& result = fidl::WireCall(fidl::UnownedClientEnd<fuchsia_io::Directory>(
zx::unowned_channel(root_connection.borrow_channel())))
->QueryFilesystem();
if (!result.ok()) {
return zx::error(result.status());
}
if (result.value().s != ZX_OK) {
return zx::error(result.value().s);
}
return zx::ok(*result.value().info);
}
inspect::Hierarchy TestFilesystem::TakeSnapshot() const {
async::Loop loop = async::Loop(&kAsyncLoopConfigNoAttachToCurrentThread);
loop.StartThread("inspect-snapshot-thread");
async::Executor executor(loop.dispatcher());
fuchsia::inspect::TreePtr tree;
async_dispatcher_t* dispatcher = executor.dispatcher();
auto export_root = GetOutgoingDirectory();
ZX_ASSERT(export_root.is_valid());
zx_status_t status =
fdio_service_connect_at(export_root.handle()->get(), "diagnostics/fuchsia.inspect.Tree",
tree.NewRequest(dispatcher).TakeChannel().release());
ZX_ASSERT_MSG(status == ZX_OK, "Failed to connect to inspect service: %s",
zx_status_get_string(status));
std::condition_variable cv;
std::mutex m;
bool done = false;
fpromise::result<inspect::Hierarchy> hierarchy_or_error;
auto promise = inspect::ReadFromTree(std::move(tree))
.then([&](fpromise::result<inspect::Hierarchy>& result) {
{
std::unique_lock<std::mutex> lock(m);
hierarchy_or_error = std::move(result);
done = true;
}
cv.notify_all();
});
executor.schedule_task(std::move(promise));
std::unique_lock<std::mutex> lock(m);
cv.wait(lock, [&done]() { return done; });
loop.Quit();
loop.JoinThreads();
ZX_ASSERT_MSG(hierarchy_or_error.is_ok(), "Failed to obtain inspect tree snapshot!");
return hierarchy_or_error.take_value();
}
} // namespace fs_test