Changeset View
Changeset View
Standalone View
Standalone View
head/tests/sys/fs/fusefs/mockfs.cc
Show First 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | return([=](auto& in, auto &out) { | ||||
out.push_back(std::move(out0)); | out.push_back(std::move(out0)); | ||||
}); | }); | ||||
} | } | ||||
void sigint_handler(int __unused sig) { | void sigint_handler(int __unused sig) { | ||||
// Don't do anything except interrupt the daemon's read(2) call | // Don't do anything except interrupt the daemon's read(2) call | ||||
} | } | ||||
void MockFS::debug_request(const mockfs_buf_in &in) | void MockFS::debug_request(const mockfs_buf_in &in, ssize_t buflen) | ||||
{ | { | ||||
printf("%-11s ino=%2" PRIu64, opcode2opname(in.header.opcode), | printf("%-11s ino=%2" PRIu64, opcode2opname(in.header.opcode), | ||||
in.header.nodeid); | in.header.nodeid); | ||||
if (verbosity > 1) { | if (verbosity > 1) { | ||||
printf(" uid=%5u gid=%5u pid=%5u unique=%" PRIu64 " len=%u", | printf(" uid=%5u gid=%5u pid=%5u unique=%" PRIu64 " len=%u" | ||||
" buflen=%zd", | |||||
in.header.uid, in.header.gid, in.header.pid, | in.header.uid, in.header.gid, in.header.pid, | ||||
in.header.unique, in.header.len); | in.header.unique, in.header.len, buflen); | ||||
} | } | ||||
switch (in.header.opcode) { | switch (in.header.opcode) { | ||||
const char *name, *value; | const char *name, *value; | ||||
case FUSE_ACCESS: | case FUSE_ACCESS: | ||||
printf(" mask=%#x", in.body.access.mask); | printf(" mask=%#x", in.body.access.mask); | ||||
break; | break; | ||||
case FUSE_BMAP: | case FUSE_BMAP: | ||||
▲ Show 20 Lines • Show All 291 Lines • ▼ Show 20 Lines | if (m_daemon_id != NULL) { | ||||
m_daemon_id = NULL; | m_daemon_id = NULL; | ||||
} | } | ||||
::unmount("mountpoint", MNT_FORCE); | ::unmount("mountpoint", MNT_FORCE); | ||||
rmdir("mountpoint"); | rmdir("mountpoint"); | ||||
if (m_kq >= 0) | if (m_kq >= 0) | ||||
close(m_kq); | close(m_kq); | ||||
} | } | ||||
void MockFS::audit_request(const mockfs_buf_in &in) { | void MockFS::audit_request(const mockfs_buf_in &in, ssize_t buflen) { | ||||
uint32_t inlen = in.header.len; | uint32_t inlen = in.header.len; | ||||
size_t fih = sizeof(in.header); | size_t fih = sizeof(in.header); | ||||
switch (in.header.opcode) { | switch (in.header.opcode) { | ||||
case FUSE_LOOKUP: | case FUSE_LOOKUP: | ||||
case FUSE_RMDIR: | case FUSE_RMDIR: | ||||
case FUSE_SYMLINK: | case FUSE_SYMLINK: | ||||
case FUSE_UNLINK: | case FUSE_UNLINK: | ||||
ASSERT_GT(inlen, fih) << "Missing request filename"; | EXPECT_GT(inlen, fih) << "Missing request filename"; | ||||
// No redundant information for checking buflen | |||||
break; | break; | ||||
case FUSE_FORGET: | case FUSE_FORGET: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.forget)); | EXPECT_EQ(inlen, fih + sizeof(in.body.forget)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_GETATTR: | case FUSE_GETATTR: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.getattr)); | EXPECT_EQ(inlen, fih + sizeof(in.body.getattr)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_SETATTR: | case FUSE_SETATTR: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.setattr)); | EXPECT_EQ(inlen, fih + sizeof(in.body.setattr)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_READLINK: | case FUSE_READLINK: | ||||
ASSERT_EQ(inlen, fih) << "Unexpected request body"; | EXPECT_EQ(inlen, fih) << "Unexpected request body"; | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_MKNOD: | case FUSE_MKNOD: | ||||
{ | { | ||||
size_t s; | size_t s; | ||||
if (m_kernel_minor_version >= 12) | if (m_kernel_minor_version >= 12) | ||||
s = sizeof(in.body.mknod); | s = sizeof(in.body.mknod); | ||||
else | else | ||||
s = FUSE_COMPAT_MKNOD_IN_SIZE; | s = FUSE_COMPAT_MKNOD_IN_SIZE; | ||||
ASSERT_GE(inlen, fih + s) << "Missing request body"; | EXPECT_GE(inlen, fih + s) << "Missing request body"; | ||||
ASSERT_GT(inlen, fih + s) << "Missing request filename"; | EXPECT_GT(inlen, fih + s) << "Missing request filename"; | ||||
// No redundant information for checking buflen | |||||
break; | break; | ||||
} | } | ||||
case FUSE_MKDIR: | case FUSE_MKDIR: | ||||
ASSERT_GE(inlen, fih + sizeof(in.body.mkdir)) << | EXPECT_GE(inlen, fih + sizeof(in.body.mkdir)) << | ||||
"Missing request body"; | "Missing request body"; | ||||
ASSERT_GT(inlen, fih + sizeof(in.body.mkdir)) << | EXPECT_GT(inlen, fih + sizeof(in.body.mkdir)) << | ||||
"Missing request filename"; | "Missing request filename"; | ||||
// No redundant information for checking buflen | |||||
break; | break; | ||||
case FUSE_RENAME: | case FUSE_RENAME: | ||||
ASSERT_GE(inlen, fih + sizeof(in.body.rename)) << | EXPECT_GE(inlen, fih + sizeof(in.body.rename)) << | ||||
"Missing request body"; | "Missing request body"; | ||||
ASSERT_GT(inlen, fih + sizeof(in.body.rename)) << | EXPECT_GT(inlen, fih + sizeof(in.body.rename)) << | ||||
"Missing request filename"; | "Missing request filename"; | ||||
// No redundant information for checking buflen | |||||
break; | break; | ||||
case FUSE_LINK: | case FUSE_LINK: | ||||
ASSERT_GE(inlen, fih + sizeof(in.body.link)) << | EXPECT_GE(inlen, fih + sizeof(in.body.link)) << | ||||
"Missing request body"; | "Missing request body"; | ||||
ASSERT_GT(inlen, fih + sizeof(in.body.link)) << | EXPECT_GT(inlen, fih + sizeof(in.body.link)) << | ||||
"Missing request filename"; | "Missing request filename"; | ||||
// No redundant information for checking buflen | |||||
break; | break; | ||||
case FUSE_OPEN: | case FUSE_OPEN: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.open)); | EXPECT_EQ(inlen, fih + sizeof(in.body.open)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_READ: | case FUSE_READ: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.read)); | EXPECT_EQ(inlen, fih + sizeof(in.body.read)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_WRITE: | case FUSE_WRITE: | ||||
{ | { | ||||
size_t s; | size_t s; | ||||
if (m_kernel_minor_version >= 9) | if (m_kernel_minor_version >= 9) | ||||
s = sizeof(in.body.write); | s = sizeof(in.body.write); | ||||
else | else | ||||
s = FUSE_COMPAT_WRITE_IN_SIZE; | s = FUSE_COMPAT_WRITE_IN_SIZE; | ||||
ASSERT_GE(inlen, fih + s) << "Missing request body"; | |||||
// I suppose a 0-byte write should be allowed | // I suppose a 0-byte write should be allowed | ||||
EXPECT_GE(inlen, fih + s) << "Missing request body"; | |||||
EXPECT_EQ((size_t)buflen, fih + s + in.body.write.size); | |||||
break; | break; | ||||
} | } | ||||
case FUSE_DESTROY: | case FUSE_DESTROY: | ||||
case FUSE_STATFS: | case FUSE_STATFS: | ||||
ASSERT_EQ(inlen, fih); | EXPECT_EQ(inlen, fih); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_RELEASE: | case FUSE_RELEASE: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.release)); | EXPECT_EQ(inlen, fih + sizeof(in.body.release)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_FSYNC: | case FUSE_FSYNC: | ||||
case FUSE_FSYNCDIR: | case FUSE_FSYNCDIR: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.fsync)); | EXPECT_EQ(inlen, fih + sizeof(in.body.fsync)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_SETXATTR: | case FUSE_SETXATTR: | ||||
ASSERT_GE(inlen, fih + sizeof(in.body.setxattr)) << | EXPECT_GE(inlen, fih + sizeof(in.body.setxattr)) << | ||||
"Missing request body"; | "Missing request body"; | ||||
ASSERT_GT(inlen, fih + sizeof(in.body.setxattr)) << | EXPECT_GT(inlen, fih + sizeof(in.body.setxattr)) << | ||||
"Missing request attribute name"; | "Missing request attribute name"; | ||||
// No redundant information for checking buflen | |||||
break; | break; | ||||
case FUSE_GETXATTR: | case FUSE_GETXATTR: | ||||
ASSERT_GE(inlen, fih + sizeof(in.body.getxattr)) << | EXPECT_GE(inlen, fih + sizeof(in.body.getxattr)) << | ||||
"Missing request body"; | "Missing request body"; | ||||
ASSERT_GT(inlen, fih + sizeof(in.body.getxattr)) << | EXPECT_GT(inlen, fih + sizeof(in.body.getxattr)) << | ||||
"Missing request attribute name"; | "Missing request attribute name"; | ||||
// No redundant information for checking buflen | |||||
break; | break; | ||||
case FUSE_LISTXATTR: | case FUSE_LISTXATTR: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.listxattr)); | EXPECT_EQ(inlen, fih + sizeof(in.body.listxattr)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_REMOVEXATTR: | case FUSE_REMOVEXATTR: | ||||
ASSERT_GT(inlen, fih) << "Missing request attribute name"; | EXPECT_GT(inlen, fih) << "Missing request attribute name"; | ||||
// No redundant information for checking buflen | |||||
break; | break; | ||||
case FUSE_FLUSH: | case FUSE_FLUSH: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.flush)); | EXPECT_EQ(inlen, fih + sizeof(in.body.flush)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_INIT: | case FUSE_INIT: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.init)); | EXPECT_EQ(inlen, fih + sizeof(in.body.init)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_OPENDIR: | case FUSE_OPENDIR: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.opendir)); | EXPECT_EQ(inlen, fih + sizeof(in.body.opendir)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_READDIR: | case FUSE_READDIR: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.readdir)); | EXPECT_EQ(inlen, fih + sizeof(in.body.readdir)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_RELEASEDIR: | case FUSE_RELEASEDIR: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.releasedir)); | EXPECT_EQ(inlen, fih + sizeof(in.body.releasedir)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_GETLK: | case FUSE_GETLK: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.getlk)); | EXPECT_EQ(inlen, fih + sizeof(in.body.getlk)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_SETLK: | case FUSE_SETLK: | ||||
case FUSE_SETLKW: | case FUSE_SETLKW: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.setlk)); | EXPECT_EQ(inlen, fih + sizeof(in.body.setlk)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_ACCESS: | case FUSE_ACCESS: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.access)); | EXPECT_EQ(inlen, fih + sizeof(in.body.access)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_CREATE: | case FUSE_CREATE: | ||||
ASSERT_GE(inlen, fih + sizeof(in.body.create)) << | EXPECT_GE(inlen, fih + sizeof(in.body.create)) << | ||||
"Missing request body"; | "Missing request body"; | ||||
ASSERT_GT(inlen, fih + sizeof(in.body.create)) << | EXPECT_GT(inlen, fih + sizeof(in.body.create)) << | ||||
"Missing request filename"; | "Missing request filename"; | ||||
// No redundant information for checking buflen | |||||
break; | break; | ||||
case FUSE_INTERRUPT: | case FUSE_INTERRUPT: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.interrupt)); | EXPECT_EQ(inlen, fih + sizeof(in.body.interrupt)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_BMAP: | case FUSE_BMAP: | ||||
ASSERT_EQ(inlen, fih + sizeof(in.body.bmap)); | EXPECT_EQ(inlen, fih + sizeof(in.body.bmap)); | ||||
EXPECT_EQ((size_t)buflen, inlen); | |||||
break; | break; | ||||
case FUSE_NOTIFY_REPLY: | case FUSE_NOTIFY_REPLY: | ||||
case FUSE_BATCH_FORGET: | case FUSE_BATCH_FORGET: | ||||
case FUSE_FALLOCATE: | case FUSE_FALLOCATE: | ||||
case FUSE_IOCTL: | case FUSE_IOCTL: | ||||
case FUSE_POLL: | case FUSE_POLL: | ||||
case FUSE_READDIRPLUS: | case FUSE_READDIRPLUS: | ||||
FAIL() << "Unsupported opcode?"; | FAIL() << "Unsupported opcode?"; | ||||
default: | default: | ||||
FAIL() << "Unknown opcode " << in.header.opcode; | FAIL() << "Unknown opcode " << in.header.opcode; | ||||
} | } | ||||
} | } | ||||
void MockFS::init(uint32_t flags) { | void MockFS::init(uint32_t flags) { | ||||
ssize_t buflen; | |||||
std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in); | std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in); | ||||
std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); | std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); | ||||
read_request(*in); | read_request(*in, buflen); | ||||
audit_request(*in, buflen); | |||||
ASSERT_EQ(FUSE_INIT, in->header.opcode); | ASSERT_EQ(FUSE_INIT, in->header.opcode); | ||||
out->header.unique = in->header.unique; | out->header.unique = in->header.unique; | ||||
out->header.error = 0; | out->header.error = 0; | ||||
out->body.init.major = FUSE_KERNEL_VERSION; | out->body.init.major = FUSE_KERNEL_VERSION; | ||||
out->body.init.minor = m_kernel_minor_version;; | out->body.init.minor = m_kernel_minor_version;; | ||||
out->body.init.flags = in->body.init.flags & flags; | out->body.init.flags = in->body.init.flags & flags; | ||||
out->body.init.max_write = m_maxwrite; | out->body.init.max_write = m_maxwrite; | ||||
Show All 21 Lines | |||||
} | } | ||||
void MockFS::loop() { | void MockFS::loop() { | ||||
std::vector<std::unique_ptr<mockfs_buf_out>> out; | std::vector<std::unique_ptr<mockfs_buf_out>> out; | ||||
std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in); | std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in); | ||||
ASSERT_TRUE(in != NULL); | ASSERT_TRUE(in != NULL); | ||||
while (!m_quit) { | while (!m_quit) { | ||||
ssize_t buflen; | |||||
bzero(in.get(), sizeof(*in)); | bzero(in.get(), sizeof(*in)); | ||||
read_request(*in); | read_request(*in, buflen); | ||||
if (m_quit) | if (m_quit) | ||||
break; | break; | ||||
if (verbosity > 0) | if (verbosity > 0) | ||||
debug_request(*in); | debug_request(*in, buflen); | ||||
audit_request(*in); | audit_request(*in, buflen); | ||||
if (pid_ok((pid_t)in->header.pid)) { | if (pid_ok((pid_t)in->header.pid)) { | ||||
process(*in, out); | process(*in, out); | ||||
} else { | } else { | ||||
/* | /* | ||||
* Reject any requests from unknown processes. Because | * Reject any requests from unknown processes. Because | ||||
* we actually do mount a filesystem, plenty of | * we actually do mount a filesystem, plenty of | ||||
* unrelated system daemons may try to access it. | * unrelated system daemons may try to access it. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); | std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); | ||||
out0->header.unique = in.header.unique; | out0->header.unique = in.header.unique; | ||||
out0->header.error = -EOPNOTSUPP; | out0->header.error = -EOPNOTSUPP; | ||||
out0->header.len = sizeof(out0->header); | out0->header.len = sizeof(out0->header); | ||||
out.push_back(std::move(out0)); | out.push_back(std::move(out0)); | ||||
} | } | ||||
void MockFS::read_request(mockfs_buf_in &in) { | void MockFS::read_request(mockfs_buf_in &in, ssize_t &res) { | ||||
ssize_t res; | |||||
int nready = 0; | int nready = 0; | ||||
fd_set readfds; | fd_set readfds; | ||||
pollfd fds[1]; | pollfd fds[1]; | ||||
struct kevent changes[1]; | struct kevent changes[1]; | ||||
struct kevent events[1]; | struct kevent events[1]; | ||||
struct timespec timeout_ts; | struct timespec timeout_ts; | ||||
struct timeval timeout_tv; | struct timeval timeout_tv; | ||||
const int timeout_ms = 999; | const int timeout_ms = 999; | ||||
▲ Show 20 Lines • Show All 114 Lines • Show Last 20 Lines |