Changeset View
Changeset View
Standalone View
Standalone View
head/tests/sys/fs/fusefs/rename.cc
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | class Rename: public FuseTest { | ||||
virtual void TearDown() { | virtual void TearDown() { | ||||
if (tmpfd >= 0) { | if (tmpfd >= 0) { | ||||
close(tmpfd); | close(tmpfd); | ||||
unlink(tmpfile); | unlink(tmpfile); | ||||
} | } | ||||
FuseTest::TearDown(); | FuseTest::TearDown(); | ||||
} | } | ||||
void expect_getattr(uint64_t ino, mode_t mode) | |||||
{ | |||||
EXPECT_CALL(*m_mock, process( | |||||
ResultOf([=](auto in) { | |||||
return (in.header.opcode == FUSE_GETATTR && | |||||
in.header.nodeid == ino); | |||||
}, Eq(true)), | |||||
_) | |||||
).WillOnce(Invoke( | |||||
ReturnImmediate([=](auto i __unused, auto& out) { | |||||
SET_OUT_HEADER_LEN(out, attr); | |||||
out.body.attr.attr.ino = ino; // Must match nodeid | |||||
out.body.attr.attr.mode = mode; | |||||
out.body.attr.attr_valid = UINT64_MAX; | |||||
}))); | |||||
} | |||||
}; | }; | ||||
// EINVAL, dst is subdir of src | // EINVAL, dst is subdir of src | ||||
TEST_F(Rename, einval) | TEST_F(Rename, einval) | ||||
{ | { | ||||
const char FULLDST[] = "mountpoint/src/dst"; | const char FULLDST[] = "mountpoint/src/dst"; | ||||
const char RELDST[] = "dst"; | const char RELDST[] = "dst"; | ||||
const char FULLSRC[] = "mountpoint/src"; | const char FULLSRC[] = "mountpoint/src"; | ||||
const char RELSRC[] = "src"; | const char RELSRC[] = "src"; | ||||
uint64_t src_ino = 42; | uint64_t src_ino = 42; | ||||
expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); | |||||
expect_lookup(RELSRC, src_ino, S_IFDIR | 0755, 0, 2); | expect_lookup(RELSRC, src_ino, S_IFDIR | 0755, 0, 2); | ||||
EXPECT_LOOKUP(src_ino, RELDST).WillOnce(Invoke(ReturnErrno(ENOENT))); | EXPECT_LOOKUP(src_ino, RELDST).WillOnce(Invoke(ReturnErrno(ENOENT))); | ||||
ASSERT_NE(0, rename(FULLSRC, FULLDST)); | ASSERT_NE(0, rename(FULLSRC, FULLDST)); | ||||
ASSERT_EQ(EINVAL, errno); | ASSERT_EQ(EINVAL, errno); | ||||
} | } | ||||
// source does not exist | // source does not exist | ||||
Show All 24 Lines | TEST_F(Rename, entry_cache_negative) | ||||
uint64_t ino = 42; | uint64_t ino = 42; | ||||
/* | /* | ||||
* Set entry_valid = 0 because this test isn't concerned with whether | * Set entry_valid = 0 because this test isn't concerned with whether | ||||
* or not we actually cache negative entries, only with whether we | * or not we actually cache negative entries, only with whether we | ||||
* interpret negative cache responses correctly. | * interpret negative cache responses correctly. | ||||
*/ | */ | ||||
struct timespec entry_valid = {.tv_sec = 0, .tv_nsec = 0}; | struct timespec entry_valid = {.tv_sec = 0, .tv_nsec = 0}; | ||||
expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); | |||||
expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); | expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); | ||||
/* LOOKUP returns a negative cache entry for dst */ | /* LOOKUP returns a negative cache entry for dst */ | ||||
EXPECT_LOOKUP(FUSE_ROOT_ID, RELDST) | EXPECT_LOOKUP(FUSE_ROOT_ID, RELDST) | ||||
.WillOnce(ReturnNegativeCache(&entry_valid)); | .WillOnce(ReturnNegativeCache(&entry_valid)); | ||||
EXPECT_CALL(*m_mock, process( | EXPECT_CALL(*m_mock, process( | ||||
ResultOf([=](auto in) { | ResultOf([=](auto in) { | ||||
const char *src = (const char*)in.body.bytes + | const char *src = (const char*)in.body.bytes + | ||||
Show All 18 Lines | TEST_F(Rename, entry_cache_negative_purge) | ||||
const char FULLDST[] = "mountpoint/dst"; | const char FULLDST[] = "mountpoint/dst"; | ||||
const char RELDST[] = "dst"; | const char RELDST[] = "dst"; | ||||
const char FULLSRC[] = "mountpoint/src"; | const char FULLSRC[] = "mountpoint/src"; | ||||
const char RELSRC[] = "src"; | const char RELSRC[] = "src"; | ||||
uint64_t dst_dir_ino = FUSE_ROOT_ID; | uint64_t dst_dir_ino = FUSE_ROOT_ID; | ||||
uint64_t ino = 42; | uint64_t ino = 42; | ||||
struct timespec entry_valid = {.tv_sec = TIME_T_MAX, .tv_nsec = 0}; | struct timespec entry_valid = {.tv_sec = TIME_T_MAX, .tv_nsec = 0}; | ||||
expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); | |||||
expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); | expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); | ||||
/* LOOKUP returns a negative cache entry for dst */ | /* LOOKUP returns a negative cache entry for dst */ | ||||
EXPECT_LOOKUP(FUSE_ROOT_ID, RELDST) | EXPECT_LOOKUP(FUSE_ROOT_ID, RELDST) | ||||
.WillOnce(ReturnNegativeCache(&entry_valid)) | .WillOnce(ReturnNegativeCache(&entry_valid)) | ||||
.RetiresOnSaturation(); | .RetiresOnSaturation(); | ||||
EXPECT_CALL(*m_mock, process( | EXPECT_CALL(*m_mock, process( | ||||
ResultOf([=](auto in) { | ResultOf([=](auto in) { | ||||
Show All 21 Lines | TEST_F(Rename, exdev) | ||||
const char FULLB[] = "mountpoint/src"; | const char FULLB[] = "mountpoint/src"; | ||||
const char RELB[] = "src"; | const char RELB[] = "src"; | ||||
// FUSE hardcodes the mountpoint to inode 1 | // FUSE hardcodes the mountpoint to inode 1 | ||||
uint64_t b_ino = 42; | uint64_t b_ino = 42; | ||||
tmpfd = mkstemp(tmpfile); | tmpfd = mkstemp(tmpfile); | ||||
ASSERT_LE(0, tmpfd) << strerror(errno); | ASSERT_LE(0, tmpfd) << strerror(errno); | ||||
expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); | |||||
expect_lookup(RELB, b_ino, S_IFREG | 0644, 0, 2); | expect_lookup(RELB, b_ino, S_IFREG | 0644, 0, 2); | ||||
ASSERT_NE(0, rename(tmpfile, FULLB)); | ASSERT_NE(0, rename(tmpfile, FULLB)); | ||||
ASSERT_EQ(EXDEV, errno); | ASSERT_EQ(EXDEV, errno); | ||||
ASSERT_NE(0, rename(FULLB, tmpfile)); | ASSERT_NE(0, rename(FULLB, tmpfile)); | ||||
ASSERT_EQ(EXDEV, errno); | ASSERT_EQ(EXDEV, errno); | ||||
} | } | ||||
TEST_F(Rename, ok) | TEST_F(Rename, ok) | ||||
{ | { | ||||
const char FULLDST[] = "mountpoint/dst"; | const char FULLDST[] = "mountpoint/dst"; | ||||
const char RELDST[] = "dst"; | const char RELDST[] = "dst"; | ||||
const char FULLSRC[] = "mountpoint/src"; | const char FULLSRC[] = "mountpoint/src"; | ||||
const char RELSRC[] = "src"; | const char RELSRC[] = "src"; | ||||
uint64_t dst_dir_ino = FUSE_ROOT_ID; | uint64_t dst_dir_ino = FUSE_ROOT_ID; | ||||
uint64_t ino = 42; | uint64_t ino = 42; | ||||
expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); | |||||
expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); | expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); | ||||
EXPECT_LOOKUP(FUSE_ROOT_ID, RELDST) | EXPECT_LOOKUP(FUSE_ROOT_ID, RELDST) | ||||
.WillOnce(Invoke(ReturnErrno(ENOENT))); | .WillOnce(Invoke(ReturnErrno(ENOENT))); | ||||
EXPECT_CALL(*m_mock, process( | EXPECT_CALL(*m_mock, process( | ||||
ResultOf([=](auto in) { | ResultOf([=](auto in) { | ||||
const char *src = (const char*)in.body.bytes + | const char *src = (const char*)in.body.bytes + | ||||
sizeof(fuse_rename_in); | sizeof(fuse_rename_in); | ||||
Show All 19 Lines | TEST_F(Rename, parent) | ||||
const char RELSRC[] = "src"; | const char RELSRC[] = "src"; | ||||
const char FULLDSTPARENT[] = "mountpoint/dstdir/dst/.."; | const char FULLDSTPARENT[] = "mountpoint/dstdir/dst/.."; | ||||
Sequence seq; | Sequence seq; | ||||
uint64_t dst_dir_ino = 43; | uint64_t dst_dir_ino = 43; | ||||
uint64_t ino = 42; | uint64_t ino = 42; | ||||
struct stat sb; | struct stat sb; | ||||
expect_lookup(RELSRC, ino, S_IFDIR | 0755, 0, 1); | expect_lookup(RELSRC, ino, S_IFDIR | 0755, 0, 1); | ||||
expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); | |||||
EXPECT_LOOKUP(FUSE_ROOT_ID, RELDSTDIR) | EXPECT_LOOKUP(FUSE_ROOT_ID, RELDSTDIR) | ||||
.WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { | .WillRepeatedly(Invoke(ReturnImmediate([=](auto in __unused, auto& out) { | ||||
SET_OUT_HEADER_LEN(out, entry); | SET_OUT_HEADER_LEN(out, entry); | ||||
out.body.entry.nodeid = dst_dir_ino; | out.body.entry.nodeid = dst_dir_ino; | ||||
out.body.entry.entry_valid = UINT64_MAX; | out.body.entry.entry_valid = UINT64_MAX; | ||||
out.body.entry.attr_valid = UINT64_MAX; | out.body.entry.attr_valid = UINT64_MAX; | ||||
out.body.entry.attr.mode = S_IFDIR | 0755; | out.body.entry.attr.mode = S_IFDIR | 0755; | ||||
out.body.entry.attr.ino = dst_dir_ino; | out.body.entry.attr.ino = dst_dir_ino; | ||||
Show All 35 Lines | TEST_F(Rename, overwrite) | ||||
const char RELDST[] = "dst"; | const char RELDST[] = "dst"; | ||||
const char FULLSRC[] = "mountpoint/src"; | const char FULLSRC[] = "mountpoint/src"; | ||||
const char RELSRC[] = "src"; | const char RELSRC[] = "src"; | ||||
// The inode of the already-existing destination file | // The inode of the already-existing destination file | ||||
uint64_t dst_ino = 2; | uint64_t dst_ino = 2; | ||||
uint64_t dst_dir_ino = FUSE_ROOT_ID; | uint64_t dst_dir_ino = FUSE_ROOT_ID; | ||||
uint64_t ino = 42; | uint64_t ino = 42; | ||||
expect_getattr(FUSE_ROOT_ID, S_IFDIR | 0755); | |||||
expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); | expect_lookup(RELSRC, ino, S_IFREG | 0644, 0, 1); | ||||
expect_lookup(RELDST, dst_ino, S_IFREG | 0644, 0, 1); | expect_lookup(RELDST, dst_ino, S_IFREG | 0644, 0, 1); | ||||
EXPECT_CALL(*m_mock, process( | EXPECT_CALL(*m_mock, process( | ||||
ResultOf([=](auto in) { | ResultOf([=](auto in) { | ||||
const char *src = (const char*)in.body.bytes + | const char *src = (const char*)in.body.bytes + | ||||
sizeof(fuse_rename_in); | sizeof(fuse_rename_in); | ||||
const char *dst = src + strlen(src) + 1; | const char *dst = src + strlen(src) + 1; | ||||
return (in.header.opcode == FUSE_RENAME && | return (in.header.opcode == FUSE_RENAME && | ||||
Show All 9 Lines |