blob: bd75a26e59d789aded6ca814df309176716f8f93 [file] [log] [blame]
// Copyright 2017 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 <sys/types.h>
#include <threads.h>
#include <unistd.h>
#include <async/cpp/loop.h>
#include <fdio/util.h>
#include <memfs/memfs.h>
#include <unittest/unittest.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>
namespace {
bool test_memfs_null() {
BEGIN_TEST;
async::Loop loop;
memfs_filesystem_t* vfs;
zx_handle_t root;
ASSERT_EQ(memfs_create_filesystem(loop.async(), &vfs, &root), ZX_OK);
ASSERT_EQ(zx_handle_close(root), ZX_OK);
loop.Shutdown();
ASSERT_EQ(memfs_free_filesystem(vfs, 0), ZX_OK);
END_TEST;
}
bool test_memfs_basic() {
BEGIN_TEST;
async::Loop loop;
ASSERT_EQ(loop.StartThread(), ZX_OK);
// Create a memfs filesystem, acquire a file descriptor
memfs_filesystem_t* vfs;
zx_handle_t root;
ASSERT_EQ(memfs_create_filesystem(loop.async(), &vfs, &root), ZX_OK);
uint32_t type = PA_FDIO_REMOTE;
int fd;
ASSERT_EQ(fdio_create_fd(&root, &type, 1, &fd), ZX_OK);
// Access files within the filesystem.
DIR* d = fdopendir(fd);
// Create a file
const char* filename = "file-a";
fd = openat(dirfd(d), filename, O_CREAT | O_RDWR);
ASSERT_GE(fd, 0);
const char* data = "hello";
ssize_t datalen = strlen(data);
ASSERT_EQ(write(fd, data, datalen), datalen);
ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
char buf[32];
ASSERT_EQ(read(fd, buf, sizeof(buf)), datalen);
ASSERT_EQ(memcmp(buf, data, datalen), 0);
// Readdir the file
struct dirent* de;
ASSERT_NONNULL((de = readdir(d)));
ASSERT_EQ(strcmp(de->d_name, "."), 0);
ASSERT_NONNULL((de = readdir(d)));
ASSERT_EQ(strcmp(de->d_name, filename), 0);
ASSERT_NULL(readdir(d));
ASSERT_EQ(closedir(d), 0);
loop.Shutdown();
ASSERT_EQ(memfs_free_filesystem(vfs, 0), ZX_OK);
END_TEST;
}
bool test_memfs_close_during_access() {
BEGIN_TEST;
async::Loop loop;
ASSERT_EQ(loop.StartThread(), ZX_OK);
// Create a memfs filesystem, acquire a file descriptor
memfs_filesystem_t* vfs;
zx_handle_t root;
ASSERT_EQ(memfs_create_filesystem(loop.async(), &vfs, &root), ZX_OK);
uint32_t type = PA_FDIO_REMOTE;
int fd;
ASSERT_EQ(fdio_create_fd(&root, &type, 1, &fd), ZX_OK);
// Access files within the filesystem.
DIR* d = fdopendir(fd);
thrd_t worker;
ASSERT_EQ(thrd_create(&worker, [](void* arg) {
DIR* d = (DIR*) arg;
while (true) {
int fd = openat(dirfd(d), "foo", O_CREAT | O_RDWR);
if (fd < 0) {
break;
}
close(fd);
unlinkat(dirfd(d), "foo", 0);
}
return 0;
}, d), thrd_success);
// Give the background thread a little time to try accessing
// the filesystem.
usleep(1000);
loop.Shutdown();
ASSERT_EQ(memfs_free_filesystem(vfs, 0), ZX_OK);
int result;
ASSERT_EQ(thrd_join(worker, &result), thrd_success);
// Now that the filesystem has terminated, we should be
// unable to access it.
ASSERT_LT(openat(dirfd(d), "foo", O_CREAT | O_RDWR), 0);
ASSERT_EQ(errno, EPIPE, "Expected connection to remote server to be closed");
// Since the message loop has terminated, this will
// only close the client side of the connection.
ASSERT_EQ(closedir(d), 0);
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(memfs_tests)
RUN_TEST(test_memfs_null)
RUN_TEST(test_memfs_basic)
RUN_TEST(test_memfs_close_during_access)
END_TEST_CASE(memfs_tests)