extern "C" {
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
}
#include "mockfs.hh"
#include "utils.hh"
using namespace testing;
class PreInit: public FuseTest {
public:
void SetUp() {
m_no_auto_init = true;
FuseTest::SetUp();
}
};
class PreInitP: public PreInit,
public WithParamInterface<bool>
{
void SetUp() {
m_default_permissions = GetParam();
PreInit::SetUp();
}
};
static void* unmount1(void* arg __unused) {
ssize_t r;
r = unmount("mountpoint", 0);
if (r >= 0)
return 0;
else
return (void*)(intptr_t)errno;
}
TEST_F(PreInit, unmount_before_init)
{
sem_t sem0;
pthread_t th1;
ASSERT_EQ(0, sem_init(&sem0, 0, 0)) << strerror(errno);
EXPECT_CALL(*m_mock, process(
ResultOf([](auto in) {
return (in.header.opcode == FUSE_INIT);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([&](auto in, auto& out) {
SET_OUT_HEADER_LEN(out, init);
out.body.init.major = FUSE_KERNEL_VERSION;
out.body.init.minor = FUSE_KERNEL_MINOR_VERSION;
out.body.init.flags = in.body.init.flags & m_init_flags;
out.body.init.max_write = m_maxwrite;
out.body.init.max_readahead = m_maxreadahead;
out.body.init.time_gran = m_time_gran;
sem_wait(&sem0);
})));
expect_destroy(0);
ASSERT_EQ(0, pthread_create(&th1, NULL, unmount1, NULL));
nap();
sem_post(&sem0);
m_mock->join_daemon();
}
TEST_F(PreInit, signal_during_unmount_before_init)
{
sem_t sem0;
pid_t child;
ASSERT_EQ(0, sem_init(&sem0, 0, 0)) << strerror(errno);
EXPECT_CALL(*m_mock, process(
ResultOf([](auto in) {
return (in.header.opcode == FUSE_INIT);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([&](auto in, auto& out) {
SET_OUT_HEADER_LEN(out, init);
out.body.init.major = FUSE_KERNEL_VERSION;
out.body.init.minor = 19;
out.body.init.flags = in.body.init.flags & m_init_flags;
out.body.init.max_write = m_maxwrite;
out.body.init.max_readahead = m_maxreadahead;
out.body.init.time_gran = m_time_gran;
sem_wait(&sem0);
})));
if ((child = ::fork()) == 0) {
(void) unmount("mountpoint", 0);
_exit(0);
} else if (child > 0) {
nap();
kill(child, SIGINT);
waitpid(child, NULL, WEXITED);
} else {
FAIL() << strerror(errno);
}
m_mock->m_quit = true;
sem_post(&sem0);
m_mock->join_daemon();
}
TEST_P(PreInitP, getattr_before_init)
{
struct stat sb;
nlink_t nlink = 12345;
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_INIT);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([&](auto in, auto& out) {
SET_OUT_HEADER_LEN(out, init);
out.body.init.major = FUSE_KERNEL_VERSION;
out.body.init.minor = FUSE_KERNEL_MINOR_VERSION;
out.body.init.flags = in.body.init.flags & m_init_flags;
out.body.init.max_write = m_maxwrite;
out.body.init.max_readahead = m_maxreadahead;
out.body.init.time_gran = m_time_gran;
nap();
})));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_GETATTR &&
in.header.nodeid == FUSE_ROOT_ID);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto& in, auto& out) {
SET_OUT_HEADER_LEN(out, attr);
out.body.attr.attr.ino = in.header.nodeid;
out.body.attr.attr.mode = S_IFDIR | 0644;
out.body.attr.attr.nlink = nlink;
out.body.attr.attr_valid = UINT64_MAX;
})));
EXPECT_EQ(0, stat("mountpoint", &sb));
EXPECT_EQ(nlink, sb.st_nlink);
}
INSTANTIATE_TEST_SUITE_P(PI, PreInitP, Bool());