blob: 181b64888cebf5a68b17168e437e45cace92a102 [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.
// These tests verify basic functionality of `vfs::RemoteDir`. For more comprehensive tests, see
// //src/storage/lib/vfs/cpp and //src/storage/conformance.
#include <fcntl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/remote_dir.h>
#include <lib/vfs/cpp/vmo_file.h>
#include <zircon/status.h>
#include <memory>
#include <fbl/unique_fd.h>
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"
namespace {
// Fixture sets up the following hierarchy:
//
// root/
// remote_dir/
// file
//
class RemoteDirTest : public ::gtest::RealLoopFixture {
protected:
void SetUp() override {
// Create a pseudo-directory with a file in it.
remote_dir_ = std::make_unique<vfs::PseudoDir>();
constexpr size_t kFileSize = 100;
zx::vmo vmo;
ASSERT_EQ(zx::vmo::create(kFileSize, 0, &vmo), ZX_OK);
auto file = std::make_unique<vfs::VmoFile>(std::move(vmo), kFileSize);
ASSERT_EQ(remote_dir_->AddEntry("file", std::move(file)), ZX_OK);
// Serve the pseudo-dir and use it to create a remote node.
zx::channel remote_client, remote_server;
ASSERT_EQ(zx::channel::create(0, &remote_client, &remote_server), ZX_OK);
ASSERT_EQ(remote_dir_->Serve(fuchsia::io::OpenFlags::RIGHT_READABLE, std::move(remote_server)),
ZX_OK);
auto remote_node = std::make_unique<vfs::RemoteDir>(std::move(remote_client));
// Create the root directory and add the remote node.
root_ = std::make_unique<vfs::PseudoDir>();
ASSERT_EQ(root_->AddEntry("remote_dir", std::move(remote_node)), ZX_OK);
zx::channel root_server;
ASSERT_EQ(zx::channel::create(0, &root_client_, &root_server), ZX_OK);
ASSERT_EQ(root_->Serve(
fuchsia::io::OpenFlags::RIGHT_READABLE | fuchsia::io::OpenFlags::RIGHT_WRITABLE,
std::move(root_server)),
ZX_OK);
}
// Consumes and opens the root connection as a file descriptor. This must be called from a
// different thread than the one serving the connection.
fbl::unique_fd open_root_fd() {
ZX_ASSERT_MSG(root_client_.is_valid(), "open_root_fd() can only be called once per test!");
fbl::unique_fd fd;
zx_status_t status = fdio_fd_create(root_client_.release(), fd.reset_and_get_address());
ZX_ASSERT_MSG(status == ZX_OK, "Failed to create fd: %s", zx_status_get_string(status));
return fd;
}
private:
std::unique_ptr<vfs::PseudoDir> root_;
std::unique_ptr<vfs::PseudoDir> remote_dir_;
zx::channel root_client_;
};
TEST_F(RemoteDirTest, Open) {
PerformBlockingWork([this] {
auto root = open_root_fd();
// We should be able to cross the remote mount point and open the file as read-only.
fbl::unique_fd file;
zx_status_t status =
fdio_open_fd_at(root.get(), "remote_dir/file", O_RDONLY, file.reset_and_get_address());
ASSERT_EQ(status, ZX_OK) << zx_status_get_string(status);
// We should not be able to open the file as writable since the remote only has read access.
status = fdio_open_fd_at(root.get(), "remote_dir/file", O_RDWR, file.reset_and_get_address());
ASSERT_EQ(status, ZX_ERR_ACCESS_DENIED) << zx_status_get_string(status);
});
}
} // namespace