Decouple stat. Dokan in Windows and Fuse in Linux use different structs for that.

This commit is contained in:
Sebastian Messmer 2018-09-13 20:45:31 -07:00
parent d6b1a6e25d
commit 01dece6cd0
22 changed files with 169 additions and 145 deletions

View File

@ -157,23 +157,25 @@ const blockstore::BlockId &CryNode::blockId() const {
return _blockId;
}
void CryNode::stat(struct ::stat *result) const {
CryNode::stat_info CryNode::stat() const {
device()->callFsActionCallbacks();
if(_parent == none) {
stat_info result;
//We are the root directory.
//TODO What should we do?
result->st_uid = getuid();
result->st_gid = getgid();
result->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
result->st_size = fsblobstore::DirBlob::DIR_LSTAT_SIZE;
//TODO What should we do?
result.uid = getuid();
result.gid = getgid();
result.mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
result.size = fsblobstore::DirBlob::DIR_LSTAT_SIZE;
//TODO If possible without performance loss, then for a directory, st_nlink should return number of dir entries (including "." and "..")
result->st_nlink = 1;
result.nlink = 1;
struct timespec now = cpputils::time::now();
result->st_atim = now;
result->st_mtim = now;
result->st_ctim = now;
result.atime = now;
result.mtime = now;
result.ctime = now;
return result;
} else {
(*_parent)->statChild(_blockId, result);
return (*_parent)->statChild(_blockId);
}
}

View File

@ -17,7 +17,7 @@ public:
// TODO grandparent is only needed to set the timestamps of the parent directory on rename and remove. Delete grandparent parameter once we store timestamps in the blob itself instead of in the directory listing.
CryNode(CryDevice *device, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::BlockId &blockId);
void access(int mask) const override;
void stat(struct ::stat *result) const override;
stat_info stat() const override;
void chmod(mode_t mode) override;
void chown(uid_t uid, gid_t gid) override;
void rename(const boost::filesystem::path &to) override;

View File

@ -30,10 +30,9 @@ void CryOpenFile::flush() {
_parent->flush();
}
void CryOpenFile::stat(struct ::stat *result) const {
fspp::Node::stat_info CryOpenFile::stat() const {
_device->callFsActionCallbacks();
result->st_size = _fileBlob->size();
_parent->statChildWithSizeAlreadySet(_fileBlob->blockId(), result);
return _parent->statChildWithKnownSize(_fileBlob->blockId(), _fileBlob->size());
}
void CryOpenFile::truncate(off_t size) const {

View File

@ -14,7 +14,7 @@ public:
explicit CryOpenFile(const CryDevice *device, std::shared_ptr<parallelaccessfsblobstore::DirBlobRef> parent, cpputils::unique_ref<parallelaccessfsblobstore::FileBlobRef> fileBlob);
~CryOpenFile();
void stat(struct ::stat *result) const override;
stat_info stat() const override;
void truncate(off_t size) const override;
size_t read(void *buf, size_t count, off_t offset) const override;
void write(const void *buf, size_t count, off_t offset) override;

View File

@ -5,6 +5,7 @@
#include "FsBlobRef.h"
#include "../fsblobstore/DirBlob.h"
#include "../fsblobstore/utils/TimestampUpdateBehavior.h"
#include <fspp/fs_interface/Node.h>
namespace cryfs {
namespace cachingfsblobstore {
@ -53,12 +54,12 @@ public:
return _base->RenameChild(blockId, newName, onOverwritten);
}
void statChild(const blockstore::BlockId &blockId, struct ::stat *result) const {
return _base->statChild(blockId, result);
fspp::Node::stat_info statChild(const blockstore::BlockId &blockId) const {
return _base->statChild(blockId);
}
void statChildWithSizeAlreadySet(const blockstore::BlockId &blockId, struct ::stat *result) const {
return _base->statChildWithSizeAlreadySet(blockId, result);
fspp::Node::stat_info statChildWithKnownSize(const blockstore::BlockId &blockId, uint64_t size) const {
return _base->statChildWithKnownSize(blockId, size);
}
void updateAccessTimestampForChild(const blockstore::BlockId &blockId, fsblobstore::TimestampUpdateBehavior timestampUpdateBehavior) {

View File

@ -132,28 +132,30 @@ off_t DirBlob::lstat_size() const {
return DIR_LSTAT_SIZE;
}
void DirBlob::statChild(const BlockId &blockId, struct ::stat *result) const {
result->st_size = _getLstatSize(blockId);
statChildWithSizeAlreadySet(blockId, result);
fspp::Node::stat_info DirBlob::statChild(const BlockId &blockId) const {
return statChildWithKnownSize(blockId, _getLstatSize(blockId));
}
void DirBlob::statChildWithSizeAlreadySet(const BlockId &blockId, struct ::stat *result) const {
fspp::Node::stat_info DirBlob::statChildWithKnownSize(const BlockId &blockId, uint64_t size) const {
fspp::Node::stat_info result;
auto childOpt = GetChild(blockId);
if (childOpt == boost::none) {
throw fspp::fuse::FuseErrnoException(ENOENT);
}
const auto &child = *childOpt;
result->st_mode = child.mode();
result->st_uid = child.uid();
result->st_gid = child.gid();
result.mode = child.mode();
result.uid = child.uid();
result.gid = child.gid();
//TODO If possible without performance loss, then for a directory, st_nlink should return number of dir entries (including "." and "..")
result->st_nlink = 1;
result->st_atim = child.lastAccessTime();
result->st_mtim = child.lastModificationTime();
result->st_ctim = child.lastMetadataChangeTime();
result.nlink = 1;
result.size = size;
result.atime = child.lastAccessTime();
result.mtime = child.lastModificationTime();
result.ctime = child.lastMetadataChangeTime();
//TODO Move ceilDivision to general utils which can be used by cryfs as well
result->st_blocks = blobstore::onblocks::utils::ceilDivision(result->st_size, static_cast<off_t>(512));
result->st_blksize = _fsBlobStore->virtualBlocksizeBytes();
result.blocks = blobstore::onblocks::utils::ceilDivision(size, static_cast<uint64_t>(512));
return result;
}
void DirBlob::updateAccessTimestampForChild(const BlockId &blockId, TimestampUpdateBehavior timestampUpdateBehavior) {

View File

@ -5,6 +5,7 @@
#include <blockstore/utils/BlockId.h>
#include <cpp-utils/macros.h>
#include <fspp/fs_interface/Dir.h>
#include <fspp/fs_interface/Node.h>
#include "FsBlob.h"
#include "utils/DirEntryList.h"
#include <mutex>
@ -56,9 +57,9 @@ namespace cryfs {
void flush();
void statChild(const blockstore::BlockId &blockId, struct ::stat *result) const;
fspp::Node::stat_info statChild(const blockstore::BlockId &blockId) const;
void statChildWithSizeAlreadySet(const blockstore::BlockId &blockId, struct ::stat *result) const;
fspp::Node::stat_info statChildWithKnownSize(const blockstore::BlockId &blockId, uint64_t size) const;
void updateAccessTimestampForChild(const blockstore::BlockId &blockId, TimestampUpdateBehavior timestampUpdateBehavior);

View File

@ -5,6 +5,7 @@
#include "FsBlobRef.h"
#include "../cachingfsblobstore/DirBlobRef.h"
#include "../fsblobstore/utils/TimestampUpdateBehavior.h"
#include <fspp/fs_interface/Node.h>
namespace cryfs {
namespace parallelaccessfsblobstore {
@ -49,12 +50,12 @@ public:
return _base->RenameChild(blockId, newName, onOverwritten);
}
void statChild(const blockstore::BlockId &blockId, struct ::stat *result) const {
return _base->statChild(blockId, result);
fspp::Node::stat_info statChild(const blockstore::BlockId &blockId) const {
return _base->statChild(blockId);
}
void statChildWithSizeAlreadySet(const blockstore::BlockId &blockId, struct ::stat *result) const {
return _base->statChildWithSizeAlreadySet(blockId, result);
fspp::Node::stat_info statChildWithKnownSize(const blockstore::BlockId &blockId, uint64_t size) const {
return _base->statChildWithKnownSize(blockId, size);
}
void updateAccessTimestampForChild(const blockstore::BlockId &blockId, fsblobstore::TimestampUpdateBehavior timestampUpdateBehavior) {

View File

@ -4,15 +4,25 @@
#include <boost/filesystem.hpp>
#include <sys/stat.h>
namespace fspp {
class Node {
public:
virtual ~Node() {}
virtual void stat(struct ::stat *result) const = 0;
struct stat_info final {
uint32_t nlink;
uint32_t mode;
uint32_t uid;
uint32_t gid;
uint64_t size;
uint64_t blocks;
struct timespec atime;
struct timespec mtime;
struct timespec ctime;
};
virtual stat_info stat() const = 0;
virtual void chmod(mode_t mode) = 0;
virtual void chown(uid_t uid, gid_t gid) = 0;
virtual void access(int mask) const = 0;

View File

@ -3,7 +3,7 @@
#define MESSMER_FSPP_FSINTERFACE_OPENFILE_H_
#include <boost/filesystem.hpp>
#include <sys/stat.h>
#include "Node.h"
namespace fspp {
class Device;
@ -12,7 +12,9 @@ class OpenFile {
public:
virtual ~OpenFile() {}
virtual void stat(struct ::stat *result) const = 0;
using stat_info = typename Node::stat_info;
virtual stat_info stat() const = 0;
virtual void truncate(off_t size) const = 0;
virtual size_t read(void *buf, size_t count, off_t offset) const = 0;
virtual void write(const void *buf, size_t count, off_t offset) = 0;

View File

@ -16,7 +16,7 @@ public:
}
void Test_Load_While_Not_Loaded() {
struct stat oldStat{};
fspp::Node::stat_info oldStat{};
{
auto node = this->CreateNode("/mynode");
oldStat = this->stat(*node);
@ -28,10 +28,10 @@ public:
auto node = this->device->Load("/mynode");
//Test that timestamps didn't change
struct stat newStat = this->stat(*node.value());
EXPECT_EQ(oldStat.st_atim, newStat.st_atim);
EXPECT_EQ(oldStat.st_mtim, newStat.st_mtim);
EXPECT_EQ(oldStat.st_ctim, newStat.st_ctim);
fspp::Node::stat_info newStat = this->stat(*node.value());
EXPECT_EQ(oldStat.atime, newStat.atime);
EXPECT_EQ(oldStat.mtime, newStat.mtime);
EXPECT_EQ(oldStat.ctime, newStat.ctime);
}
};

View File

@ -58,22 +58,22 @@ public:
void Test_Chown_Uid(fspp::File *file, fspp::Node *node) {
node->chown(100, 200);
this->IN_STAT(file, node, [] (struct stat st){
EXPECT_EQ(100u, st.st_uid);
this->IN_STAT(file, node, [] (const fspp::Node::stat_info& st){
EXPECT_EQ(100u, st.uid);
});
}
void Test_Chown_Gid(fspp::File *file, fspp::Node *node) {
node->chown(100, 200);
this->IN_STAT(file, node, [] (struct stat st){
EXPECT_EQ(200u, st.st_gid);
this->IN_STAT(file, node, [] (const fspp::Node::stat_info& st){
EXPECT_EQ(200u, st.gid);
});
}
void Test_Chmod(fspp::File *file, fspp::Node *node) {
node->chmod(S_IFREG | S_IRUSR | S_IWOTH);
this->IN_STAT(file, node, [] (struct stat st){
EXPECT_EQ(static_cast<mode_t>(S_IFREG | S_IRUSR | S_IWOTH), st.st_mode);
this->IN_STAT(file, node, [] (const fspp::Node::stat_info& st){
EXPECT_EQ(static_cast<mode_t>(S_IFREG | S_IRUSR | S_IWOTH), st.mode);
});
}
@ -81,7 +81,7 @@ public:
struct timespec ATIME{}; ATIME.tv_sec = 1458086400; ATIME.tv_nsec = 34525;
struct timespec MTIME{}; MTIME.tv_sec = 1458086300; MTIME.tv_nsec = 48293;
node->utimens(ATIME, MTIME);
this->IN_STAT(file, node, [this, ATIME, MTIME] (struct stat st) {
this->IN_STAT(file, node, [this, ATIME, MTIME] (const fspp::Node::stat_info& st) {
this->EXPECT_ATIME_EQ(ATIME, st);
this->EXPECT_MTIME_EQ(MTIME, st);
});

View File

@ -11,8 +11,8 @@ public:
void Test_Nlink() {
this->CreateNode("/mynode");
auto node = this->Load("/mynode");
this->IN_STAT(node.get(), [] (struct stat st) {
EXPECT_EQ(1u, st.st_nlink);
this->IN_STAT(node.get(), [] (const fspp::Node::stat_info& st) {
EXPECT_EQ(1u, st.nlink);
});
}
};
@ -32,8 +32,8 @@ TYPED_TEST_P(FsppNodeTest_Stat_FileOnly, CreatedFileIsEmpty) {
TYPED_TEST_P(FsppNodeTest_Stat_FileOnly, FileIsFile) {
this->CreateFile("/myfile");
auto node = this->Load("/myfile");
this->IN_STAT(node.get(), [] (struct stat st) {
EXPECT_TRUE(S_ISREG(st.st_mode));
this->IN_STAT(node.get(), [] (const fspp::Node::stat_info& st) {
EXPECT_TRUE(S_ISREG(st.mode));
});
}
@ -46,8 +46,8 @@ TYPED_TEST_CASE_P(FsppNodeTest_Stat_DirOnly);
TYPED_TEST_P(FsppNodeTest_Stat_DirOnly, DirIsDir) {
this->CreateDir("/mydir");
auto node = this->Load("/mydir");
this->IN_STAT(node.get(), [] (struct stat st) {
EXPECT_TRUE(S_ISDIR(st.st_mode));
this->IN_STAT(node.get(), [] (const fspp::Node::stat_info& st) {
EXPECT_TRUE(S_ISDIR(st.mode));
});
}
@ -60,8 +60,8 @@ TYPED_TEST_CASE_P(FsppNodeTest_Stat_SymlinkOnly);
TYPED_TEST_P(FsppNodeTest_Stat_SymlinkOnly, SymlinkIsSymlink) {
this->CreateSymlink("/mysymlink");
auto node = this->Load("/mysymlink");
this->IN_STAT(node.get(), [] (struct stat st) {
EXPECT_TRUE(S_ISLNK(st.st_mode));
this->IN_STAT(node.get(), [] (const fspp::Node::stat_info& st) {
EXPECT_TRUE(S_ISLNK(st.mode));
});
}

View File

@ -26,8 +26,7 @@ public:
void Test_Stat() {
auto node = this->CreateNode("/mynode");
auto operation = [&node] () {
struct stat st{};
node->stat(&st);
node->stat();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
this->ExpectDoesntUpdateAnyTimestamps
@ -36,7 +35,7 @@ public:
void Test_Chmod() {
auto node = this->CreateNode("/mynode");
mode_t mode = this->stat(*node).st_mode;
mode_t mode = this->stat(*node).mode;
auto operation = [&node, mode] () {
node->chmod(mode);
};
@ -49,8 +48,8 @@ public:
void Test_Chown() {
auto node = this->CreateNode("/mynode");
uid_t uid = this->stat(*node).st_uid;
gid_t gid = this->stat(*node).st_gid;
uid_t uid = this->stat(*node).uid;
gid_t gid = this->stat(*node).gid;
auto operation = [&node, uid, gid] () {
node->chown(uid, gid);
};
@ -347,8 +346,8 @@ public:
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
this->ExpectUpdatesMetadataTimestamp
});
EXPECT_EQ(atime, this->stat(*node).st_atim);
EXPECT_EQ(mtime, this->stat(*node).st_mtim);
EXPECT_EQ(atime, this->stat(*node).atime);
EXPECT_EQ(mtime, this->stat(*node).mtime);
}
};

View File

@ -7,15 +7,14 @@
template<class ConcreteFileSystemTestFixture>
class FsppOpenFileTest: public FileSystemTest<ConcreteFileSystemTestFixture> {
public:
void IN_STAT(fspp::OpenFile *openFile, std::function<void (struct stat)> callback) {
struct stat st{};
openFile->stat(&st);
void IN_STAT(fspp::OpenFile *openFile, std::function<void (const fspp::OpenFile::stat_info&)> callback) {
auto st = openFile->stat();
callback(st);
}
void EXPECT_SIZE(uint64_t expectedSize, fspp::OpenFile *openFile) {
IN_STAT(openFile, [expectedSize] (struct stat st) {
EXPECT_EQ(expectedSize, static_cast<uint64_t>(st.st_size));
IN_STAT(openFile, [expectedSize] (const fspp::OpenFile::stat_info& st) {
EXPECT_EQ(expectedSize, static_cast<uint64_t>(st.size));
});
EXPECT_NUMBYTES_READABLE(expectedSize, openFile);
@ -41,8 +40,8 @@ TYPED_TEST_P(FsppOpenFileTest, CreatedFileIsEmpty) {
TYPED_TEST_P(FsppOpenFileTest, FileIsFile) {
auto file = this->CreateFile("/myfile");
auto openFile = this->LoadFile("/myfile")->open(O_RDONLY);
this->IN_STAT(openFile.get(), [] (struct stat st) {
EXPECT_TRUE(S_ISREG(st.st_mode));
this->IN_STAT(openFile.get(), [] (const fspp::OpenFile::stat_info& st) {
EXPECT_TRUE(S_ISREG(st.mode));
});
}

View File

@ -14,8 +14,8 @@ public:
auto file = this->CreateFile(path);
file->truncate(size);
auto openFile = file->open(O_RDWR);
assert(this->stat(*openFile).st_size == size);
assert(this->stat(*this->Load(path)).st_size == size);
assert(this->stat(*openFile).size == size);
assert(this->stat(*this->Load(path)).size == size);
return openFile;
}
};
@ -24,8 +24,7 @@ TYPED_TEST_CASE_P(FsppOpenFileTest_Timestamps);
TYPED_TEST_P(FsppOpenFileTest_Timestamps, stat) {
auto openFile = this->CreateAndOpenFile("/mynode");
auto operation = [&openFile] () {
struct ::stat st{};
openFile->stat(&st);
openFile->stat();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*openFile, operation, {this->ExpectDoesntUpdateAnyTimestamps});
}

View File

@ -90,12 +90,11 @@ public:
void setModificationTimestampLaterThanAccessTimestamp(const boost::filesystem::path& path) {
auto node = device->Load(path).value();
struct stat st{};
node->stat(&st);
st.st_mtim.tv_nsec = st.st_mtim.tv_nsec + 1;
auto st = node->stat();
st.mtime.tv_nsec = st.mtime.tv_nsec + 1;
node->utimens(
st.st_atim,
st.st_mtim
st.atime,
st.mtime
);
}
};

View File

@ -28,17 +28,16 @@ public:
std::unique_ptr<fspp::Node> file_nested_node;
//TODO IN_STAT still needed after moving it to FsppNodeTest?
void IN_STAT(fspp::File *file, fspp::Node *node, std::function<void (struct stat)> callback) {
struct stat st1{}, st2{};
node->stat(&st1);
void IN_STAT(fspp::File *file, fspp::Node *node, std::function<void (const fspp::Node::stat_info&)> callback) {
auto st1 = node->stat();
callback(st1);
file->open(O_RDONLY)->stat(&st2);
auto st2 = file->open(O_RDONLY)->stat();
callback(st2);
}
void EXPECT_SIZE(uint64_t expectedSize, fspp::File *file, fspp::Node *node) {
IN_STAT(file, node, [expectedSize] (struct stat st) {
EXPECT_EQ(expectedSize, static_cast<uint64_t>(st.st_size));
IN_STAT(file, node, [expectedSize] (const fspp::Node::stat_info& st) {
EXPECT_EQ(expectedSize, static_cast<uint64_t>(st.size));
});
EXPECT_NUMBYTES_READABLE(expectedSize, file);
@ -53,14 +52,14 @@ public:
EXPECT_EQ(expectedSize, static_cast<uint64_t>(readBytes));
}
void EXPECT_ATIME_EQ(struct timespec expected, struct stat st) {
EXPECT_EQ(expected.tv_sec, st.st_atim.tv_sec);
EXPECT_EQ(expected.tv_nsec, st.st_atim.tv_nsec);
void EXPECT_ATIME_EQ(struct timespec expected, const fspp::Node::stat_info& st) {
EXPECT_EQ(expected.tv_sec, st.atime.tv_sec);
EXPECT_EQ(expected.tv_nsec, st.atime.tv_nsec);
}
void EXPECT_MTIME_EQ(struct timespec expected, struct stat st) {
EXPECT_EQ(expected.tv_sec, st.st_mtim.tv_sec);
EXPECT_EQ(expected.tv_nsec, st.st_mtim.tv_nsec);
void EXPECT_MTIME_EQ(struct timespec expected, const fspp::Node::stat_info& st) {
EXPECT_EQ(expected.tv_sec, st.mtime.tv_sec);
EXPECT_EQ(expected.tv_nsec, st.mtime.tv_nsec);
}
};

View File

@ -9,15 +9,14 @@
class FsppNodeTestHelper {
public:
void IN_STAT(fspp::Node *file, std::function<void (struct stat)> callback) {
struct stat st{};
file->stat(&st);
void IN_STAT(fspp::Node *file, std::function<void (const fspp::Node::stat_info& stat)> callback) {
auto st = file->stat();
callback(st);
}
void EXPECT_SIZE(uint64_t expectedSize, fspp::Node *node) {
IN_STAT(node, [expectedSize] (struct stat st) {
EXPECT_EQ(expectedSize, static_cast<uint64_t>(st.st_size));
IN_STAT(node, [expectedSize] (const fspp::Node::stat_info& st) {
EXPECT_EQ(expectedSize, static_cast<uint64_t>(st.size));
});
}
};

View File

@ -10,7 +10,7 @@
template<class ConcreteFileSystemTestFixture>
class TimestampTestUtils : public virtual FileSystemTest<ConcreteFileSystemTestFixture> {
public:
using TimestampUpdateBehavior = std::function<void (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation)>;
using TimestampUpdateBehavior = std::function<void (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation)>;
static TimestampUpdateBehavior ExpectUpdatesAccessTimestamp;
static TimestampUpdateBehavior ExpectDoesntUpdateAccessTimestamp;
@ -20,13 +20,13 @@ public:
static TimestampUpdateBehavior ExpectDoesntUpdateMetadataTimestamp;
static TimestampUpdateBehavior ExpectDoesntUpdateAnyTimestamps;
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(std::function<struct stat()> statOld, std::function<struct stat()> statNew, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
struct stat oldStat = statOld();
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(std::function<fspp::Node::stat_info()> statOld, std::function<fspp::Node::stat_info()> statNew, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
auto oldStat = statOld();
ensureNodeTimestampsAreOld(oldStat);
timespec timeBeforeOperation = cpputils::time::now();
operation();
timespec timeAfterOperation = cpputils::time::now();
struct stat newStat = statNew();
auto newStat = statNew();
for (auto behaviorCheck : behaviorChecks) {
behaviorCheck(oldStat, newStat, timeBeforeOperation, timeAfterOperation);
}
@ -55,30 +55,26 @@ public:
}
void EXPECT_ACCESS_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
EXPECT_LE(lowerBound, stat(node).st_atim);
EXPECT_GE(upperBound, stat(node).st_atim);
EXPECT_LE(lowerBound, stat(node).atime);
EXPECT_GE(upperBound, stat(node).atime);
}
void EXPECT_MODIFICATION_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
EXPECT_LE(lowerBound, stat(node).st_mtim);
EXPECT_GE(upperBound, stat(node).st_mtim);
EXPECT_LE(lowerBound, stat(node).mtime);
EXPECT_GE(upperBound, stat(node).mtime);
}
void EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const fspp::Node &node) {
EXPECT_LE(lowerBound, stat(node).st_ctim);
EXPECT_GE(upperBound, stat(node).st_ctim);
EXPECT_LE(lowerBound, stat(node).ctime);
EXPECT_GE(upperBound, stat(node).ctime);
}
static struct stat stat(const fspp::Node &node) {
struct stat st{};
node.stat(&st);
return st;
static fspp::Node::stat_info stat(const fspp::Node &node) {
return node.stat();
}
static struct stat stat(const fspp::OpenFile &openFile) {
struct stat st{};
openFile.stat(&st);
return st;
static fspp::Node::stat_info stat(const fspp::OpenFile &openFile) {
return openFile.stat();
}
timespec xSecondsAgo(int sec) {
@ -87,11 +83,11 @@ public:
return result;
}
void ensureNodeTimestampsAreOld(const struct stat &nodeStat) {
void ensureNodeTimestampsAreOld(const fspp::Node::stat_info &nodeStat) {
waitUntilClockProgresses();
EXPECT_LT(nodeStat.st_atim, cpputils::time::now());
EXPECT_LT(nodeStat.st_mtim, cpputils::time::now());
EXPECT_LT(nodeStat.st_ctim, cpputils::time::now());
EXPECT_LT(nodeStat.atime, cpputils::time::now());
EXPECT_LT(nodeStat.mtime, cpputils::time::now());
EXPECT_LT(nodeStat.ctime, cpputils::time::now());
}
private:
@ -106,57 +102,57 @@ private:
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesAccessTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(statBeforeOperation);
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_atim);
EXPECT_GE(timeAfterOperation, statAfterOperation.st_atim);
EXPECT_LE(timeBeforeOperation, statAfterOperation.atime);
EXPECT_GE(timeAfterOperation, statAfterOperation.atime);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAccessTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_EQ(statBeforeOperation.st_atim, statAfterOperation.st_atim);
EXPECT_EQ(statBeforeOperation.atime, statAfterOperation.atime);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesModificationTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(statBeforeOperation);
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_mtim);
EXPECT_GE(timeAfterOperation, statAfterOperation.st_mtim);
EXPECT_LE(timeBeforeOperation, statAfterOperation.mtime);
EXPECT_GE(timeAfterOperation, statAfterOperation.mtime);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateModificationTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_EQ(statBeforeOperation.st_mtim, statAfterOperation.st_mtim);
EXPECT_EQ(statBeforeOperation.mtime, statAfterOperation.mtime);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesMetadataTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(statBeforeOperation);
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_ctim);
EXPECT_GE(timeAfterOperation, statAfterOperation.st_ctim);
EXPECT_LE(timeBeforeOperation, statAfterOperation.ctime);
EXPECT_GE(timeAfterOperation, statAfterOperation.ctime);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateMetadataTimestamp =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
UNUSED(timeBeforeOperation);
UNUSED(timeAfterOperation);
EXPECT_EQ(statBeforeOperation.st_ctim, statAfterOperation.st_ctim);
EXPECT_EQ(statBeforeOperation.ctime, statAfterOperation.ctime);
};
template<class ConcreteFileSystemTestFixture>
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAnyTimestamps =
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
[] (const fspp::Node::stat_info& statBeforeOperation, const fspp::Node::stat_info& statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
ExpectDoesntUpdateAccessTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
ExpectDoesntUpdateModificationTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
ExpectDoesntUpdateMetadataTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);

View File

@ -137,19 +137,35 @@ void FilesystemImpl::closeFile(int descriptor) {
_open_files.close(descriptor);
}
namespace {
void convert_stat_info(const fspp::Node::stat_info& input, struct ::stat *output) {
output->st_nlink = input.nlink;
output->st_mode = input.mode;
output->st_uid = input.uid;
output->st_gid = input.gid;
output->st_size = input.size;
output->st_blocks = input.blocks;
output->st_atim = input.atime;
output->st_mtim = input.mtime;
output->st_ctim = input.ctime;
}
}
void FilesystemImpl::lstat(const bf::path &path, struct ::stat *stbuf) {
PROFILE(_lstatNanosec);
auto node = _device->Load(path);
if(node == none) {
throw fuse::FuseErrnoException(ENOENT);
} else {
(*node)->stat(stbuf);
auto stat_info = (*node)->stat();
convert_stat_info(stat_info, stbuf);
}
}
void FilesystemImpl::fstat(int descriptor, struct ::stat *stbuf) {
PROFILE(_fstatNanosec);
_open_files.get(descriptor)->stat(stbuf);
auto stat_info = _open_files.get(descriptor)->stat();
convert_stat_info(stat_info, stbuf);
}
void FilesystemImpl::chmod(const boost::filesystem::path &path, mode_t mode) {

View File

@ -17,7 +17,7 @@ public:
~MockOpenFile() {destructed = true;}
MOCK_CONST_METHOD1(stat, void(struct ::stat*));
MOCK_CONST_METHOD0(stat, OpenFile::stat_info());
MOCK_CONST_METHOD1(truncate, void(off_t));
MOCK_CONST_METHOD3(read, size_t(void*, size_t, off_t));
MOCK_METHOD3(write, void(const void*, size_t, off_t));