extern "C" {
#include <sys/param.h>
#include <fcntl.h>
}
#include "mockfs.hh"
#include "utils.hh"
using namespace testing;
class Lseek: public FuseTest {};
class LseekPathconf: public Lseek {};
class LseekPathconf_7_23: public LseekPathconf {
public:
virtual void SetUp() {
m_kernel_minor_version = 23;
FuseTest::SetUp();
}
};
class LseekSeekHole: public Lseek {};
class LseekSeekData: public Lseek {};
TEST_F(LseekPathconf, already_enosys)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
off_t offset_in = 1 << 28;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnErrno(ENOSYS)));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(offset_in, lseek(fd, offset_in, SEEK_DATA));
EXPECT_EQ(-1, fpathconf(fd, _PC_MIN_HOLE_SIZE));
EXPECT_EQ(EINVAL, errno);
leak(fd);
}
TEST_F(LseekPathconf, already_seeked)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
off_t offset = 1 << 28;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto i, auto& out) {
SET_OUT_HEADER_LEN(out, lseek);
out.body.lseek.offset = i.body.lseek.offset;
})));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(offset, lseek(fd, offset, SEEK_DATA));
EXPECT_EQ(1, fpathconf(fd, _PC_MIN_HOLE_SIZE));
leak(fd);
}
TEST_F(LseekPathconf, eacces)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
EXPECT_LOOKUP(FUSE_ROOT_ID, RELPATH)
.WillOnce(Invoke(ReturnImmediate([=](auto in __unused, auto& out) {
SET_OUT_HEADER_LEN(out, entry);
out.body.entry.entry_valid = UINT64_MAX;
out.body.entry.attr.mode = S_IFREG | 0644;
out.body.entry.nodeid = ino;
out.body.entry.attr.size = fsize;
})));
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_OPEN &&
in.header.nodeid == ino);
}, Eq(true)),
_)
).Times(2)
.WillRepeatedly(Invoke(ReturnErrno(EACCES)));
EXPECT_EQ(-1, pathconf(FULLPATH, _PC_MIN_HOLE_SIZE));
EXPECT_EQ(EACCES, errno);
EXPECT_EQ(-1, pathconf(FULLPATH, _PC_MIN_HOLE_SIZE));
EXPECT_EQ(EACCES, errno);
}
TEST_F(LseekPathconf, eio)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK);
}, Eq(true)),
_)
).Times(2)
.WillRepeatedly(Invoke(ReturnErrno(EIO)));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(-1, fpathconf(fd, _PC_MIN_HOLE_SIZE));
EXPECT_EQ(EIO, errno);
EXPECT_EQ(-1, fpathconf(fd, _PC_MIN_HOLE_SIZE));
EXPECT_EQ(EIO, errno);
leak(fd);
}
TEST_F(LseekPathconf, enosys_now)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnErrno(ENOSYS)));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(-1, fpathconf(fd, _PC_MIN_HOLE_SIZE));
EXPECT_EQ(EINVAL, errno);
leak(fd);
}
TEST_F(LseekPathconf, pathconf)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
off_t offset_out = 1 << 29;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
SET_OUT_HEADER_LEN(out, lseek);
out.body.lseek.offset = offset_out;
})));
expect_release(ino, FuseTest::FH);
EXPECT_EQ(1, pathconf(FULLPATH, _PC_MIN_HOLE_SIZE)) << strerror(errno);
}
TEST_F(LseekPathconf, seek_now)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
off_t offset_initial = 1 << 27;
off_t offset_out = 1 << 29;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
SET_OUT_HEADER_LEN(out, lseek);
out.body.lseek.offset = offset_out;
})));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(offset_initial, lseek(fd, offset_initial, SEEK_SET));
EXPECT_EQ(1, fpathconf(fd, _PC_MIN_HOLE_SIZE));
EXPECT_EQ(offset_initial, lseek(fd, 0, SEEK_CUR));
leak(fd);
}
TEST_F(LseekPathconf, zerolength)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 0;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK &&
in.header.nodeid == ino &&
in.body.lseek.whence == SEEK_DATA);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnErrno(ENXIO)));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(1, fpathconf(fd, _PC_MIN_HOLE_SIZE));
EXPECT_EQ(1, fpathconf(fd, _PC_MIN_HOLE_SIZE));
leak(fd);
}
TEST_F(LseekPathconf_7_23, already_enosys)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK);
}, Eq(true)),
_)
).Times(0);
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(-1, fpathconf(fd, _PC_MIN_HOLE_SIZE));
EXPECT_EQ(EINVAL, errno);
leak(fd);
}
TEST_F(LseekSeekData, ok)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
off_t offset_in = 1 << 28;
off_t offset_out = 1 << 29;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK &&
in.header.nodeid == ino &&
in.body.lseek.fh == FH &&
(off_t)in.body.lseek.offset == offset_in &&
in.body.lseek.whence == SEEK_DATA);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
SET_OUT_HEADER_LEN(out, lseek);
out.body.lseek.offset = offset_out;
})));
fd = open(FULLPATH, O_RDONLY);
EXPECT_EQ(offset_out, lseek(fd, offset_in, SEEK_DATA));
EXPECT_EQ(offset_out, lseek(fd, 0, SEEK_CUR));
leak(fd);
}
TEST_F(LseekSeekData, enosys)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
off_t offset_in = 1 << 28;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK &&
in.header.nodeid == ino &&
in.body.lseek.fh == FH &&
(off_t)in.body.lseek.offset == offset_in &&
in.body.lseek.whence == SEEK_DATA);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnErrno(ENOSYS)));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(offset_in, lseek(fd, offset_in, SEEK_DATA));
EXPECT_EQ(-1, lseek(fd, -1, SEEK_HOLE));
EXPECT_EQ(ENXIO, errno);
EXPECT_EQ(-1, lseek(fd, fsize, SEEK_HOLE));
EXPECT_EQ(ENXIO, errno);
leak(fd);
}
TEST_F(LseekSeekHole, ok)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
off_t offset_in = 1 << 28;
off_t offset_out = 1 << 29;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK &&
in.header.nodeid == ino &&
in.body.lseek.fh == FH &&
(off_t)in.body.lseek.offset == offset_in &&
in.body.lseek.whence == SEEK_HOLE);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnImmediate([=](auto i __unused, auto& out) {
SET_OUT_HEADER_LEN(out, lseek);
out.body.lseek.offset = offset_out;
})));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(offset_out, lseek(fd, offset_in, SEEK_HOLE));
EXPECT_EQ(offset_out, lseek(fd, 0, SEEK_CUR));
leak(fd);
}
TEST_F(LseekSeekHole, enosys)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
off_t offset_in = 1 << 28;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK &&
in.header.nodeid == ino &&
in.body.lseek.fh == FH &&
(off_t)in.body.lseek.offset == offset_in &&
in.body.lseek.whence == SEEK_HOLE);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnErrno(ENOSYS)));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(fsize, lseek(fd, offset_in, SEEK_HOLE));
EXPECT_EQ(-1, lseek(fd, -1, SEEK_HOLE));
EXPECT_EQ(ENXIO, errno);
EXPECT_EQ(-1, lseek(fd, fsize, SEEK_HOLE));
EXPECT_EQ(ENXIO, errno);
leak(fd);
}
TEST_F(LseekSeekHole, enxio)
{
const char FULLPATH[] = "mountpoint/some_file.txt";
const char RELPATH[] = "some_file.txt";
const uint64_t ino = 42;
off_t fsize = 1 << 30;
off_t offset_in = fsize;
int fd;
expect_lookup(RELPATH, ino, S_IFREG | 0644, fsize, 1);
expect_open(ino, 0, 1);
EXPECT_CALL(*m_mock, process(
ResultOf([=](auto in) {
return (in.header.opcode == FUSE_LSEEK &&
in.header.nodeid == ino &&
in.body.lseek.fh == FH &&
(off_t)in.body.lseek.offset == offset_in &&
in.body.lseek.whence == SEEK_HOLE);
}, Eq(true)),
_)
).WillOnce(Invoke(ReturnErrno(ENXIO)));
fd = open(FULLPATH, O_RDONLY);
ASSERT_LE(0, fd);
EXPECT_EQ(-1, lseek(fd, offset_in, SEEK_HOLE));
EXPECT_EQ(ENXIO, errno);
leak(fd);
}