blob: 0bd1a05405e0f1d6fe9e15e459f193e726e0afeb [file] [log] [blame]
// Copyright 2018 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 <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <threads.h>
#include <unistd.h>
#include <fbl/unique_fd.h>
#include <fuchsia/io/c/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/directory.h>
#include <lib/fzl/fdio.h>
#include <lib/memfs/memfs.h>
#include <unittest/unittest.h>
#include <zircon/device/vfs.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>
#include <utility>
namespace {
bool TestFidlBasic() {
BEGIN_TEST;
async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
ASSERT_EQ(loop.StartThread(), ZX_OK);
ASSERT_EQ(memfs_install_at(loop.dispatcher(), "/fidltmp"), ZX_OK);
fbl::unique_fd fd(open("/fidltmp", O_DIRECTORY | O_RDONLY));
ASSERT_GE(fd.get(), 0);
// Create a file
const char* filename = "file-a";
fd.reset(openat(fd.get(), filename, O_CREAT | O_RDWR));
ASSERT_GE(fd.get(), 0);
const char* data = "hello";
ssize_t datalen = strlen(data);
ASSERT_EQ(write(fd.get(), data, datalen), datalen);
fd.reset();
zx_handle_t h, request;
ASSERT_EQ(zx_channel_create(0, &h, &request), ZX_OK);
ASSERT_EQ(fdio_service_connect("/fidltmp/file-a", request), ZX_OK);
fuchsia_io_NodeInfo info = {};
ASSERT_EQ(fuchsia_io_FileDescribe(h, &info), ZX_OK);
ASSERT_EQ(info.tag, fuchsia_io_NodeInfoTag_file);
ASSERT_EQ(info.file.event, ZX_HANDLE_INVALID);
zx_handle_close(h);
loop.Shutdown();
// No way to clean up the namespace entry. See ZX-2013 for more details.
END_TEST;
}
bool TestFidlOpenReadOnly() {
BEGIN_TEST;
async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
ASSERT_EQ(loop.StartThread(), ZX_OK);
ASSERT_EQ(memfs_install_at(loop.dispatcher(), "/fidltmp-ro"), ZX_OK);
fbl::unique_fd fd(open("/fidltmp-ro", O_DIRECTORY | O_RDONLY));
ASSERT_GE(fd.get(), 0);
// Create a file
const char* filename = "file-ro";
fd.reset(openat(fd.get(), filename, O_CREAT | O_RDWR));
ASSERT_GE(fd.get(), 0);
fd.reset();
zx_handle_t h, request;
ASSERT_EQ(zx_channel_create(0, &h, &request), ZX_OK);
ASSERT_EQ(fdio_open("/fidltmp-ro/file-ro", ZX_FS_RIGHT_READABLE, request), ZX_OK);
zx_status_t status;
uint32_t flags;
ASSERT_EQ(fuchsia_io_FileGetFlags(h, &status, &flags), ZX_OK);
ASSERT_EQ(status, ZX_OK);
ASSERT_EQ(flags, ZX_FS_RIGHT_READABLE);
zx_handle_close(h);
loop.Shutdown();
// No way to clean up the namespace entry. See ZX-2013 for more details.
END_TEST;
}
bool QueryInfo(const char* path, fuchsia_io_FilesystemInfo* info) {
BEGIN_HELPER;
fbl::unique_fd fd(open(path, O_RDONLY | O_DIRECTORY));
ASSERT_TRUE(fd);
zx_status_t status;
fzl::FdioCaller caller(std::move(fd));
ASSERT_EQ(fuchsia_io_DirectoryAdminQueryFilesystem(caller.borrow_channel(), &status, info),
ZX_OK);
ASSERT_EQ(status, ZX_OK);
const char* kFsName = "memfs";
const char* name = reinterpret_cast<const char*>(info->name);
ASSERT_EQ(strncmp(name, kFsName, strlen(kFsName)), 0, "Unexpected filesystem mounted");
ASSERT_EQ(info->block_size, ZX_PAGE_SIZE);
ASSERT_EQ(info->max_filename_size, NAME_MAX);
ASSERT_EQ(info->fs_type, VFS_TYPE_MEMFS);
ASSERT_NE(info->fs_id, 0);
ASSERT_EQ(info->used_bytes % info->block_size, 0);
END_HELPER;
}
bool TestFidlQueryFilesystem() {
BEGIN_TEST;
{
async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
ASSERT_EQ(loop.StartThread(), ZX_OK);
ASSERT_EQ(memfs_install_at(loop.dispatcher(), "/fidltmp-basic"), ZX_OK);
fbl::unique_fd fd(open("/fidltmp-basic", O_DIRECTORY | O_RDONLY));
ASSERT_GE(fd.get(), 0);
// Sanity checks
fuchsia_io_FilesystemInfo info;
ASSERT_TRUE(QueryInfo("/fidltmp-basic", &info));
// Query number of blocks
uint64_t physmem_size = zx_system_get_physmem();
ASSERT_EQ(info.total_bytes, physmem_size);
ASSERT_EQ(info.used_bytes, 0);
loop.Shutdown();
}
// Query disk pressure in a page-limited scenario
{
async::Loop loop(&kAsyncLoopConfigNoAttachToThread);
ASSERT_EQ(loop.StartThread(), ZX_OK);
size_t max_num_pages = 3;
ASSERT_EQ(memfs_install_at_with_page_limit(loop.dispatcher(),
max_num_pages, "/fidltmp-limited"), ZX_OK);
fbl::unique_fd fd(open("/fidltmp-limited", O_DIRECTORY | O_RDONLY));
ASSERT_GE(fd.get(), 0);
fuchsia_io_FilesystemInfo info;
ASSERT_TRUE(QueryInfo("/fidltmp-limited", &info));
// When space is limited, total_bytes must be a multiple of block_size
ASSERT_EQ(info.total_bytes % info.block_size, 0);
// Query number of blocks
ASSERT_EQ(info.total_bytes, 3 * info.block_size);
ASSERT_EQ(info.used_bytes, 0);
// Create a file with a size smaller than ZX_PAGE_SIZE
DIR* d = fdopendir(fd.release());
const char* filename = "file-a";
fd.reset(openat(dirfd(d), filename, O_CREAT | O_RDWR));
ASSERT_GE(fd.get(), 0);
const char* data = "hello";
ssize_t datalen = strlen(data);
ASSERT_EQ(write(fd.get(), data, datalen), datalen);
// Query should now indicate an entire page is used
ASSERT_TRUE(QueryInfo("/fidltmp-limited", &info));
ASSERT_EQ(info.used_bytes, 1 * info.block_size);
// Unlink and close the file
ASSERT_EQ(unlinkat(dirfd(d), filename, 0), 0);
ASSERT_EQ(close(fd.get()), 0);
fd.reset();
// Query should now indicate 0 bytes used
ASSERT_TRUE(QueryInfo("/fidltmp-limited", &info));
ASSERT_EQ(info.used_bytes, 0);
closedir(d);
loop.Shutdown();
}
// No way to clean up the namespace entry. See ZX-2013 for more details.
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(fidl_tests)
RUN_TEST(TestFidlBasic)
RUN_TEST(TestFidlOpenReadOnly)
RUN_TEST(TestFidlQueryFilesystem)
END_TEST_CASE(fidl_tests)