blob: 928477708c31902c74dacf93fd6c10e15b93cc09 [file] [log] [blame]
// Copyright 2023 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 <fidl/fuchsia.io.test/cpp/fidl.h>
#include <fidl/fuchsia.io/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/default.h>
#include <lib/component/outgoing/cpp/outgoing_directory.h>
#include <lib/syslog/cpp/log_settings.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/pseudo_file.h>
#include <lib/vfs/cpp/remote_dir.h>
#include <lib/vfs/cpp/vmo_file.h>
#include <zircon/status.h>
#include <cstdint>
#include <limits>
#include <memory>
#include <vector>
namespace fio_test = fuchsia_io_test;
zx_status_t DummyWriter(const std::vector<uint8_t>&) { return ZX_OK; }
class SdkCppHarness : public fidl::Server<fio_test::Io1Harness> {
public:
explicit SdkCppHarness() = default;
~SdkCppHarness() override = default;
void GetConfig(GetConfigCompleter::Sync& completer) final {
fio_test::Io1Config config;
// The SDK VFS uses the in-tree C++ VFS under the hood, and thus should support at *least* the
// same feature set. Other than adding additional supported options, the remainder of this
// test harness should be the exact same as the current SDK VFS one.
// Supported options:
config.supports_get_backing_memory(true);
config.supports_remote_dir(true);
config.supports_get_token(true);
// Unsupported options:
config.supports_create(false);
config.supports_executable_file(false);
config.supports_rename(false);
config.supports_link(false);
config.supports_set_attr(false);
config.supports_unlink(false);
config.supports_get_attributes(false);
config.supports_update_attributes(false);
config.supports_directory_watchers(false);
config.supports_open2(false);
// TODO(https://fxbug.dev/324112857): Support append when adding Open2.
config.supports_append(false);
completer.Reply(std::move(config));
}
void GetDirectory(GetDirectoryRequest& request, GetDirectoryCompleter::Sync& completer) final {
auto dir = std::make_unique<vfs::PseudoDir>();
if (request.root().entries()) {
for (auto& entry : *request.root().entries()) {
AddEntry(std::move(*entry), *dir);
}
}
// TODO(https://fxbug.dev/311176363): Support the new C++ bindings in the SDK VFS so that we can
// use `fuchsia_io::OpenFlags` instead of the deprecated HLCPP `fuchsia::io::OpenFlags` type.
fuchsia::io::OpenFlags flags = fuchsia::io::OpenFlags{static_cast<uint32_t>(request.flags())};
ZX_ASSERT_MSG(dir->Serve(flags, request.directory_request().TakeChannel()) == ZX_OK,
"Failed to serve directory!");
directories_.push_back(std::move(dir));
}
private:
// NOLINTNEXTLINE(misc-no-recursion): Test-only code, recursion is acceptable here.
void AddEntry(fio_test::DirectoryEntry entry, vfs::PseudoDir& dest) {
switch (entry.Which()) {
case fio_test::DirectoryEntry::Tag::kDirectory: {
fio_test::Directory directory = std::move(entry.directory().value());
auto dir_entry = std::make_unique<vfs::PseudoDir>();
if (directory.entries()) {
for (auto& child_entry : *directory.entries()) {
AddEntry(std::move(*child_entry), *dir_entry);
}
}
ZX_ASSERT_MSG(dest.AddEntry(*directory.name(), std::move(dir_entry)) == ZX_OK,
"Failed to add Directory entry!");
break;
}
case fio_test::DirectoryEntry::Tag::kRemoteDirectory: {
fio_test::RemoteDirectory remote_directory = std::move(entry.remote_directory().value());
// TODO(https://fxbug.dev/311176363): Support the new C++ bindings in the SDK VFS so we can
// construct a `vfs::RemoteDir` using a `fidl::ClientEnd` directly.
auto remote_dir_entry =
std::make_unique<vfs::RemoteDir>(remote_directory.remote_client()->TakeChannel());
dest.AddEntry(*remote_directory.name(), std::move(remote_dir_entry));
break;
}
case fio_test::DirectoryEntry::Tag::kFile: {
fio_test::File file = std::move(entry.file().value());
zx::vmo vmo;
zx_status_t status = zx::vmo::create(file.contents()->size(), {}, &vmo);
ZX_ASSERT_MSG(status == ZX_OK, "Failed to create VMO: %s", zx_status_get_string(status));
status = vmo.write(file.contents()->data(), 0, file.contents()->size());
ZX_ASSERT_MSG(status == ZX_OK, "Failed to write to VMO: %s", zx_status_get_string(status));
auto file_entry = std::make_unique<vfs::VmoFile>(std::move(vmo), file.contents()->size(),
vfs::VmoFile::WriteMode::kWritable);
ZX_ASSERT_MSG(dest.AddEntry(*file.name(), std::move(file_entry)) == ZX_OK,
"Failed to add File entry!");
break;
}
case fio_test::DirectoryEntry::Tag::kExecutableFile:
ZX_PANIC("Executable files are not supported!");
break;
}
}
std::vector<std::unique_ptr<vfs::PseudoDir>> directories_;
};
int main(int argc, const char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
fuchsia_logging::SetTags({"io_conformance_harness_sdkcpp_new"});
component::OutgoingDirectory outgoing(loop.dispatcher());
zx::result result = outgoing.AddProtocol<fio_test::Io1Harness>(std::make_unique<SdkCppHarness>());
ZX_ASSERT_MSG(result.is_ok(), "Failed to add protocol: %s", result.status_string());
result = outgoing.ServeFromStartupInfo();
ZX_ASSERT_MSG(result.is_ok(), "Failed to serve outgoing directory: %s", result.status_string());
return loop.Run();
}