extern "C" {
#include <fcntl.h>
}
#include "mockfs.hh"
#include "utils.hh"
using namespace testing;
class Mkdir: public FuseTest {};
class Mkdir_7_8: public FuseTest {
public:
virtual void SetUp() {
m_kernel_minor_version = 8;
FuseTest::SetUp();
}
};
TEST_F(Mkdir, emlink)
{
const char FULLPATH[] = "mountpoint/some_dir";
const char RELPATH[] = "some_dir";
mode_t mode = 0755;
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
.WillOnce(Invoke(ReturnErrno(ENOENT)));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
const char *name = (const char*)in.body.bytes +
sizeof(fuse_mkdir_in);
return (in.header.opcode == FUSE_MKDIR &&
in.body.mkdir.mode == (S_IFDIR | mode) &&
(0 == strcmp(RELPATH, name)));
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnErrno(EMLINK)));
ASSERT_NE(1, mkdir(FULLPATH, mode));
ASSERT_EQ(EMLINK, errno);
}
TEST_F(Mkdir, entry_cache_negative)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
mode_t mode = 0755;
uint64_t ino = 42;
struct timespec entry_valid = {.tv_sec = 0, .tv_nsec = 0};
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
.WillOnce(ReturnNegativeCache(&entry_valid));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
const char *name = (const char*)in.body.bytes +
sizeof(fuse_open_in);
return (in.header.opcode == FUSE_MKDIR &&
in.body.mkdir.mode == (S_IFDIR | mode) &&
(0 == strcmp(RELPATH, name)));
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
SET_OUT_HEADER_LEN(out, entry);
out.body.create.entry.attr.mode = S_IFDIR | mode;
out.body.create.entry.nodeid = ino;
out.body.create.entry.entry_valid = UINT64_MAX;
out.body.create.entry.attr_valid = UINT64_MAX;
})));
ASSERT_EQ(0, mkdir(FULLPATH, mode)) << strerror(errno);
}
TEST_F(Mkdir, entry_cache_negative_purge)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
mode_t mode = 0755;
uint64_t ino = 42;
struct timespec entry_valid = {.tv_sec = TIME_T_MAX, .tv_nsec = 0};
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
.Times(1)
.WillOnce(Invoke(ReturnNegativeCache(&entry_valid)))
.RetiresOnSaturation();
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
const char *name = (const char*)in.body.bytes +
sizeof(fuse_open_in);
return (in.header.opcode == FUSE_MKDIR &&
in.body.mkdir.mode == (S_IFDIR | mode) &&
(0 == strcmp(RELPATH, name)));
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
SET_OUT_HEADER_LEN(out, entry);
out.body.entry.attr.mode = S_IFDIR | mode;
out.body.entry.nodeid = ino;
out.body.entry.attr_valid = UINT64_MAX;
})));
ASSERT_EQ(0, mkdir(FULLPATH, mode)) << strerror(errno);
expect_lookup(RELPATH, ino, S_IFDIR | mode, 0, 1);
ASSERT_EQ(0, access(FULLPATH, F_OK)) << strerror(errno);
}
TEST_F(Mkdir, ok)
{
const char FULLPATH[] = "mountpoint/some_dir";
const char RELPATH[] = "some_dir";
mode_t mode = 0755;
uint64_t ino = 42;
mode_t mask;
mask = umask(0);
(void)umask(mask);
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
.WillOnce(Invoke(ReturnErrno(ENOENT)));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
const char *name = (const char*)in.body.bytes +
sizeof(fuse_mkdir_in);
return (in.header.opcode == FUSE_MKDIR &&
in.body.mkdir.mode == (S_IFDIR | mode) &&
in.body.mkdir.umask == mask &&
(0 == strcmp(RELPATH, name)));
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
SET_OUT_HEADER_LEN(out, entry);
out.body.create.entry.attr.mode = S_IFDIR | mode;
out.body.create.entry.nodeid = ino;
out.body.create.entry.entry_valid = UINT64_MAX;
out.body.create.entry.attr_valid = UINT64_MAX;
})));
ASSERT_EQ(0, mkdir(FULLPATH, mode)) << strerror(errno);
}
TEST_F(Mkdir, parent_inode)
{
const char FULLPATH[] = "mountpoint/parent/some_dir";
const char PPATH[] = "parent";
const char RELPATH[] = "some_dir";
mode_t mode = 0755;
uint64_t ino = 42;
mode_t mask;
mask = umask(0);
(void)umask(mask);
expect_lookup(PPATH, ino, S_IFDIR | 0755, 0, 1);
EXPECT_LOOKUP(ino, RELPATH)
.WillOnce(Invoke(ReturnErrno(ENOENT)));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
const char *name = (const char*)in.body.bytes +
sizeof(fuse_mkdir_in);
return (in.header.opcode == FUSE_MKDIR &&
in.body.mkdir.mode == (S_IFDIR | mode) &&
in.body.mkdir.umask == mask &&
(0 == strcmp(RELPATH, name)));
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
SET_OUT_HEADER_LEN(out, entry);
out.body.create.entry.attr.mode = S_IFDIR | mode;
out.body.create.entry.nodeid = ino;
out.body.create.entry.entry_valid = UINT64_MAX;
out.body.create.entry.attr_valid = UINT64_MAX;
})));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_FORGET);
}, Eq(true)),
_)
).Times(AtMost(1))
.WillOnce(Invoke([=](auto in __unused, auto &out __unused) { }));
ASSERT_EQ(-1, mkdir(FULLPATH, mode));
ASSERT_EQ(EIO, errno);
}
TEST_F(Mkdir_7_8, ok)
{
const char FULLPATH[] = "mountpoint/some_dir";
const char RELPATH[] = "some_dir";
mode_t mode = 0755;
uint64_t ino = 42;
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
.WillOnce(Invoke(ReturnErrno(ENOENT)));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
const char *name = (const char*)in.body.bytes +
sizeof(fuse_mkdir_in);
return (in.header.opcode == FUSE_MKDIR &&
in.body.mkdir.mode == (S_IFDIR | mode) &&
(0 == strcmp(RELPATH, name)));
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
SET_OUT_HEADER_LEN(out, entry_7_8);
out.body.create.entry.attr.mode = S_IFDIR | mode;
out.body.create.entry.nodeid = ino;
out.body.create.entry.entry_valid = UINT64_MAX;
out.body.create.entry.attr_valid = UINT64_MAX;
})));
ASSERT_EQ(0, mkdir(FULLPATH, mode)) << strerror(errno);
}