Directory timestamps are updated correctly. Also added test cases for this.

This commit is contained in:
Sebastian Messmer 2016-06-08 12:21:57 -07:00
parent 5a5037c992
commit 5aff394a16
14 changed files with 396 additions and 54 deletions

View File

@ -67,15 +67,20 @@ Key CryDevice::CreateRootBlobAndReturnKey() {
}
optional<unique_ref<fspp::Node>> CryDevice::Load(const bf::path &path) {
// TODO Split into smaller functions
ASSERT(path.is_absolute(), "Non absolute path given");
callFsActionCallbacks();
if (path.parent_path().empty()) {
//We are asked to load the base directory '/'.
return optional<unique_ref<fspp::Node>>(make_unique_ref<CryDir>(this, none, _rootKey));
return optional<unique_ref<fspp::Node>>(make_unique_ref<CryDir>(this, none, none, _rootKey));
}
auto parent = LoadDirBlob(path.parent_path());
auto parentWithGrandparent = LoadDirBlobWithParent(path.parent_path());
auto parent = std::move(parentWithGrandparent.blob);
auto grandparent = std::move(parentWithGrandparent.parent);
auto optEntry = parent->GetChild(path.filename().native());
if (optEntry == boost::none) {
return boost::none;
@ -84,33 +89,39 @@ optional<unique_ref<fspp::Node>> CryDevice::Load(const bf::path &path) {
switch(entry.type()) {
case fspp::Dir::EntryType::DIR:
return optional<unique_ref<fspp::Node>>(make_unique_ref<CryDir>(this, std::move(parent), entry.key()));
return optional<unique_ref<fspp::Node>>(make_unique_ref<CryDir>(this, std::move(parent), std::move(grandparent), entry.key()));
case fspp::Dir::EntryType::FILE:
return optional<unique_ref<fspp::Node>>(make_unique_ref<CryFile>(this, std::move(parent), entry.key()));
return optional<unique_ref<fspp::Node>>(make_unique_ref<CryFile>(this, std::move(parent), std::move(grandparent), entry.key()));
case fspp::Dir::EntryType::SYMLINK:
return optional<unique_ref<fspp::Node>>(make_unique_ref<CrySymlink>(this, std::move(parent), entry.key()));
return optional<unique_ref<fspp::Node>>(make_unique_ref<CrySymlink>(this, std::move(parent), std::move(grandparent), entry.key()));
}
ASSERT(false, "Switch/case not exhaustive");
}
unique_ref<DirBlobRef> CryDevice::LoadDirBlob(const bf::path &path) {
auto blob = LoadBlob(path);
auto dir = dynamic_pointer_move<DirBlobRef>(blob);
CryDevice::DirBlobWithParent CryDevice::LoadDirBlobWithParent(const bf::path &path) {
auto blob = LoadBlobWithParent(path);
auto dir = dynamic_pointer_move<DirBlobRef>(blob.blob);
if (dir == none) {
throw FuseErrnoException(ENOTDIR); // Loaded blob is not a directory
}
return std::move(*dir);
return DirBlobWithParent{std::move(*dir), std::move(blob.parent)};
}
unique_ref<FsBlobRef> CryDevice::LoadBlob(const bf::path &path) {
auto currentBlob = _fsBlobStore->load(_rootKey);
if (currentBlob == none) {
return LoadBlobWithParent(path).blob;
}
CryDevice::BlobWithParent CryDevice::LoadBlobWithParent(const bf::path &path) {
optional<unique_ref<DirBlobRef>> parentBlob = none;
optional<unique_ref<FsBlobRef>> currentBlobOpt = _fsBlobStore->load(_rootKey);
if (currentBlobOpt == none) {
LOG(ERROR) << "Could not load root blob. Is the base directory accessible?";
throw FuseErrnoException(EIO);
}
unique_ref<FsBlobRef> currentBlob = std::move(*currentBlobOpt);
for (const bf::path &component : path.relative_path()) {
auto currentDir = dynamic_pointer_move<DirBlobRef>(*currentBlob);
auto currentDir = dynamic_pointer_move<DirBlobRef>(currentBlob);
if (currentDir == none) {
throw FuseErrnoException(ENOTDIR); // Path component is not a dir
}
@ -120,13 +131,15 @@ unique_ref<FsBlobRef> CryDevice::LoadBlob(const bf::path &path) {
throw FuseErrnoException(ENOENT); // Child entry in directory not found
}
Key childKey = childOpt->key();
currentBlob = _fsBlobStore->load(childKey);
if (currentBlob == none) {
auto nextBlob = _fsBlobStore->load(childKey);
if (nextBlob == none) {
throw FuseErrnoException(ENOENT); // Blob for directory entry not found
}
parentBlob = std::move(*currentDir);
currentBlob = std::move(*nextBlob);
}
return std::move(*currentBlob);
return BlobWithParent{std::move(currentBlob), std::move(parentBlob)};
//TODO (I think this is resolved, but I should test it)
// Running the python script, waiting for "Create files in sequential order...", then going into dir ~/tmp/cryfs-mount-.../Bonnie.../ and calling "ls"

View File

@ -26,7 +26,11 @@ public:
cpputils::unique_ref<parallelaccessfsblobstore::SymlinkBlobRef> CreateSymlinkBlob(const boost::filesystem::path &target);
cpputils::unique_ref<parallelaccessfsblobstore::FsBlobRef> LoadBlob(const blockstore::Key &key); //TODO Do I still need this function?
cpputils::unique_ref<parallelaccessfsblobstore::FsBlobRef> LoadBlob(const boost::filesystem::path &path);
cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> LoadDirBlob(const boost::filesystem::path &path);
struct DirBlobWithParent {
cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> blob;
boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> parent;
};
DirBlobWithParent LoadDirBlobWithParent(const boost::filesystem::path &path);
void RemoveBlob(const blockstore::Key &key);
void onFsAction(std::function<void()> callback);
@ -48,6 +52,12 @@ private:
blockstore::Key CreateRootBlobAndReturnKey();
static cpputils::unique_ref<blockstore::BlockStore> CreateEncryptedBlockStore(const CryConfig &config, cpputils::unique_ref<blockstore::BlockStore> baseBlockStore);
struct BlobWithParent {
cpputils::unique_ref<parallelaccessfsblobstore::FsBlobRef> blob;
boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> parent;
};
BlobWithParent LoadBlobWithParent(const boost::filesystem::path &path);
DISALLOW_COPY_AND_ASSIGN(CryDevice);
};

View File

@ -30,8 +30,8 @@ using cryfs::parallelaccessfsblobstore::DirBlobRef;
namespace cryfs {
CryDir::CryDir(CryDevice *device, boost::optional<unique_ref<DirBlobRef>> parent, const Key &key)
: CryNode(device, std::move(parent), key) {
CryDir::CryDir(CryDevice *device, optional<unique_ref<DirBlobRef>> parent, optional<unique_ref<DirBlobRef>> grandparent, const Key &key)
: CryNode(device, std::move(parent), std::move(grandparent), key) {
}
CryDir::~CryDir() {
@ -39,6 +39,10 @@ CryDir::~CryDir() {
unique_ref<fspp::OpenFile> CryDir::createAndOpenFile(const string &name, mode_t mode, uid_t uid, gid_t gid) {
device()->callFsActionCallbacks();
if (!isRootDir()) {
//TODO Instead of doing nothing when we're the root directory, handle timestamps in the root dir correctly (and delete isRootDir() function)
parent()->updateModificationTimestampForChild(key());
}
auto child = device()->CreateFileBlob();
auto now = cpputils::time::now();
auto dirBlob = LoadBlob();
@ -48,6 +52,10 @@ unique_ref<fspp::OpenFile> CryDir::createAndOpenFile(const string &name, mode_t
void CryDir::createDir(const string &name, mode_t mode, uid_t uid, gid_t gid) {
device()->callFsActionCallbacks();
if (!isRootDir()) {
//TODO Instead of doing nothing when we're the root directory, handle timestamps in the root dir correctly (and delete isRootDir() function)
parent()->updateModificationTimestampForChild(key());
}
auto blob = LoadBlob();
auto child = device()->CreateDirBlob();
auto now = cpputils::time::now();
@ -61,8 +69,12 @@ unique_ref<DirBlobRef> CryDir::LoadBlob() const {
return std::move(*dir_blob);
}
unique_ref<vector<fspp::Dir::Entry>> CryDir::children() const {
unique_ref<vector<fspp::Dir::Entry>> CryDir::children() {
device()->callFsActionCallbacks();
if (!isRootDir()) {
//TODO Instead of doing nothing when we're the root directory, handle timestamps in the root dir correctly (and delete isRootDir() function)
parent()->updateAccessTimestampForChild(key());
}
auto children = make_unique_ref<vector<fspp::Dir::Entry>>();
children->push_back(fspp::Dir::Entry(fspp::Dir::EntryType::DIR, "."));
children->push_back(fspp::Dir::Entry(fspp::Dir::EntryType::DIR, ".."));
@ -78,6 +90,10 @@ fspp::Dir::EntryType CryDir::getType() const {
void CryDir::createSymlink(const string &name, const bf::path &target, uid_t uid, gid_t gid) {
device()->callFsActionCallbacks();
if (!isRootDir()) {
//TODO Instead of doing nothing when we're the root directory, handle timestamps in the root dir correctly (and delete isRootDir() function)
parent()->updateModificationTimestampForChild(key());
}
auto blob = LoadBlob();
auto child = device()->CreateSymlinkBlob(target);
auto now = cpputils::time::now();
@ -86,6 +102,10 @@ void CryDir::createSymlink(const string &name, const bf::path &target, uid_t uid
void CryDir::remove() {
device()->callFsActionCallbacks();
if (grandparent() != none) {
//TODO Instead of doing nothing when we're in the root directory, handle timestamps in the root dir correctly
(*grandparent())->updateModificationTimestampForChild(parent()->key());
}
{
auto blob = LoadBlob();
if (0 != blob->NumChildren()) {

View File

@ -10,7 +10,7 @@ namespace cryfs {
class CryDir final: public fspp::Dir, CryNode {
public:
CryDir(CryDevice *device, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> parent, const blockstore::Key &key);
CryDir(CryDevice *device, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::Key &key);
~CryDir();
//TODO return type variance to CryFile/CryDir?
@ -19,7 +19,7 @@ public:
void createSymlink(const std::string &name, const boost::filesystem::path &target, uid_t uid, gid_t gid) override;
//TODO Make Entry a public class instead of hidden in DirBlob (which is not publicly visible)
cpputils::unique_ref<std::vector<fspp::Dir::Entry>> children() const override;
cpputils::unique_ref<std::vector<fspp::Dir::Entry>> children() override;
fspp::Dir::EntryType getType() const override;

View File

@ -12,6 +12,7 @@ using fspp::fuse::FuseErrnoException;
using blockstore::Key;
using boost::none;
using boost::optional;
using cpputils::unique_ref;
using cpputils::make_unique_ref;
using cpputils::dynamic_pointer_move;
@ -20,8 +21,8 @@ using cryfs::parallelaccessfsblobstore::FileBlobRef;
namespace cryfs {
CryFile::CryFile(CryDevice *device, unique_ref<DirBlobRef> parent, const Key &key)
: CryNode(device, std::move(parent), key) {
CryFile::CryFile(CryDevice *device, unique_ref<DirBlobRef> parent, optional<unique_ref<DirBlobRef>> grandparent, const Key &key)
: CryNode(device, std::move(parent), std::move(grandparent), key) {
}
CryFile::~CryFile() {
@ -56,6 +57,10 @@ fspp::Dir::EntryType CryFile::getType() const {
void CryFile::remove() {
device()->callFsActionCallbacks();
if (grandparent() != none) {
//TODO Instead of doing nothing when we're in the root directory, handle timestamps in the root dir correctly
(*grandparent())->updateModificationTimestampForChild(parent()->key());
}
removeNode();
}

View File

@ -11,7 +11,7 @@ namespace cryfs {
class CryFile final: public fspp::File, CryNode {
public:
CryFile(CryDevice *device, cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> parent, const blockstore::Key &key);
CryFile(CryDevice *device, cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::Key &key);
~CryFile();
cpputils::unique_ref<fspp::OpenFile> open(int flags) override;

View File

@ -28,13 +28,18 @@ using fspp::fuse::FuseErrnoException;
namespace cryfs {
CryNode::CryNode(CryDevice *device, optional<unique_ref<DirBlobRef>> parent, const Key &key)
CryNode::CryNode(CryDevice *device, optional<unique_ref<DirBlobRef>> parent, optional<unique_ref<DirBlobRef>> grandparent, const Key &key)
: _device(device),
_parent(none),
_grandparent(none),
_key(key) {
ASSERT(parent != none || grandparent == none, "Grandparent can only be set when parent is not none");
if (parent != none) {
_parent = cpputils::to_unique_ptr(std::move(*parent));
}
_grandparent = std::move(grandparent);
}
CryNode::~CryNode() {
@ -47,6 +52,10 @@ void CryNode::access(int mask) const {
return;
}
bool CryNode::isRootDir() const {
return _parent == none;
}
shared_ptr<const DirBlobRef> CryNode::parent() const {
ASSERT(_parent != none, "We are the root directory and can't get the parent of the root directory");
return *_parent;
@ -57,24 +66,36 @@ shared_ptr<DirBlobRef> CryNode::parent() {
return *_parent;
}
optional<DirBlobRef*> CryNode::grandparent() {
if (_grandparent == none) {
return none;
}
return _grandparent->get();
}
void CryNode::rename(const bf::path &to) {
device()->callFsActionCallbacks();
if (_parent == none) {
//We are the root direcory.
throw FuseErrnoException(EBUSY);
}
auto targetDir = _device->LoadDirBlob(to.parent_path());
auto targetDirWithParent = _device->LoadDirBlobWithParent(to.parent_path());
auto targetDir = std::move(targetDirWithParent.blob);
auto targetDirParent = std::move(targetDirWithParent.parent);
auto old = (*_parent)->GetChild(_key);
if (old == boost::none) {
throw FuseErrnoException(EIO);
}
fsblobstore::DirEntry oldEntry = *old; // Copying this and not only keeping the reference is necessary, because the operations below (i.e. RenameChild()) might make a reference invalid.
fsblobstore::DirEntry oldEntry = *old; // Copying this (instead of only keeping the reference) is necessary, because the operations below (i.e. RenameChild()) might make a reference invalid.
auto onOverwritten = [this] (const blockstore::Key &key) {
device()->RemoveBlob(key);
};
_updateParentModificationTimestamp();
if (targetDir->key() == (*_parent)->key()) {
targetDir->RenameChild(oldEntry.key(), to.filename().native(), onOverwritten);
} else {
_updateTargetDirModificationTimestamp(*targetDir, std::move(targetDirParent));
targetDir->AddOrOverwriteChild(to.filename().native(), oldEntry.key(), oldEntry.type(), oldEntry.mode(), oldEntry.uid(), oldEntry.gid(),
oldEntry.lastAccessTime(), oldEntry.lastModificationTime(), onOverwritten);
(*_parent)->RemoveChild(oldEntry.name());
@ -83,6 +104,21 @@ void CryNode::rename(const bf::path &to) {
}
}
void CryNode::_updateParentModificationTimestamp() {
if (_grandparent != none) {
// TODO Handle timestamps of the root directory (_grandparent == none) correctly.
ASSERT(_parent != none, "Grandparent is set, so also parent has to be set");
(*_grandparent)->updateModificationTimestampForChild((*_parent)->key());
}
}
void CryNode::_updateTargetDirModificationTimestamp(const DirBlobRef &targetDir, optional<unique_ref<DirBlobRef>> targetDirParent) {
if (targetDirParent != none) {
// TODO Handle timestamps of the root directory (targetDirParent == none) correctly.
(*targetDirParent)->updateModificationTimestampForChild(targetDir.key());
}
}
void CryNode::utimens(timespec lastAccessTime, timespec lastModificationTime) {
device()->callFsActionCallbacks();
if (_parent == none) {

View File

@ -14,7 +14,8 @@ class CryNode: public virtual fspp::Node {
public:
virtual ~CryNode();
CryNode(CryDevice *device, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> parent, const blockstore::Key &key);
// 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::Key &key);
void access(int mask) const override;
void stat(struct ::stat *result) const override;
void chmod(mode_t mode) override;
@ -29,16 +30,22 @@ protected:
const CryDevice *device() const;
const blockstore::Key &key() const;
cpputils::unique_ref<parallelaccessfsblobstore::FsBlobRef> LoadBlob() const;
bool isRootDir() const;
std::shared_ptr<const parallelaccessfsblobstore::DirBlobRef> parent() const;
std::shared_ptr<parallelaccessfsblobstore::DirBlobRef> parent();
boost::optional<parallelaccessfsblobstore::DirBlobRef*> grandparent();
virtual fspp::Dir::EntryType getType() const = 0;
void removeNode();
private:
void _updateParentModificationTimestamp();
void _updateTargetDirModificationTimestamp(const parallelaccessfsblobstore::DirBlobRef &targetDir, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> targetDirParent);
CryDevice *_device;
boost::optional<std::shared_ptr<parallelaccessfsblobstore::DirBlobRef>> _parent;
boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> _grandparent;
blockstore::Key _key;
DISALLOW_COPY_AND_ASSIGN(CryNode);

View File

@ -25,8 +25,8 @@ using cryfs::parallelaccessfsblobstore::DirBlobRef;
namespace cryfs {
CrySymlink::CrySymlink(CryDevice *device, unique_ref<DirBlobRef> parent, const Key &key)
: CryNode(device, std::move(parent), key) {
CrySymlink::CrySymlink(CryDevice *device, unique_ref<DirBlobRef> parent, optional<unique_ref<DirBlobRef>> grandparent, const Key &key)
: CryNode(device, std::move(parent), std::move(grandparent), key) {
}
CrySymlink::~CrySymlink() {
@ -53,6 +53,10 @@ bf::path CrySymlink::target() {
void CrySymlink::remove() {
device()->callFsActionCallbacks();
if (grandparent() != none) {
//TODO Instead of doing nothing when we're in the root directory, handle timestamps in the root dir correctly
(*grandparent())->updateModificationTimestampForChild(parent()->key());
}
removeNode();
}

View File

@ -11,7 +11,7 @@ namespace cryfs {
class CrySymlink final: public fspp::Symlink, CryNode {
public:
CrySymlink(CryDevice *device, cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> parent, const blockstore::Key &key);
CrySymlink(CryDevice *device, cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::Key &key);
~CrySymlink();
boost::filesystem::path target() override;

View File

@ -32,7 +32,7 @@ public:
//TODO Allow alternative implementation returning only children names without more information
//virtual std::unique_ptr<std::vector<std::string>> children() const = 0;
virtual cpputils::unique_ref<std::vector<Entry>> children() const = 0;
virtual cpputils::unique_ref<std::vector<Entry>> children() = 0;
};
}

View File

@ -12,26 +12,29 @@
#include "FsppOpenFileTest.h"
#include "FsppDeviceTest_Timestamps.h"
#include "FsppNodeTest_Timestamps.h"
#include "FsppDirTest_Timestamps.h"
#include "FsppSymlinkTest_Timestamps.h"
#include "FsppFileTest_Timestamps.h"
#include "FsppOpenFileTest_Timestamps.h"
#define FSPP_ADD_FILESYTEM_TESTS(FS_NAME, FIXTURE) \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDeviceTest, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppDeviceTest_Timestamps, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDirTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppFileTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppFileTest_Timestamps, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppSymlinkTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppSymlinkTest_Timestamps, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Rename, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Stat, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Timestamps, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_FileOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_DirOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_SymlinkOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppOpenFileTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppOpenFileTest_Timestamps, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDeviceTest, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppDeviceTest_Timestamps, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDirTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDirTest_Timestamps, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppDirTest_Timestamps_Entries, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppFileTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppFileTest_Timestamps, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppSymlinkTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppSymlinkTest_Timestamps, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Rename, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Stat, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Timestamps, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_FileOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_DirOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_SymlinkOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppOpenFileTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppOpenFileTest_Timestamps, FIXTURE); \
#endif

View File

@ -17,14 +17,14 @@ public:
}
void EXPECT_CHILDREN_ARE(const boost::filesystem::path &path, const std::initializer_list<fspp::Dir::Entry> expected) {
EXPECT_CHILDREN_ARE(*this->LoadDir(path), expected);
EXPECT_CHILDREN_ARE(this->LoadDir(path).get(), expected);
}
void EXPECT_CHILDREN_ARE(const fspp::Dir &dir, const std::initializer_list<fspp::Dir::Entry> expected) {
void EXPECT_CHILDREN_ARE(fspp::Dir *dir, const std::initializer_list<fspp::Dir::Entry> expected) {
std::vector<fspp::Dir::Entry> expectedChildren = expected;
expectedChildren.push_back(fspp::Dir::Entry(fspp::Dir::EntryType::DIR, "."));
expectedChildren.push_back(fspp::Dir::Entry(fspp::Dir::EntryType::DIR, ".."));
EXPECT_UNORDERED_EQ(expectedChildren, *dir.children());
EXPECT_UNORDERED_EQ(expectedChildren, *dir->children());
}
template<class Entry>
@ -63,7 +63,7 @@ TYPED_TEST_P(FsppDirTest, Children_RootDir_Empty) {
TYPED_TEST_P(FsppDirTest, Children_RootDir_OneFile_Directly) {
auto rootdir = this->LoadDir("/");
rootdir->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
this->EXPECT_CHILDREN_ARE(*rootdir, {
this->EXPECT_CHILDREN_ARE(rootdir.get(), {
FileEntry("myfile")
});
}
@ -78,7 +78,7 @@ TYPED_TEST_P(FsppDirTest, Children_RootDir_OneFile_AfterReloadingDir) {
TYPED_TEST_P(FsppDirTest, Children_RootDir_OneDir_Directly) {
auto rootdir = this->LoadDir("/");
rootdir->createDir("mydir", this->MODE_PUBLIC, 0, 0);
this->EXPECT_CHILDREN_ARE(*rootdir, {
this->EXPECT_CHILDREN_ARE(rootdir.get(), {
DirEntry("mydir")
});
}
@ -108,7 +108,7 @@ TYPED_TEST_P(FsppDirTest, Children_Nested_OneFile_Directly) {
this->LoadDir("/")->createDir("mydir", this->MODE_PUBLIC, 0, 0);
auto dir = this->LoadDir("/mydir");
dir->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
this->EXPECT_CHILDREN_ARE(*dir, {
this->EXPECT_CHILDREN_ARE(dir.get(), {
FileEntry("myfile")
});
}
@ -125,7 +125,7 @@ TYPED_TEST_P(FsppDirTest, Children_Nested_OneDir_Directly) {
this->LoadDir("/")->createDir("mydir", this->MODE_PUBLIC, 0, 0);
auto dir = this->LoadDir("/mydir");
dir->createDir("mysubdir", this->MODE_PUBLIC, 0, 0);
this->EXPECT_CHILDREN_ARE(*dir, {
this->EXPECT_CHILDREN_ARE(dir.get(), {
DirEntry("mysubdir")
});
}

View File

@ -0,0 +1,244 @@
#pragma once
#ifndef MESSMER_FSPP_FSTEST_FSPPDIRTEST_TIMESTAMPS_H_
#define MESSMER_FSPP_FSTEST_FSPPDIRTEST_TIMESTAMPS_H_
#include "testutils/TimestampTestUtils.h"
template<class ConcreteFileSystemTestFixture>
class FsppDirTest_Timestamps: public FileSystemTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<fspp::Node> {
public:
};
TYPED_TEST_CASE_P(FsppDirTest_Timestamps);
TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile) {
auto dir = this->CreateDir("/mydir");
auto operation = [&dir] () {
dir->createAndOpenFile("childname", S_IFREG, 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_inRootDir) {
auto dir = this->LoadDir("/");
auto operation = [&dir] () {
dir->createAndOpenFile("childname", S_IFREG, 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_TimestampsOfCreatedFile) {
auto dir = this->CreateDir("/mydir");
timespec lowerBound = now();
dir->createAndOpenFile("childname", S_IFREG, 1000, 1000);
timespec upperBound = now();
auto child = this->LoadFile("/mydir/childname");
this->EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *child);
}
TYPED_TEST_P(FsppDirTest_Timestamps, createDir) {
auto dir = this->CreateDir("/mydir");
auto operation = [&dir] () {
dir->createDir("childname", S_IFDIR, 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
TYPED_TEST_P(FsppDirTest_Timestamps, createDir_inRootDir) {
auto dir = this->LoadDir("/");
auto operation = [&dir] () {
dir->createDir("childname", S_IFDIR, 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
TYPED_TEST_P(FsppDirTest_Timestamps, createDir_TimestampsOfCreatedDir) {
auto dir = this->CreateDir("/mydir");
timespec lowerBound = now();
dir->createDir("childname", S_IFDIR, 1000, 1000);
timespec upperBound = now();
auto child = this->LoadDir("/mydir/childname");
this->EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *child);
}
TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink) {
auto dir = this->CreateDir("/mydir");
auto operation = [&dir] () {
dir->createSymlink("childname", "/target", 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_inRootDir) {
auto dir = this->LoadDir("/");
auto operation = [&dir] () {
dir->createSymlink("childname", "/target", 1000, 1000);
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_TimestampsOfCreatedSymlink) {
auto dir = this->CreateDir("/mydir");
timespec lowerBound = now();
dir->createSymlink("childname", "/target", 1000, 1000);
timespec upperBound = now();
auto child = this->LoadSymlink("/mydir/childname");
this->EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *child);
this->EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *child);
}
TYPED_TEST_P(FsppDirTest_Timestamps, children_empty) {
auto dir = this->CreateDir("/mydir");
auto operation = [&dir] () {
dir->children();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
TYPED_TEST_P(FsppDirTest_Timestamps, children_empty_inRootDir) {
auto dir = this->LoadDir("/");
auto operation = [&dir] () {
dir->children();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
}*/
TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty) {
auto dir = this->CreateDir("/mydir");
dir->createAndOpenFile("filename", S_IFREG, 1000, 1000);
auto operation = [&dir] () {
dir->children();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty_inRootDir) {
auto dir = this->LoadDir("/");
dir->createAndOpenFile("filename", S_IFREG, 1000, 1000);
auto operation = [&dir] () {
dir->children();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
}*/
template<class ConcreteFileSystemTestFixture>
class FsppDirTest_Timestamps_Entries: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<fspp::Node> {
public:
void Test_deleteChild() {
auto dir = this->CreateDir("/mydir");
auto child = this->CreateNode("/mydir/childname");
auto operation = [&child]() {
child->remove();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
void Test_deleteChild_inRootDir() {
auto dir = this->LoadDir("/");
auto child = this->CreateNode("/childname");
auto operation = [&child] () {
child->remove();
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
void Test_renameChild() {
auto dir = this->CreateDir("/mydir");
auto child = this->CreateNode("/mydir/childname");
auto operation = [&child]() {
child->rename("/mydir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
void Test_renameChild_inRootDir() {
auto dir = this->LoadDir("/");
auto child = this->CreateNode("/childname");
auto operation = [&child] () {
child->rename("/mydir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
void Test_moveChildIn() {
auto sourceDir = this->CreateDir("/sourcedir");
auto child = this->CreateNode("/sourcedir/childname");
auto dir = this->CreateDir("/mydir");
auto operation = [&child]() {
child->rename("/mydir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
void Test_moveChildIn_inRootDir() {
auto sourceDir = this->CreateDir("/sourcedir");
auto child = this->CreateNode("/sourcedir/childname");
auto dir = this->LoadDir("/");
auto operation = [&child] () {
child->rename("/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
void Test_moveChildOut() {
auto dir = this->CreateDir("/mydir");
auto child = this->CreateNode("/mydir/childname");
this->CreateDir("/targetdir");
auto operation = [&child]() {
child->rename("/targetdir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
this->ExpectUpdatesModificationTimestamp,
this->ExpectUpdatesMetadataTimestamp});
}
/* TODO Re-enable this test once the root dir handles timestamps correctly
void Test_moveChildOut_inRootDir() {
auto dir = this->LoadDir("/");
auto child = this->CreateNode("/childname");
this->CreateDir("/targetdir");
auto operation = [&child] () {
child->rename("/targetdir/mychild");
};
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
}*/
};
REGISTER_TYPED_TEST_CASE_P(FsppDirTest_Timestamps,
createAndOpenFile,
createAndOpenFile_TimestampsOfCreatedFile,
createDir,
createDir_TimestampsOfCreatedDir,
createSymlink,
createSymlink_TimestampsOfCreatedSymlink,
children_empty,
children_nonempty
);
REGISTER_NODE_TEST_CASE(FsppDirTest_Timestamps_Entries,
deleteChild,
renameChild,
moveChildIn,
moveChildOut
);
#endif