fspp::Dir, fspp::File and fspp::Symlink don't inherit from fspp::Node anymore. This allows file systems to return a generic fspp::Node instead of a concrete subclass when the operation doesn't need to know what type of node it is.
This commit is contained in:
parent
002b1a2e23
commit
e37d84a3d6
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,3 +7,5 @@ umltest.status
|
||||
|
||||
src/gitversion/*.pyc
|
||||
src/gitversion/__pycache__
|
||||
cmake-build-debug
|
||||
cmake-build-release
|
||||
|
@ -66,7 +66,44 @@ Key CryDevice::CreateRootBlobAndReturnKey() {
|
||||
return rootBlob->key();
|
||||
}
|
||||
|
||||
optional<unique_ref<fspp::File>> CryDevice::LoadFile(const bf::path &path) {
|
||||
auto loaded = Load(path);
|
||||
if (loaded == none) {
|
||||
return none;
|
||||
}
|
||||
auto file = cpputils::dynamic_pointer_move<fspp::File>(*loaded);
|
||||
if (file == none) {
|
||||
throw fspp::fuse::FuseErrnoException(EISDIR); // TODO Also EISDIR if it is a symlink?
|
||||
}
|
||||
return std::move(*file);
|
||||
}
|
||||
|
||||
optional<unique_ref<fspp::Dir>> CryDevice::LoadDir(const bf::path &path) {
|
||||
auto loaded = Load(path);
|
||||
if (loaded == none) {
|
||||
return none;
|
||||
}
|
||||
auto dir = cpputils::dynamic_pointer_move<fspp::Dir>(*loaded);
|
||||
if (dir == none) {
|
||||
throw fspp::fuse::FuseErrnoException(ENOTDIR);
|
||||
}
|
||||
return std::move(*dir);
|
||||
}
|
||||
|
||||
optional<unique_ref<fspp::Symlink>> CryDevice::LoadSymlink(const bf::path &path) {
|
||||
auto loaded = Load(path);
|
||||
if (loaded == none) {
|
||||
return none;
|
||||
}
|
||||
auto lnk = cpputils::dynamic_pointer_move<fspp::Symlink>(*loaded);
|
||||
if (lnk == none) {
|
||||
throw fspp::fuse::FuseErrnoException(ENOTDIR); // TODO ENOTDIR although it is a symlink?
|
||||
}
|
||||
return std::move(*lnk);
|
||||
}
|
||||
|
||||
optional<unique_ref<fspp::Node>> CryDevice::Load(const bf::path &path) {
|
||||
// TODO Is it faster to not let CryFile/CryDir/CryDevice inherit from CryNode and loading CryNode without having to know what it is?
|
||||
// TODO Split into smaller functions
|
||||
ASSERT(path.is_absolute(), "Non absolute path given");
|
||||
|
||||
|
@ -35,6 +35,9 @@ public:
|
||||
void onFsAction(std::function<void()> callback);
|
||||
|
||||
boost::optional<cpputils::unique_ref<fspp::Node>> Load(const boost::filesystem::path &path) override;
|
||||
boost::optional<cpputils::unique_ref<fspp::File>> LoadFile(const boost::filesystem::path &path) override;
|
||||
boost::optional<cpputils::unique_ref<fspp::Dir>> LoadDir(const boost::filesystem::path &path) override;
|
||||
boost::optional<cpputils::unique_ref<fspp::Symlink>> LoadSymlink(const boost::filesystem::path &path) override;
|
||||
|
||||
void callFsActionCallbacks() const;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
class CryDir final: public fspp::Dir, CryNode {
|
||||
class CryDir final: public fspp::Dir, public CryNode {
|
||||
public:
|
||||
CryDir(CryDevice *device, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::Key &key);
|
||||
~CryDir();
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
class CryFile final: public fspp::File, CryNode {
|
||||
class CryFile final: public fspp::File, public CryNode {
|
||||
public:
|
||||
CryFile(CryDevice *device, cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::Key &key);
|
||||
~CryFile();
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
class CryNode: public virtual fspp::Node {
|
||||
class CryNode: public fspp::Node {
|
||||
public:
|
||||
virtual ~CryNode();
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace cryfs {
|
||||
|
||||
class CrySymlink final: public fspp::Symlink, CryNode {
|
||||
class CrySymlink final: public fspp::Symlink, public CryNode {
|
||||
public:
|
||||
CrySymlink(CryDevice *device, cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef> parent, boost::optional<cpputils::unique_ref<parallelaccessfsblobstore::DirBlobRef>> grandparent, const blockstore::Key &key);
|
||||
~CrySymlink();
|
||||
|
@ -8,6 +8,9 @@
|
||||
|
||||
namespace fspp {
|
||||
class Node;
|
||||
class File;
|
||||
class Dir;
|
||||
class Symlink;
|
||||
|
||||
class Device {
|
||||
public:
|
||||
@ -15,6 +18,14 @@ public:
|
||||
|
||||
virtual void statfs(const boost::filesystem::path &path, struct ::statvfs *fsstat) = 0;
|
||||
virtual boost::optional<cpputils::unique_ref<Node>> Load(const boost::filesystem::path &path) = 0;
|
||||
|
||||
//TODO Test default implementation (Device.cpp)
|
||||
//TODO Test client implementation (fstest)
|
||||
//TODO When it exists but is wrong node type, don't throw exception, but return this somehow (or at least throw specific exception, not just FuseErrnoException)
|
||||
virtual boost::optional<cpputils::unique_ref<File>> LoadFile(const boost::filesystem::path &path) = 0;
|
||||
virtual boost::optional<cpputils::unique_ref<Dir>> LoadDir(const boost::filesystem::path &path) = 0;
|
||||
virtual boost::optional<cpputils::unique_ref<Symlink>> LoadSymlink(const boost::filesystem::path &path) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -2,15 +2,15 @@
|
||||
#ifndef MESSMER_FSPP_FSINTERFACE_DIR_H_
|
||||
#define MESSMER_FSPP_FSINTERFACE_DIR_H_
|
||||
|
||||
#include "Node.h"
|
||||
#include <cpp-utils/pointer/unique_ref.h>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
namespace fspp {
|
||||
class Device;
|
||||
class OpenFile;
|
||||
|
||||
class Dir: public virtual Node {
|
||||
class Dir {
|
||||
public:
|
||||
virtual ~Dir() {}
|
||||
|
||||
|
@ -2,14 +2,13 @@
|
||||
#ifndef MESSMER_FSPP_FSINTERFACE_FILE_H_
|
||||
#define MESSMER_FSPP_FSINTERFACE_FILE_H_
|
||||
|
||||
#include "Node.h"
|
||||
#include <cpp-utils/pointer/unique_ref.h>
|
||||
|
||||
namespace fspp {
|
||||
class Device;
|
||||
class OpenFile;
|
||||
|
||||
class File: public virtual Node {
|
||||
class File {
|
||||
public:
|
||||
virtual ~File() {}
|
||||
|
||||
|
@ -2,14 +2,14 @@
|
||||
#ifndef MESSMER_FSPP_FSINTERFACE_SYMLINK_H_
|
||||
#define MESSMER_FSPP_FSINTERFACE_SYMLINK_H_
|
||||
|
||||
#include "Node.h"
|
||||
#include <cpp-utils/pointer/unique_ref.h>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
namespace fspp {
|
||||
class Device;
|
||||
|
||||
class Symlink: public virtual Node {
|
||||
class Symlink {
|
||||
public:
|
||||
virtual ~Symlink() {}
|
||||
|
||||
|
@ -18,7 +18,8 @@
|
||||
#include "FsppOpenFileTest_Timestamps.h"
|
||||
|
||||
#define FSPP_ADD_FILESYTEM_TESTS(FS_NAME, FIXTURE) \
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDeviceTest, FIXTURE); \
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDeviceTest_One, FIXTURE); \
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppDeviceTest_Two, 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); \
|
||||
|
@ -2,104 +2,481 @@
|
||||
#ifndef MESSMER_FSPP_FSTEST_FSPPDEVICETEST_H_
|
||||
#define MESSMER_FSPP_FSTEST_FSPPDEVICETEST_H_
|
||||
|
||||
#include <fspp/fuse/FuseErrnoException.h>
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppDeviceTest: public FileSystemTest<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
void InitDirStructure() {
|
||||
this->LoadDir("/")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadDir("/")->createSymlink("mysymlink", "/symlink/target", 0, 0);
|
||||
this->LoadDir("/")->createDir("mydir", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadDir("/")->createDir("myemptydir", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadDir("/mydir")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadDir("/mydir")->createAndOpenFile("myfile2", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadDir("/mydir")->createSymlink("mysymlink", "/symlink/target", 0, 0);
|
||||
this->LoadDir("/mydir")->createDir("mysubdir", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadDir("/mydir/mysubdir")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadDir("/mydir/mysubdir")->createSymlink("mysymlink", "/symlink/target", 0, 0);
|
||||
this->LoadDir("/mydir/mysubdir")->createDir("mysubsubdir", this->MODE_PUBLIC, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
TYPED_TEST_CASE_P(FsppDeviceTest);
|
||||
//Unfortunately, googletest only allows 50 test cases per REGISTER_TYPED_TEST_CASE_P, so we have to split it.
|
||||
template<class ConcreteFileSystemTestFixture> class FsppDeviceTest_One: public FsppDeviceTest<ConcreteFileSystemTestFixture> {};
|
||||
template<class ConcreteFileSystemTestFixture> class FsppDeviceTest_Two: public FsppDeviceTest<ConcreteFileSystemTestFixture> {};
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, InitFilesystem) {
|
||||
TYPED_TEST_CASE_P(FsppDeviceTest_One);
|
||||
TYPED_TEST_CASE_P(FsppDeviceTest_Two);
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, InitFilesystem) {
|
||||
//fixture->createDevice() is called in the FileSystemTest constructor
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadRootDir) {
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadRootDir_Load) {
|
||||
auto node = this->Load("/");
|
||||
this->EXPECT_IS_DIR(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadRootDir_LoadDir) {
|
||||
this->LoadDir("/");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadFileFromRootDir) {
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadRootDir_LoadFile) {
|
||||
EXPECT_THROW(
|
||||
this->LoadFile("/"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadRootDir_LoadSymlink) {
|
||||
EXPECT_THROW(
|
||||
this->LoadSymlink("/"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromRootDir_Load) {
|
||||
this->InitDirStructure();
|
||||
auto node = this->Load("/myfile");
|
||||
this->EXPECT_IS_FILE(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromRootDir_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
this->LoadFile("/myfile");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadDirFromRootDir) {
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromRootDir_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadDir("/myfile"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromRootDir_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadSymlink("/myfile"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromRootDir_Load) {
|
||||
this->InitDirStructure();
|
||||
auto node = this->Load("/mydir");
|
||||
this->EXPECT_IS_DIR(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromRootDir_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
this->LoadDir("/mydir");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromEmptyRootDir) {
|
||||
EXPECT_EQ(boost::none, this->device->Load("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromRootDir) {
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromRootDir_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->Load("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromNonexistingDir) {
|
||||
this->InitDirStructure();
|
||||
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
|
||||
EXPECT_ANY_THROW(
|
||||
this->device->Load("/nonexisting/nonexisting2")
|
||||
EXPECT_THROW(
|
||||
this->LoadFile("/mydir"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromExistingDir) {
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromRootDir_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadSymlink("/mydir"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromRootDir_Load) {
|
||||
this->InitDirStructure();
|
||||
auto node = this->Load("/mysymlink");
|
||||
this->EXPECT_IS_SYMLINK(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromRootDir_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
this->LoadSymlink("/mysymlink");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromRootDir_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadFile("/mysymlink"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromRootDir_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadDir("/mysymlink"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromEmptyRootDir_Load) {
|
||||
EXPECT_EQ(boost::none, this->device->Load("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromEmptyRootDir_LoadDir) {
|
||||
EXPECT_EQ(boost::none, this->device->LoadDir("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromEmptyRootDir_LoadFile) {
|
||||
EXPECT_EQ(boost::none, this->device->LoadFile("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromEmptyRootDir_LoadSymlink) {
|
||||
EXPECT_EQ(boost::none, this->device->LoadSymlink("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromRootDir_Load) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->Load("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromRootDir_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->LoadDir("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromRootDir_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->LoadFile("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromRootDir_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->LoadSymlink("/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromNonexistingDir_Load) {
|
||||
this->InitDirStructure();
|
||||
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
|
||||
EXPECT_ANY_THROW(
|
||||
this->device->Load("/nonexisting/nonexisting2")
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromNonexistingDir_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
|
||||
EXPECT_ANY_THROW(
|
||||
this->device->LoadDir("/nonexisting/nonexisting2")
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromNonexistingDir_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
|
||||
EXPECT_ANY_THROW(
|
||||
this->device->LoadFile("/nonexisting/nonexisting2")
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromNonexistingDir_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
//TODO Change as soon as we have a concept of how to handle filesystem errors in the interface
|
||||
EXPECT_ANY_THROW(
|
||||
this->device->LoadSymlink("/nonexisting/nonexisting2")
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingDir_Load) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->Load("/mydir/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadNonexistingFromExistingEmptyDir) {
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingDir_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->LoadDir("/mydir/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingDir_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->LoadFile("/mydir/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingDir_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->LoadSymlink("/mydir/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingEmptyDir_Load) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->Load("/myemptydir/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadFileFromDir_Nesting1) {
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingEmptyDir_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->LoadDir("/myemptydir/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingEmptyDir_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->LoadFile("/myemptydir/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadNonexistingFromExistingEmptyDir_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_EQ(boost::none, this->device->LoadSymlink("/myemptydir/nonexisting"));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromDir_Nesting1_Load) {
|
||||
this->InitDirStructure();
|
||||
auto node = this->Load("/mydir/myfile");
|
||||
this->EXPECT_IS_FILE(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromDir_Nesting1_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
this->LoadFile("/mydir/myfile");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadDirFromDir_Nesting1) {
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromDir_Nesting1_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadDir("/mydir/myfile"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadFileFromDir_Nesting1_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadSymlink("/mydir/myfile"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromDir_Nesting1_Load) {
|
||||
this->InitDirStructure();
|
||||
auto node = this->Load("/mydir/mysubdir");
|
||||
this->EXPECT_IS_DIR(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromDir_Nesting1_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
this->LoadDir("/mydir/mysubdir");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadFileFromDir_Nesting2) {
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromDir_Nesting1_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadFile("/mydir/mysubdir"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadDirFromDir_Nesting1_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadSymlink("/mydir/mysubdir"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromDir_Nesting1_Load) {
|
||||
this->InitDirStructure();
|
||||
auto node = this->Load("/mydir/mysymlink");
|
||||
this->EXPECT_IS_SYMLINK(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromDir_Nesting1_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
this->LoadSymlink("/mydir/mysymlink");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromDir_Nesting1_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadFile("/mydir/mysymlink"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_One, LoadSymlinkFromDir_Nesting1_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadDir("/mydir/mysymlink"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadFileFromDir_Nesting2_Load) {
|
||||
this->InitDirStructure();
|
||||
auto node = this->Load("/mydir/mysubdir/myfile");
|
||||
this->EXPECT_IS_FILE(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadFileFromDir_Nesting2_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
this->LoadFile("/mydir/mysubdir/myfile");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest, LoadDirFromDir_Nesting2) {
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadFileFromDir_Nesting2_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadDir("/mydir/mysubdir/myfile"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadFileFromDir_Nesting2_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadSymlink("/mydir/mysubdir/myfile"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadDirFromDir_Nesting2_Load) {
|
||||
this->InitDirStructure();
|
||||
auto node = this->Load("/mydir/mysubdir/mysubsubdir");
|
||||
this->EXPECT_IS_DIR(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadDirFromDir_Nesting2_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
this->LoadDir("/mydir/mysubdir/mysubsubdir");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadDirFromDir_Nesting2_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadFile("/mydir/mysubdir/mysubsubdir"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadDirFromDir_Nesting2_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadSymlink("/mydir/mysubdir/mysubsubdir"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadSymlinkFromDir_Nesting2_Load) {
|
||||
this->InitDirStructure();
|
||||
auto node = this->Load("/mydir/mysubdir/mysymlink");
|
||||
this->EXPECT_IS_SYMLINK(node);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadSymlinkFromDir_Nesting2_LoadSymlink) {
|
||||
this->InitDirStructure();
|
||||
this->LoadSymlink("/mydir/mysubdir/mysymlink");
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadSymlinkFromDir_Nesting2_LoadFile) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadFile("/mydir/mysubdir/mysymlink"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDeviceTest_Two, LoadSymlinkFromDir_Nesting2_LoadDir) {
|
||||
this->InitDirStructure();
|
||||
EXPECT_THROW(
|
||||
this->LoadDir("/mydir/mysubdir/mysymlink"),
|
||||
fspp::fuse::FuseErrnoException
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//TODO Test statfs
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(FsppDeviceTest,
|
||||
REGISTER_TYPED_TEST_CASE_P(FsppDeviceTest_One,
|
||||
InitFilesystem,
|
||||
LoadRootDir,
|
||||
LoadFileFromRootDir,
|
||||
LoadDirFromRootDir,
|
||||
LoadNonexistingFromEmptyRootDir,
|
||||
LoadNonexistingFromRootDir,
|
||||
LoadNonexistingFromNonexistingDir,
|
||||
LoadNonexistingFromExistingDir,
|
||||
LoadNonexistingFromExistingEmptyDir,
|
||||
LoadFileFromDir_Nesting1,
|
||||
LoadDirFromDir_Nesting1,
|
||||
LoadFileFromDir_Nesting2,
|
||||
LoadDirFromDir_Nesting2
|
||||
LoadRootDir_Load,
|
||||
LoadRootDir_LoadDir,
|
||||
LoadRootDir_LoadFile,
|
||||
LoadRootDir_LoadSymlink,
|
||||
LoadFileFromRootDir_Load,
|
||||
LoadFileFromRootDir_LoadFile,
|
||||
LoadFileFromRootDir_LoadDir,
|
||||
LoadFileFromRootDir_LoadSymlink,
|
||||
LoadDirFromRootDir_Load,
|
||||
LoadDirFromRootDir_LoadDir,
|
||||
LoadDirFromRootDir_LoadFile,
|
||||
LoadDirFromRootDir_LoadSymlink,
|
||||
LoadSymlinkFromRootDir_Load,
|
||||
LoadSymlinkFromRootDir_LoadSymlink,
|
||||
LoadSymlinkFromRootDir_LoadFile,
|
||||
LoadSymlinkFromRootDir_LoadDir,
|
||||
LoadNonexistingFromEmptyRootDir_Load,
|
||||
LoadNonexistingFromEmptyRootDir_LoadDir,
|
||||
LoadNonexistingFromEmptyRootDir_LoadFile,
|
||||
LoadNonexistingFromEmptyRootDir_LoadSymlink,
|
||||
LoadNonexistingFromRootDir_Load,
|
||||
LoadNonexistingFromRootDir_LoadDir,
|
||||
LoadNonexistingFromRootDir_LoadFile,
|
||||
LoadNonexistingFromRootDir_LoadSymlink,
|
||||
LoadNonexistingFromNonexistingDir_Load,
|
||||
LoadNonexistingFromNonexistingDir_LoadDir,
|
||||
LoadNonexistingFromNonexistingDir_LoadFile,
|
||||
LoadNonexistingFromNonexistingDir_LoadSymlink,
|
||||
LoadNonexistingFromExistingDir_Load,
|
||||
LoadNonexistingFromExistingDir_LoadDir,
|
||||
LoadNonexistingFromExistingDir_LoadFile,
|
||||
LoadNonexistingFromExistingDir_LoadSymlink,
|
||||
LoadNonexistingFromExistingEmptyDir_Load,
|
||||
LoadNonexistingFromExistingEmptyDir_LoadDir,
|
||||
LoadNonexistingFromExistingEmptyDir_LoadFile,
|
||||
LoadNonexistingFromExistingEmptyDir_LoadSymlink,
|
||||
LoadFileFromDir_Nesting1_Load,
|
||||
LoadFileFromDir_Nesting1_LoadFile,
|
||||
LoadFileFromDir_Nesting1_LoadDir,
|
||||
LoadFileFromDir_Nesting1_LoadSymlink,
|
||||
LoadDirFromDir_Nesting1_Load,
|
||||
LoadDirFromDir_Nesting1_LoadDir,
|
||||
LoadDirFromDir_Nesting1_LoadFile,
|
||||
LoadDirFromDir_Nesting1_LoadSymlink,
|
||||
LoadSymlinkFromDir_Nesting1_Load,
|
||||
LoadSymlinkFromDir_Nesting1_LoadSymlink,
|
||||
LoadSymlinkFromDir_Nesting1_LoadFile,
|
||||
LoadSymlinkFromDir_Nesting1_LoadDir
|
||||
);
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(FsppDeviceTest_Two,
|
||||
LoadFileFromDir_Nesting2_Load,
|
||||
LoadFileFromDir_Nesting2_LoadFile,
|
||||
LoadFileFromDir_Nesting2_LoadDir,
|
||||
LoadFileFromDir_Nesting2_LoadSymlink,
|
||||
LoadDirFromDir_Nesting2_Load,
|
||||
LoadDirFromDir_Nesting2_LoadDir,
|
||||
LoadDirFromDir_Nesting2_LoadFile,
|
||||
LoadDirFromDir_Nesting2_LoadSymlink,
|
||||
LoadSymlinkFromDir_Nesting2_Load,
|
||||
LoadSymlinkFromDir_Nesting2_LoadSymlink,
|
||||
LoadSymlinkFromDir_Nesting2_LoadFile,
|
||||
LoadSymlinkFromDir_Nesting2_LoadDir
|
||||
);
|
||||
|
||||
//TODO Missing tests: LoadSymlink
|
||||
|
||||
#endif
|
||||
|
@ -5,21 +5,21 @@
|
||||
#include "testutils/TimestampTestUtils.h"
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppDeviceTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
|
||||
class FsppDeviceTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
void Test_Load_While_Loaded() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
auto operation = [this, &node] () {
|
||||
this->device->Load("/mynode");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}
|
||||
|
||||
void Test_Load_While_Not_Loaded() {
|
||||
struct stat oldStat;
|
||||
{
|
||||
auto node = this->CreateNode("/mynode");
|
||||
oldStat = stat(*node);
|
||||
oldStat = this->stat(*node);
|
||||
this->ensureNodeTimestampsAreOld(oldStat);
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ public:
|
||||
auto node = this->device->Load("/mynode");
|
||||
|
||||
//Test that timestamps didn't change
|
||||
struct stat newStat = stat(*node.value());
|
||||
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);
|
||||
|
@ -163,6 +163,7 @@ TYPED_TEST_P(FsppDirTest, Children_Nested2_LargerStructure) {
|
||||
TYPED_TEST_P(FsppDirTest, CreateAndOpenFile_InEmptyRoot) {
|
||||
this->LoadDir("/")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadFile("/myfile");
|
||||
this->Load("/myfile"); // Test that we can also load the file node
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest, CreateAndOpenFile_InNonemptyRoot) {
|
||||
@ -206,6 +207,7 @@ TYPED_TEST_P(FsppDirTest, CreateAndOpenFile_AlreadyExisting) {
|
||||
TYPED_TEST_P(FsppDirTest, CreateDir_InEmptyRoot) {
|
||||
this->LoadDir("/")->createDir("mydir", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadDir("/mydir");
|
||||
this->Load("/mydir"); // Test we can also load the dir node
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppDirTest, CreateDir_InNonemptyRoot) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "testutils/TimestampTestUtils.h"
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppDirTest_Timestamps: public FileSystemTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
|
||||
class FsppDirTest_Timestamps: public TimestampTestUtils<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
};
|
||||
TYPED_TEST_CASE_P(FsppDirTest_Timestamps);
|
||||
@ -15,7 +15,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile) {
|
||||
auto operation = [&dir] () {
|
||||
dir->createAndOpenFile("childname", S_IFREG, 1000, 1000);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
@ -24,7 +24,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_inRootDir) {
|
||||
auto operation = [&dir] () {
|
||||
dir->createAndOpenFile("childname", S_IFREG, 1000, 1000);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_TimestampsOfCreatedFile) {
|
||||
@ -32,7 +32,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createAndOpenFile_TimestampsOfCreatedFile)
|
||||
timespec lowerBound = now();
|
||||
dir->createAndOpenFile("childname", S_IFREG, 1000, 1000);
|
||||
timespec upperBound = now();
|
||||
auto child = this->LoadFile("/mydir/childname");
|
||||
auto child = this->Load("/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);
|
||||
@ -43,7 +43,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createDir) {
|
||||
auto operation = [&dir] () {
|
||||
dir->createDir("childname", S_IFDIR, 1000, 1000);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
@ -52,7 +52,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createDir_inRootDir) {
|
||||
auto operation = [&dir] () {
|
||||
dir->createDir("childname", S_IFDIR, 1000, 1000);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createDir_TimestampsOfCreatedDir) {
|
||||
@ -60,7 +60,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createDir_TimestampsOfCreatedDir) {
|
||||
timespec lowerBound = now();
|
||||
dir->createDir("childname", S_IFDIR, 1000, 1000);
|
||||
timespec upperBound = now();
|
||||
auto child = this->LoadDir("/mydir/childname");
|
||||
auto child = this->Load("/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);
|
||||
@ -71,7 +71,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink) {
|
||||
auto operation = [&dir] () {
|
||||
dir->createSymlink("childname", "/target", 1000, 1000);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
@ -80,7 +80,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_inRootDir) {
|
||||
auto operation = [&dir] () {
|
||||
dir->createSymlink("childname", "/target", 1000, 1000);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_TimestampsOfCreatedSymlink) {
|
||||
@ -88,7 +88,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, createSymlink_TimestampsOfCreatedSymlink) {
|
||||
timespec lowerBound = now();
|
||||
dir->createSymlink("childname", "/target", 1000, 1000);
|
||||
timespec upperBound = now();
|
||||
auto child = this->LoadSymlink("/mydir/childname");
|
||||
auto child = this->Load("/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);
|
||||
@ -99,7 +99,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, children_empty) {
|
||||
auto operation = [&dir] () {
|
||||
dir->children();
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
@ -108,7 +108,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, children_empty_inRootDir) {
|
||||
auto operation = [&dir] () {
|
||||
dir->children();
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}*/
|
||||
|
||||
TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty) {
|
||||
@ -117,7 +117,7 @@ TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty) {
|
||||
auto operation = [&dir] () {
|
||||
dir->children();
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
@ -127,11 +127,11 @@ TYPED_TEST_P(FsppDirTest_Timestamps, children_nonempty_inRootDir) {
|
||||
auto operation = [&dir] () {
|
||||
dir->children();
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}*/
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppDirTest_Timestamps_Entries: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
|
||||
class FsppDirTest_Timestamps_Entries: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
|
||||
void Test_deleteChild() {
|
||||
@ -140,9 +140,11 @@ public:
|
||||
auto operation = [&child]() {
|
||||
child->remove();
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
@ -152,7 +154,7 @@ public:
|
||||
auto operation = [&child] () {
|
||||
child->remove();
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
|
||||
void Test_renameChild() {
|
||||
@ -161,9 +163,11 @@ public:
|
||||
auto operation = [&child]() {
|
||||
child->rename("/mydir/mychild");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
@ -173,7 +177,7 @@ public:
|
||||
auto operation = [&child] () {
|
||||
child->rename("/mydir/mychild");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
|
||||
void Test_moveChildIn() {
|
||||
@ -183,9 +187,11 @@ public:
|
||||
auto operation = [&child]() {
|
||||
child->rename("/mydir/mychild");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
@ -196,7 +202,7 @@ public:
|
||||
auto operation = [&child] () {
|
||||
child->rename("/mychild");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
|
||||
void Test_moveChildOut() {
|
||||
@ -206,9 +212,11 @@ public:
|
||||
auto operation = [&child]() {
|
||||
child->rename("/targetdir/mychild");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectUpdatesModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
/* TODO Re-enable this test once the root dir handles timestamps correctly
|
||||
@ -219,7 +227,7 @@ public:
|
||||
auto operation = [&child] () {
|
||||
child->rename("/targetdir/mychild");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*dir, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}*/
|
||||
};
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include "testutils/FileTest.h"
|
||||
|
||||
//TODO Restructure. FsppFileTest tests fspp::File interface. All tests for fspp::Node interface go to a FsppNodeTest.
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppFileTest: public FileTest<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
@ -22,65 +24,65 @@ public:
|
||||
file->open(O_RDONLY);
|
||||
}
|
||||
|
||||
void Test_Truncate_DontChange1(fspp::File *file) {
|
||||
void Test_Truncate_DontChange1(fspp::File *file, fspp::Node *node) {
|
||||
file->truncate(0);
|
||||
this->EXPECT_SIZE(0, file);
|
||||
this->EXPECT_SIZE(0, file, node);
|
||||
}
|
||||
|
||||
void Test_Truncate_GrowTo1(fspp::File *file) {
|
||||
void Test_Truncate_GrowTo1(fspp::File *file, fspp::Node *node) {
|
||||
file->truncate(1);
|
||||
this->EXPECT_SIZE(1, file);
|
||||
this->EXPECT_SIZE(1, file, node);
|
||||
}
|
||||
|
||||
void Test_Truncate_Grow(fspp::File *file) {
|
||||
void Test_Truncate_Grow(fspp::File *file, fspp::Node *node) {
|
||||
file->truncate(10*1024*1024);
|
||||
this->EXPECT_SIZE(10*1024*1024, file);
|
||||
this->EXPECT_SIZE(10*1024*1024, file, node);
|
||||
}
|
||||
|
||||
void Test_Truncate_DontChange2(fspp::File *file) {
|
||||
void Test_Truncate_DontChange2(fspp::File *file, fspp::Node *node) {
|
||||
file->truncate(10*1024*1024);
|
||||
file->truncate(10*1024*1024);
|
||||
this->EXPECT_SIZE(10*1024*1024, file);
|
||||
this->EXPECT_SIZE(10*1024*1024, file, node);
|
||||
}
|
||||
|
||||
void Test_Truncate_Shrink(fspp::File *file) {
|
||||
void Test_Truncate_Shrink(fspp::File *file, fspp::Node *node) {
|
||||
file->truncate(10*1024*1024);
|
||||
file->truncate(5*1024*1024);
|
||||
this->EXPECT_SIZE(5*1024*1024, file);
|
||||
this->EXPECT_SIZE(5*1024*1024, file, node);
|
||||
}
|
||||
|
||||
void Test_Truncate_ShrinkTo0(fspp::File *file) {
|
||||
void Test_Truncate_ShrinkTo0(fspp::File *file, fspp::Node *node) {
|
||||
file->truncate(10*1024*1024);
|
||||
file->truncate(0);
|
||||
this->EXPECT_SIZE(0, file);
|
||||
this->EXPECT_SIZE(0, file, node);
|
||||
}
|
||||
|
||||
void Test_Chown_Uid(fspp::File *file) {
|
||||
file->chown(100, 200);
|
||||
this->IN_STAT(file, [] (struct stat st){
|
||||
EXPECT_EQ(100u, st.st_uid);
|
||||
});
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Chown_Gid(fspp::File *file) {
|
||||
file->chown(100, 200);
|
||||
this->IN_STAT(file, [] (struct stat st){
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Chmod(fspp::File *file) {
|
||||
file->chmod(S_IFREG | S_IRUSR | S_IWOTH);
|
||||
this->IN_STAT(file, [] (struct stat st){
|
||||
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((mode_t)(S_IFREG | S_IRUSR | S_IWOTH), st.st_mode);
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Utimens(fspp::File *file) {
|
||||
void Test_Utimens(fspp::File *file, fspp::Node *node) {
|
||||
struct timespec ATIME; ATIME.tv_sec = 1458086400; ATIME.tv_nsec = 34525;
|
||||
struct timespec MTIME; MTIME.tv_sec = 1458086300; MTIME.tv_nsec = 48293;
|
||||
file->utimens(ATIME, MTIME);
|
||||
this->IN_STAT(file, [this, ATIME, MTIME] (struct stat st) {
|
||||
node->utimens(ATIME, MTIME);
|
||||
this->IN_STAT(file, node, [this, ATIME, MTIME] (struct stat st) {
|
||||
this->EXPECT_ATIME_EQ(ATIME, st);
|
||||
this->EXPECT_MTIME_EQ(MTIME, st);
|
||||
});
|
||||
@ -114,83 +116,83 @@ TYPED_TEST_P(FsppFileTest, Open_RDWR_Nested) {
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_DontChange1) {
|
||||
this->Test_Truncate_DontChange1(this->file_root.get());
|
||||
this->Test_Truncate_DontChange1(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_DontChange1_Nested) {
|
||||
this->Test_Truncate_DontChange1(this->file_nested.get());
|
||||
this->Test_Truncate_DontChange1(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_GrowTo1) {
|
||||
this->Test_Truncate_GrowTo1(this->file_root.get());
|
||||
this->Test_Truncate_GrowTo1(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_GrowTo1_Nested) {
|
||||
this->Test_Truncate_GrowTo1(this->file_nested.get());
|
||||
this->Test_Truncate_GrowTo1(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_Grow) {
|
||||
this->Test_Truncate_Grow(this->file_root.get());
|
||||
this->Test_Truncate_Grow(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_Grow_Nested) {
|
||||
this->Test_Truncate_Grow(this->file_nested.get());
|
||||
this->Test_Truncate_Grow(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_DontChange2) {
|
||||
this->Test_Truncate_DontChange2(this->file_root.get());
|
||||
this->Test_Truncate_DontChange2(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_DontChange2_Nested) {
|
||||
this->Test_Truncate_DontChange2(this->file_nested.get());
|
||||
this->Test_Truncate_DontChange2(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_Shrink) {
|
||||
this->Test_Truncate_Shrink(this->file_root.get());
|
||||
this->Test_Truncate_Shrink(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_Shrink_Nested) {
|
||||
this->Test_Truncate_Shrink(this->file_nested.get());
|
||||
this->Test_Truncate_Shrink(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_ShrinkTo0) {
|
||||
this->Test_Truncate_ShrinkTo0(this->file_root.get());
|
||||
this->Test_Truncate_ShrinkTo0(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Truncate_ShrinkTo0_Nested) {
|
||||
this->Test_Truncate_ShrinkTo0(this->file_nested.get());
|
||||
this->Test_Truncate_ShrinkTo0(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Chown_Uid) {
|
||||
this->Test_Chown_Uid(this->file_root.get());
|
||||
this->Test_Chown_Uid(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Chown_Uid_Nested) {
|
||||
this->Test_Chown_Uid(this->file_nested.get());
|
||||
this->Test_Chown_Uid(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Chown_Gid) {
|
||||
this->Test_Chown_Gid(this->file_root.get());
|
||||
this->Test_Chown_Gid(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Chown_Gid_Nested) {
|
||||
this->Test_Chown_Gid(this->file_nested.get());
|
||||
this->Test_Chown_Gid(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Chmod) {
|
||||
this->Test_Chmod(this->file_root.get());
|
||||
this->Test_Chmod(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Chmod_Nested) {
|
||||
this->Test_Chmod(this->file_nested.get());
|
||||
this->Test_Chmod(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Utimens) {
|
||||
this->Test_Utimens(this->file_root.get());
|
||||
this->Test_Utimens(this->file_root.get(), this->file_root_node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest, Utimens_Nested) {
|
||||
this->Test_Utimens(this->file_nested.get());
|
||||
this->Test_Utimens(this->file_nested.get(), this->file_nested_node.get());
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(FsppFileTest,
|
||||
|
@ -5,12 +5,12 @@
|
||||
#include "testutils/TimestampTestUtils.h"
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppFileTest_Timestamps: public FileSystemTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
|
||||
class FsppFileTest_Timestamps: public TimestampTestUtils<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
cpputils::unique_ref<fspp::File> CreateFileWithSize(const boost::filesystem::path &path, off_t size) {
|
||||
auto file = this->CreateFile(path);
|
||||
file->truncate(size);
|
||||
assert(stat(*file).st_size == size);
|
||||
assert(this->stat(*this->Load(path)).st_size == size);
|
||||
return file;
|
||||
}
|
||||
};
|
||||
@ -21,7 +21,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, open_nomode) {
|
||||
auto operation = [&file] () {
|
||||
file->open(0);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, open_rdonly) {
|
||||
@ -29,7 +29,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, open_rdonly) {
|
||||
auto operation = [&file] () {
|
||||
file->open(O_RDONLY);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, open_wronly) {
|
||||
@ -37,7 +37,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, open_wronly) {
|
||||
auto operation = [&file] () {
|
||||
file->open(O_WRONLY);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, open_rdwr) {
|
||||
@ -45,7 +45,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, open_rdwr) {
|
||||
auto operation = [&file] () {
|
||||
file->open(O_RDWR);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAnyTimestamps});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_empty) {
|
||||
@ -53,7 +53,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_empty) {
|
||||
auto operation = [&file] () {
|
||||
file->truncate(0);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_nonempty) {
|
||||
@ -61,7 +61,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_empty_to_nonempty) {
|
||||
auto operation = [&file] () {
|
||||
file->truncate(10);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_empty) {
|
||||
@ -69,7 +69,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_empty) {
|
||||
auto operation = [&file] () {
|
||||
file->truncate(0);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_shrink) {
|
||||
@ -77,7 +77,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_shrink) {
|
||||
auto operation = [&file] () {
|
||||
file->truncate(5);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_grow) {
|
||||
@ -85,7 +85,7 @@ TYPED_TEST_P(FsppFileTest_Timestamps, truncate_nonempty_to_nonempty_grow) {
|
||||
auto operation = [&file] () {
|
||||
file->truncate(20);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*file, operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/myfile", operation, {this->ExpectDoesntUpdateAccessTimestamp, this->ExpectUpdatesModificationTimestamp, this->ExpectUpdatesMetadataTimestamp});
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(FsppFileTest_Timestamps,
|
||||
|
@ -16,28 +16,28 @@ public:
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOENT, e.getErrno());
|
||||
}
|
||||
//Old file should still exist
|
||||
//Old node should still exist
|
||||
EXPECT_NE(boost::none, this->device->Load("/oldname"));
|
||||
}
|
||||
|
||||
void Test_Error_TargetParentDirIsFile() {
|
||||
auto node = this->CreateNode("/oldname");
|
||||
this->CreateNode("/oldname");
|
||||
this->CreateFile("/somefile");
|
||||
try {
|
||||
node->rename("/somefile/newname");
|
||||
this->Load("/somefile")->rename("/somefile/newname");
|
||||
EXPECT_TRUE(false); // Expect it throws an exception
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno());
|
||||
}
|
||||
//Files should still exist
|
||||
//Nodes should still exist
|
||||
EXPECT_NE(boost::none, this->device->Load("/oldname"));
|
||||
EXPECT_NE(boost::none, this->device->Load("/somefile"));
|
||||
}
|
||||
|
||||
void Test_Error_RootDir() {
|
||||
auto root = this->LoadDir("/");
|
||||
auto rootDirNode = this->Load("/");
|
||||
try {
|
||||
root->rename("/newname");
|
||||
rootDirNode->rename("/newname");
|
||||
EXPECT_TRUE(false); // expect throws
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(EBUSY, e.getErrno());
|
||||
@ -142,10 +142,10 @@ public:
|
||||
}
|
||||
|
||||
void Test_Overwrite_Error_DirWithFile_InSameDir() {
|
||||
auto file = this->CreateFile("/oldname");
|
||||
this->CreateFile("/oldname");
|
||||
this->CreateDir("/newname");
|
||||
try {
|
||||
file->rename("/newname");
|
||||
this->Load("/oldname")->rename("/newname");
|
||||
EXPECT_TRUE(false); // expect throw
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(EISDIR, e.getErrno());
|
||||
@ -157,10 +157,10 @@ public:
|
||||
void Test_Overwrite_Error_DirWithFile_InDifferentDir() {
|
||||
this->CreateDir("/parent1");
|
||||
this->CreateDir("/parent2");
|
||||
auto file = this->CreateFile("/parent1/oldname");
|
||||
this->CreateFile("/parent1/oldname");
|
||||
this->CreateDir("/parent2/newname");
|
||||
try {
|
||||
file->rename("/parent2/newname");
|
||||
this->Load("/parent1/oldname")->rename("/parent2/newname");
|
||||
EXPECT_TRUE(false); // expect throw
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(EISDIR, e.getErrno());
|
||||
@ -170,10 +170,10 @@ public:
|
||||
}
|
||||
|
||||
void Test_Overwrite_Error_FileWithDir_InSameDir() {
|
||||
auto dir = this->CreateDir("/oldname");
|
||||
this->CreateDir("/oldname");
|
||||
this->CreateFile("/newname");
|
||||
try {
|
||||
dir->rename("/newname");
|
||||
this->Load("/oldname")->rename("/newname");
|
||||
EXPECT_TRUE(false); // expect throw
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno());
|
||||
@ -185,10 +185,10 @@ public:
|
||||
void Test_Overwrite_Error_FileWithDir_InDifferentDir() {
|
||||
this->CreateDir("/parent1");
|
||||
this->CreateDir("/parent2");
|
||||
auto dir = this->CreateDir("/parent1/oldname");
|
||||
this->CreateDir("/parent1/oldname");
|
||||
this->CreateFile("/parent2/newname");
|
||||
try {
|
||||
dir->rename("/parent2/newname");
|
||||
this->Load("/parent1/oldname")->rename("/parent2/newname");
|
||||
EXPECT_TRUE(false); // expect throw
|
||||
} catch (const fspp::fuse::FuseErrnoException &e) {
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno());
|
||||
|
@ -9,7 +9,8 @@ template<class ConcreteFileSystemTestFixture>
|
||||
class FsppNodeTest_Stat: public FsppNodeTest<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
void Test_Nlink() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
this->CreateNode("/mynode");
|
||||
auto node = this->Load("/mynode");
|
||||
this->IN_STAT(node.get(), [] (struct stat st) {
|
||||
EXPECT_EQ(1u, st.st_nlink);
|
||||
});
|
||||
@ -23,13 +24,15 @@ class FsppNodeTest_Stat_FileOnly: public FileSystemTest<ConcreteFileSystemTestFi
|
||||
TYPED_TEST_CASE_P(FsppNodeTest_Stat_FileOnly);
|
||||
|
||||
TYPED_TEST_P(FsppNodeTest_Stat_FileOnly, CreatedFileIsEmpty) {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
this->EXPECT_SIZE(0, file.get());
|
||||
this->CreateFile("/myfile");
|
||||
auto node = this->Load("/myfile");
|
||||
this->EXPECT_SIZE(0, node.get());
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FsppNodeTest_Stat_FileOnly, FileIsFile) {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
this->IN_STAT(file.get(), [] (struct stat st) {
|
||||
this->CreateFile("/myfile");
|
||||
auto node = this->Load("/myfile");
|
||||
this->IN_STAT(node.get(), [] (struct stat st) {
|
||||
EXPECT_TRUE(S_ISREG(st.st_mode));
|
||||
});
|
||||
}
|
||||
@ -41,8 +44,9 @@ class FsppNodeTest_Stat_DirOnly: public FileSystemTest<ConcreteFileSystemTestFix
|
||||
TYPED_TEST_CASE_P(FsppNodeTest_Stat_DirOnly);
|
||||
|
||||
TYPED_TEST_P(FsppNodeTest_Stat_DirOnly, DirIsDir) {
|
||||
auto file = this->CreateDir("/mydir");
|
||||
this->IN_STAT(file.get(), [] (struct stat st) {
|
||||
this->CreateDir("/mydir");
|
||||
auto node = this->Load("/mydir");
|
||||
this->IN_STAT(node.get(), [] (struct stat st) {
|
||||
EXPECT_TRUE(S_ISDIR(st.st_mode));
|
||||
});
|
||||
}
|
||||
@ -54,8 +58,9 @@ class FsppNodeTest_Stat_SymlinkOnly: public FileSystemTest<ConcreteFileSystemTes
|
||||
TYPED_TEST_CASE_P(FsppNodeTest_Stat_SymlinkOnly);
|
||||
|
||||
TYPED_TEST_P(FsppNodeTest_Stat_SymlinkOnly, SymlinkIsSymlink) {
|
||||
auto file = this->CreateSymlink("/mysymlink");
|
||||
this->IN_STAT(file.get(), [] (struct stat st) {
|
||||
this->CreateSymlink("/mysymlink");
|
||||
auto node = this->Load("/mysymlink");
|
||||
this->IN_STAT(node.get(), [] (struct stat st) {
|
||||
EXPECT_TRUE(S_ISLNK(st.st_mode));
|
||||
});
|
||||
}
|
||||
|
@ -11,16 +11,16 @@ using namespace cpputils::time;
|
||||
using std::function;
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppNodeTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
|
||||
class FsppNodeTest_Timestamps: public FsppNodeTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
|
||||
void Test_Create() {
|
||||
timespec lowerBound = now();
|
||||
auto node = this->CreateNode("/mynode");
|
||||
timespec upperBound = now();
|
||||
EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
|
||||
EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
|
||||
EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *node);
|
||||
this->EXPECT_ACCESS_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
|
||||
this->EXPECT_MODIFICATION_TIMESTAMP_BETWEEN (lowerBound, upperBound, *node);
|
||||
this->EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(lowerBound, upperBound, *node);
|
||||
}
|
||||
|
||||
void Test_Stat() {
|
||||
@ -29,26 +29,36 @@ public:
|
||||
struct stat st;
|
||||
node->stat(&st);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Chmod() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
mode_t mode = stat(*node).st_mode;
|
||||
mode_t mode = this->stat(*node).st_mode;
|
||||
auto operation = [&node, mode] () {
|
||||
node->chmod(mode);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Chown() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
uid_t uid = stat(*node).st_uid;
|
||||
gid_t gid = stat(*node).st_gid;
|
||||
uid_t uid = this->stat(*node).st_uid;
|
||||
gid_t gid = this->stat(*node).st_gid;
|
||||
auto operation = [&node, uid, gid] () {
|
||||
node->chown(uid, gid);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Access() {
|
||||
@ -56,7 +66,9 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->access(0);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Error_TargetParentDirDoesntExist() {
|
||||
@ -69,7 +81,9 @@ public:
|
||||
EXPECT_EQ(ENOENT, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Error_TargetParentDirIsFile() {
|
||||
@ -83,13 +97,15 @@ public:
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Error_RootDir() {
|
||||
// TODO Re-enable this test once the root dir stores timestamps correctly
|
||||
/*
|
||||
auto root = this->LoadDir("/");
|
||||
auto root = this->Load("/");
|
||||
auto operation = [&root] () {
|
||||
try {
|
||||
root->rename("/newname");
|
||||
@ -98,7 +114,9 @@ public:
|
||||
EXPECT_EQ(EBUSY, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mynode", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
@ -107,7 +125,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/newname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_InNested() {
|
||||
@ -116,7 +138,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir/newname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/mydir/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_RootToNested_SameName() {
|
||||
@ -125,7 +151,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir/oldname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/mydir/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_RootToNested_NewName() {
|
||||
@ -134,7 +164,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir/newname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/mydir/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_NestedToRoot_SameName() {
|
||||
@ -143,7 +177,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/oldname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_NestedToRoot_NewName() {
|
||||
@ -152,7 +190,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/newname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir/oldname", "/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_NestedToNested_SameName() {
|
||||
@ -162,7 +204,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir2/oldname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_NestedToNested_NewName() {
|
||||
@ -172,7 +218,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir2/newname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_ToItself() {
|
||||
@ -180,7 +230,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/oldname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_InSameDir() {
|
||||
@ -189,7 +243,11 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/newname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", "/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_InDifferentDir() {
|
||||
@ -200,12 +258,17 @@ public:
|
||||
auto operation = [&node] () {
|
||||
node->rename("/mydir2/newname");
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAccessTimestamp, ExpectDoesntUpdateModificationTimestamp, ExpectUpdatesMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", "/mydir2/newname", operation, {
|
||||
this->ExpectDoesntUpdateAccessTimestamp,
|
||||
this->ExpectDoesntUpdateModificationTimestamp,
|
||||
this->ExpectUpdatesMetadataTimestamp
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_Error_DirWithFile_InSameDir() {
|
||||
auto node = this->CreateFile("/oldname");
|
||||
this->CreateFile("/oldname");
|
||||
this->CreateDir("/newname");
|
||||
auto node = this->Load("/oldname");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/newname");
|
||||
@ -214,14 +277,17 @@ public:
|
||||
EXPECT_EQ(EISDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_Error_DirWithFile_InDifferentDir() {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
auto node = this->CreateFile("/mydir1/oldname");
|
||||
this->CreateFile("/mydir1/oldname");
|
||||
this->CreateDir("/mydir2/newname");
|
||||
auto node = this->Load("/mydir1/oldname");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/mydir2/newname");
|
||||
@ -230,12 +296,15 @@ public:
|
||||
EXPECT_EQ(EISDIR, e.getErrno());//Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_Error_FileWithDir_InSameDir() {
|
||||
auto node = this->CreateDir("/oldname");
|
||||
this->CreateDir("/oldname");
|
||||
this->CreateFile("/newname");
|
||||
auto node = this->Load("/oldname");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/newname");
|
||||
@ -244,14 +313,17 @@ public:
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Rename_Overwrite_Error_FileWithDir_InDifferentDir() {
|
||||
this->CreateDir("/mydir1");
|
||||
this->CreateDir("/mydir2");
|
||||
auto node = this->CreateDir("/mydir1/oldname");
|
||||
this->CreateDir("/mydir1/oldname");
|
||||
this->CreateFile("/mydir2/newname");
|
||||
auto node = this->Load("/mydir1/oldname");
|
||||
auto operation = [&node] () {
|
||||
try {
|
||||
node->rename("/mydir2/newname");
|
||||
@ -260,19 +332,23 @@ public:
|
||||
EXPECT_EQ(ENOTDIR, e.getErrno()); //Rename fails, everything is ok.
|
||||
}
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectDoesntUpdateAnyTimestamps});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mydir1/oldname", operation, {
|
||||
this->ExpectDoesntUpdateAnyTimestamps
|
||||
});
|
||||
}
|
||||
|
||||
void Test_Utimens() {
|
||||
auto node = this->CreateNode("/mynode");
|
||||
timespec atime = xSecondsAgo(100);
|
||||
timespec mtime = xSecondsAgo(200);
|
||||
timespec atime = this->xSecondsAgo(100);
|
||||
timespec mtime = this->xSecondsAgo(200);
|
||||
auto operation = [&node, atime, mtime] () {
|
||||
node->utimens(atime, mtime);
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*node, operation, {ExpectUpdatesMetadataTimestamp});
|
||||
EXPECT_EQ(atime, stat(*node).st_atim);
|
||||
EXPECT_EQ(mtime, stat(*node).st_mtim);
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,18 +5,50 @@
|
||||
#include "testutils/FileTest.h"
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppOpenFileTest: public FileTest<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);
|
||||
callback(st);
|
||||
}
|
||||
|
||||
void EXPECT_SIZE(uint64_t expectedSize, fspp::OpenFile *openFile) {
|
||||
IN_STAT(openFile, [expectedSize] (struct stat st) {
|
||||
EXPECT_EQ(expectedSize, (uint64_t)st.st_size);
|
||||
});
|
||||
|
||||
EXPECT_NUMBYTES_READABLE(expectedSize, openFile);
|
||||
}
|
||||
|
||||
void EXPECT_NUMBYTES_READABLE(uint64_t expectedSize, fspp::OpenFile *openFile) {
|
||||
cpputils::Data data(expectedSize);
|
||||
//Try to read one byte more than the expected size
|
||||
ssize_t readBytes = openFile->read(data.data(), expectedSize+1, 0);
|
||||
//and check that it only read the expected size (but also not less)
|
||||
EXPECT_EQ(expectedSize, (uint64_t)readBytes);
|
||||
}
|
||||
};
|
||||
|
||||
TYPED_TEST_CASE_P(FsppOpenFileTest);
|
||||
|
||||
TYPED_TEST_P(FsppOpenFileTest, Bla) {
|
||||
//TODO
|
||||
TYPED_TEST_P(FsppOpenFileTest, CreatedFileIsEmpty) {
|
||||
auto file = this->CreateFile("/myfile");
|
||||
auto openFile = this->LoadFile("/myfile")->open(O_RDONLY);
|
||||
this->EXPECT_SIZE(0, openFile.get());
|
||||
}
|
||||
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(FsppOpenFileTest,
|
||||
Bla
|
||||
CreatedFileIsEmpty,
|
||||
FileIsFile
|
||||
);
|
||||
|
||||
//TODO Test stat
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "testutils/TimestampTestUtils.h"
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppOpenFileTest_Timestamps: public FileSystemTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
|
||||
class FsppOpenFileTest_Timestamps: public TimestampTestUtils<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
cpputils::unique_ref<fspp::OpenFile> CreateAndOpenFile(const boost::filesystem::path &path) {
|
||||
return this->CreateFile(path)->open(O_RDWR);
|
||||
@ -14,7 +14,8 @@ public:
|
||||
auto file = this->CreateFile(path);
|
||||
file->truncate(size);
|
||||
auto openFile = file->open(O_RDWR);
|
||||
assert(stat(*openFile).st_size == size);
|
||||
assert(this->stat(*openFile).st_size == size);
|
||||
assert(this->stat(*this->Load(path)).st_size == size);
|
||||
return openFile;
|
||||
}
|
||||
};
|
||||
|
@ -38,8 +38,10 @@ TYPED_TEST_P(FsppSymlinkTest, Read_RelativePath) {
|
||||
TYPED_TEST_P(FsppSymlinkTest, Delete) {
|
||||
this->CreateSymlink("mysymlink", "/my/symlink/target");
|
||||
EXPECT_NE(boost::none, this->device->Load("/mysymlink"));
|
||||
this->LoadSymlink("/mysymlink")->remove();
|
||||
EXPECT_NE(boost::none, this->device->LoadSymlink("/mysymlink"));
|
||||
this->Load("/mysymlink")->remove();
|
||||
EXPECT_EQ(boost::none, this->device->Load("/mysymlink"));
|
||||
EXPECT_EQ(boost::none, this->device->LoadSymlink("/mysymlink"));
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(FsppSymlinkTest,
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "testutils/TimestampTestUtils.h"
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppSymlinkTest_Timestamps: public FileSystemTest<ConcreteFileSystemTestFixture>, public TimestampTestUtils {
|
||||
class FsppSymlinkTest_Timestamps: public TimestampTestUtils<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
};
|
||||
TYPED_TEST_CASE_P(FsppSymlinkTest_Timestamps);
|
||||
@ -15,7 +15,7 @@ TYPED_TEST_P(FsppSymlinkTest_Timestamps, target) {
|
||||
auto operation = [&symlink] () {
|
||||
symlink->target();
|
||||
};
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(*symlink, operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
this->EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS("/mysymlink", operation, {this->ExpectUpdatesAccessTimestamp, this->ExpectDoesntUpdateModificationTimestamp, this->ExpectDoesntUpdateMetadataTimestamp});
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(FsppSymlinkTest_Timestamps,
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <cpp-utils/pointer/unique_ref_boost_optional_gtest_workaround.h>
|
||||
|
||||
#include "../../fs_interface/Device.h"
|
||||
#include "../../fs_interface/Node.h"
|
||||
#include "../../fs_interface/Dir.h"
|
||||
#include "../../fs_interface/File.h"
|
||||
#include "../../fs_interface/Symlink.h"
|
||||
@ -35,28 +36,28 @@ public:
|
||||
|
||||
static constexpr mode_t MODE_PUBLIC = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
|
||||
|
||||
cpputils::unique_ref<fspp::Dir> LoadDir(const boost::filesystem::path &path) {
|
||||
auto loaded = device->Load(path);
|
||||
cpputils::unique_ref<fspp::Node> Load(const boost::filesystem::path &path) {
|
||||
auto loaded = device->Load(path);
|
||||
EXPECT_NE(boost::none, loaded);
|
||||
auto dir = cpputils::dynamic_pointer_move<fspp::Dir>(*loaded);
|
||||
EXPECT_NE(boost::none, dir);
|
||||
return std::move(*dir);
|
||||
return std::move(*loaded);
|
||||
}
|
||||
|
||||
cpputils::unique_ref<fspp::Dir> LoadDir(const boost::filesystem::path &path) {
|
||||
auto loaded = device->LoadDir(path);
|
||||
EXPECT_NE(boost::none, loaded);
|
||||
return std::move(*loaded);
|
||||
}
|
||||
|
||||
cpputils::unique_ref<fspp::File> LoadFile(const boost::filesystem::path &path) {
|
||||
auto loaded = device->Load(path);
|
||||
auto loaded = device->LoadFile(path);
|
||||
EXPECT_NE(boost::none, loaded);
|
||||
auto file = cpputils::dynamic_pointer_move<fspp::File>(*loaded);
|
||||
EXPECT_NE(boost::none, file);
|
||||
return std::move(*file);
|
||||
return std::move(*loaded);
|
||||
}
|
||||
|
||||
cpputils::unique_ref<fspp::Symlink> LoadSymlink(const boost::filesystem::path &path) {
|
||||
auto loaded = device->Load(path);
|
||||
auto loaded = device->LoadSymlink(path);
|
||||
EXPECT_NE(boost::none, loaded);
|
||||
auto symlink = cpputils::dynamic_pointer_move<fspp::Symlink>(*loaded);
|
||||
EXPECT_NE(boost::none, symlink);
|
||||
return std::move(*symlink);
|
||||
return std::move(*loaded);
|
||||
}
|
||||
|
||||
cpputils::unique_ref<fspp::Dir> CreateDir(const boost::filesystem::path &path) {
|
||||
@ -73,6 +74,18 @@ public:
|
||||
this->LoadDir(path.parent_path())->createSymlink(path.filename().native(), "/my/symlink/target", 0, 0);
|
||||
return this->LoadSymlink(path);
|
||||
}
|
||||
|
||||
void EXPECT_IS_FILE(const cpputils::unique_ref<fspp::Node> &node) {
|
||||
EXPECT_NE(nullptr, dynamic_cast<const fspp::File*>(node.get()));
|
||||
}
|
||||
|
||||
void EXPECT_IS_DIR(const cpputils::unique_ref<fspp::Node> &node) {
|
||||
EXPECT_NE(nullptr, dynamic_cast<const fspp::Dir*>(node.get()));
|
||||
}
|
||||
|
||||
void EXPECT_IS_SYMLINK(const cpputils::unique_ref<fspp::Node> &node) {
|
||||
EXPECT_NE(nullptr, dynamic_cast<const fspp::Symlink*>(node.get()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -13,27 +13,31 @@ public:
|
||||
FileTest(): file_root(), file_nested() {
|
||||
this->LoadDir("/")->createAndOpenFile("myfile", this->MODE_PUBLIC, 0, 0);
|
||||
file_root = cpputils::to_unique_ptr(this->LoadFile("/myfile"));
|
||||
file_root_node = cpputils::to_unique_ptr(this->Load("/myfile"));
|
||||
|
||||
this->LoadDir("/")->createDir("mydir", this->MODE_PUBLIC, 0, 0);
|
||||
this->LoadDir("/mydir")->createAndOpenFile("mynestedfile", this->MODE_PUBLIC, 0, 0);
|
||||
file_nested = cpputils::to_unique_ptr(this->LoadFile("/mydir/mynestedfile"));
|
||||
file_nested_node = cpputils::to_unique_ptr(this->Load("/mydir/mynestedfile"));
|
||||
|
||||
this->LoadDir("/")->createDir("mydir2", this->MODE_PUBLIC, 0, 0);
|
||||
}
|
||||
std::unique_ptr<fspp::File> file_root;
|
||||
std::unique_ptr<fspp::File> file_nested;
|
||||
std::unique_ptr<fspp::Node> file_root_node;
|
||||
std::unique_ptr<fspp::Node> file_nested_node;
|
||||
|
||||
//TODO IN_STAT still needed after moving it to FsppNodeTest?
|
||||
void IN_STAT(fspp::File *file, std::function<void (struct stat)> callback) {
|
||||
void IN_STAT(fspp::File *file, fspp::Node *node, std::function<void (struct stat)> callback) {
|
||||
struct stat st1, st2;
|
||||
file->stat(&st1);
|
||||
node->stat(&st1);
|
||||
callback(st1);
|
||||
file->open(O_RDONLY)->stat(&st2);
|
||||
callback(st2);
|
||||
}
|
||||
|
||||
void EXPECT_SIZE(uint64_t expectedSize, fspp::File *file) {
|
||||
IN_STAT(file, [expectedSize] (struct stat st) {
|
||||
void EXPECT_SIZE(uint64_t expectedSize, fspp::File *file, fspp::Node *node) {
|
||||
IN_STAT(file, node, [expectedSize] (struct stat st) {
|
||||
EXPECT_EQ(expectedSize, (uint64_t)st.st_size);
|
||||
});
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <boost/preprocessor/variadic/to_seq.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
|
||||
// TODO separation into File/Dir/Symlink Helpers probably not needed anymore
|
||||
|
||||
class FsppNodeTestBase {
|
||||
public:
|
||||
virtual void IN_STAT(fspp::Node *node, std::function<void (struct stat)> callback) = 0;
|
||||
@ -22,7 +24,7 @@ public:
|
||||
* See FsppNodeTest_Rename for an example.
|
||||
*/
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
class FsppNodeTest: public virtual FsppNodeTestBase, public FileSystemTest<ConcreteFileSystemTestFixture> {
|
||||
class FsppNodeTest: public virtual FsppNodeTestBase, public virtual FileSystemTest<ConcreteFileSystemTestFixture> {
|
||||
public:
|
||||
virtual cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) = 0;
|
||||
};
|
||||
@ -30,30 +32,15 @@ public:
|
||||
class FsppNodeTest_File_Helper: public virtual FsppNodeTestBase {
|
||||
public:
|
||||
void IN_STAT(fspp::Node *file, std::function<void (struct stat)> callback) override {
|
||||
struct stat st1, st2;
|
||||
file->stat(&st1);
|
||||
callback(st1);
|
||||
dynamic_cast<fspp::File &>(*file).open(O_RDONLY)->stat(&st2);
|
||||
callback(st2);
|
||||
struct stat st;
|
||||
file->stat(&st);
|
||||
callback(st);
|
||||
}
|
||||
|
||||
void EXPECT_SIZE(uint64_t expectedSize, fspp::Node *node) override {
|
||||
IN_STAT(node, [expectedSize] (struct stat st) {
|
||||
EXPECT_EQ(expectedSize, (uint64_t)st.st_size);
|
||||
});
|
||||
|
||||
fspp::File* fileNode = dynamic_cast<fspp::File*>(node);
|
||||
ASSERT(fileNode != nullptr, "Is not a file node");
|
||||
EXPECT_NUMBYTES_READABLE(expectedSize, fileNode);
|
||||
}
|
||||
|
||||
void EXPECT_NUMBYTES_READABLE(uint64_t expectedSize, fspp::File *file) {
|
||||
auto openFile = file->open(O_RDONLY);
|
||||
cpputils::Data data(expectedSize);
|
||||
//Try to read one byte more than the expected size
|
||||
ssize_t readBytes = openFile->read(data.data(), expectedSize+1, 0);
|
||||
//and check that it only read the expected size (but also not less)
|
||||
EXPECT_EQ(expectedSize, (uint64_t)readBytes);
|
||||
}
|
||||
};
|
||||
|
||||
@ -101,7 +88,8 @@ public:
|
||||
class Class##_FileNode: public Class<ConcreteFileSystemTestFixture>, public FsppNodeTest_File_Helper { \
|
||||
public: \
|
||||
cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) override { \
|
||||
return this->CreateFile(path); \
|
||||
this->CreateFile(path); \
|
||||
return this->Load(path); \
|
||||
} \
|
||||
}; \
|
||||
TYPED_TEST_CASE_P(Class##_FileNode); \
|
||||
@ -112,7 +100,8 @@ public:
|
||||
class Class##_DirNode: public Class<ConcreteFileSystemTestFixture>, public FsppNodeTest_Dir_Helper { \
|
||||
public: \
|
||||
cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) override { \
|
||||
return this->CreateDir(path); \
|
||||
this->CreateDir(path); \
|
||||
return this->Load(path); \
|
||||
} \
|
||||
}; \
|
||||
TYPED_TEST_CASE_P(Class##_DirNode); \
|
||||
@ -123,7 +112,8 @@ public:
|
||||
class Class##_SymlinkNode: public Class<ConcreteFileSystemTestFixture>, public FsppNodeTest_Symlink_Helper { \
|
||||
public: \
|
||||
cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) override { \
|
||||
return this->CreateSymlink(path); \
|
||||
this->CreateSymlink(path); \
|
||||
return this->Load(path); \
|
||||
} \
|
||||
}; \
|
||||
TYPED_TEST_CASE_P(Class##_SymlinkNode); \
|
||||
|
@ -4,100 +4,83 @@
|
||||
|
||||
#include <cpp-utils/system/time.h>
|
||||
#include <cpp-utils/system/stat.h>
|
||||
#include "FileSystemTest.h"
|
||||
#include <functional>
|
||||
|
||||
class TimestampTestUtils {
|
||||
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)>;
|
||||
|
||||
TimestampUpdateBehavior ExpectUpdatesAccessTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(statBeforeOperation);
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_atim);
|
||||
EXPECT_GE(timeAfterOperation, statAfterOperation.st_atim);
|
||||
};
|
||||
static TimestampUpdateBehavior ExpectUpdatesAccessTimestamp;
|
||||
static TimestampUpdateBehavior ExpectDoesntUpdateAccessTimestamp;
|
||||
static TimestampUpdateBehavior ExpectUpdatesModificationTimestamp;
|
||||
static TimestampUpdateBehavior ExpectDoesntUpdateModificationTimestamp;
|
||||
static TimestampUpdateBehavior ExpectUpdatesMetadataTimestamp;
|
||||
static TimestampUpdateBehavior ExpectDoesntUpdateMetadataTimestamp;
|
||||
static TimestampUpdateBehavior ExpectDoesntUpdateAnyTimestamps;
|
||||
|
||||
TimestampUpdateBehavior ExpectDoesntUpdateAccessTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
EXPECT_EQ(statBeforeOperation.st_atim, statAfterOperation.st_atim);
|
||||
};
|
||||
|
||||
TimestampUpdateBehavior ExpectUpdatesModificationTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(statBeforeOperation);
|
||||
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_mtim);
|
||||
EXPECT_GE(timeAfterOperation, statAfterOperation.st_mtim);
|
||||
};
|
||||
|
||||
TimestampUpdateBehavior ExpectDoesntUpdateModificationTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
EXPECT_EQ(statBeforeOperation.st_mtim, statAfterOperation.st_mtim);
|
||||
};
|
||||
|
||||
TimestampUpdateBehavior ExpectUpdatesMetadataTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(statBeforeOperation);
|
||||
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_ctim);
|
||||
EXPECT_GE(timeAfterOperation, statAfterOperation.st_ctim);
|
||||
};
|
||||
|
||||
TimestampUpdateBehavior ExpectDoesntUpdateMetadataTimestamp = [] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
EXPECT_EQ(statBeforeOperation.st_ctim, statAfterOperation.st_ctim);
|
||||
};
|
||||
|
||||
TimestampUpdateBehavior ExpectDoesntUpdateAnyTimestamps = [this] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
ExpectDoesntUpdateAccessTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
|
||||
ExpectDoesntUpdateModificationTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
|
||||
ExpectDoesntUpdateMetadataTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
|
||||
};
|
||||
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(std::function<struct stat()> stat, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
|
||||
struct stat oldStat = stat();
|
||||
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();
|
||||
ensureNodeTimestampsAreOld(oldStat);
|
||||
timespec timeBeforeOperation = cpputils::time::now();
|
||||
operation();
|
||||
timespec timeAfterOperation = cpputils::time::now();
|
||||
struct stat newStat = stat();
|
||||
struct stat newStat = statNew();
|
||||
for (auto behaviorCheck : behaviorChecks) {
|
||||
behaviorCheck(oldStat, newStat, timeBeforeOperation, timeAfterOperation);
|
||||
}
|
||||
}
|
||||
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const fspp::OpenFile &node, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
|
||||
return EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS([&node](){return stat(node);}, operation, behaviorChecks);
|
||||
EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(
|
||||
[this, &node](){return this->stat(node);},
|
||||
[this, &node](){return this->stat(node);},
|
||||
operation,
|
||||
behaviorChecks
|
||||
);
|
||||
}
|
||||
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const fspp::Node &node, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
|
||||
return EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS([&node](){return stat(node);}, operation, behaviorChecks);
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const boost::filesystem::path &oldPath, const boost::filesystem::path &newPath, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
|
||||
EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(
|
||||
[this, oldPath](){return this->stat(*this->Load(oldPath));},
|
||||
[this, newPath](){return this->stat(*this->Load(newPath));},
|
||||
operation,
|
||||
behaviorChecks
|
||||
);
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
void EXPECT_ACCESS_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const NodeType &node) {
|
||||
void EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(const boost::filesystem::path &path, std::function<void()> operation, std::initializer_list<TimestampUpdateBehavior> behaviorChecks) {
|
||||
EXPECT_OPERATION_UPDATES_TIMESTAMPS_AS(path, path, operation, behaviorChecks);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
void EXPECT_MODIFICATION_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const NodeType &node) {
|
||||
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);
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
void EXPECT_METADATACHANGE_TIMESTAMP_BETWEEN(timespec lowerBound, timespec upperBound, const NodeType &node) {
|
||||
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);
|
||||
}
|
||||
|
||||
template<typename NodeType>
|
||||
static struct stat stat(const NodeType &node) {
|
||||
static struct stat stat(const fspp::Node &node) {
|
||||
struct stat st;
|
||||
node.stat(&st);
|
||||
return st;
|
||||
}
|
||||
|
||||
static struct stat stat(const fspp::OpenFile &openFile) {
|
||||
struct stat st;
|
||||
openFile.stat(&st);
|
||||
return st;
|
||||
}
|
||||
|
||||
timespec xSecondsAgo(int sec) {
|
||||
timespec result = cpputils::time::now();
|
||||
result.tv_sec -= sec;
|
||||
@ -121,4 +104,62 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesAccessTimestamp =
|
||||
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(statBeforeOperation);
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_atim);
|
||||
EXPECT_GE(timeAfterOperation, statAfterOperation.st_atim);
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAccessTimestamp =
|
||||
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
EXPECT_EQ(statBeforeOperation.st_atim, statAfterOperation.st_atim);
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesModificationTimestamp =
|
||||
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(statBeforeOperation);
|
||||
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_mtim);
|
||||
EXPECT_GE(timeAfterOperation, statAfterOperation.st_mtim);
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateModificationTimestamp =
|
||||
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
EXPECT_EQ(statBeforeOperation.st_mtim, statAfterOperation.st_mtim);
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectUpdatesMetadataTimestamp =
|
||||
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(statBeforeOperation);
|
||||
EXPECT_LE(timeBeforeOperation, statAfterOperation.st_ctim);
|
||||
EXPECT_GE(timeAfterOperation, statAfterOperation.st_ctim);
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateMetadataTimestamp =
|
||||
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
UNUSED(timeBeforeOperation);
|
||||
UNUSED(timeAfterOperation);
|
||||
EXPECT_EQ(statBeforeOperation.st_ctim, statAfterOperation.st_ctim);
|
||||
};
|
||||
|
||||
template<class ConcreteFileSystemTestFixture>
|
||||
typename TimestampTestUtils<ConcreteFileSystemTestFixture>::TimestampUpdateBehavior TimestampTestUtils<ConcreteFileSystemTestFixture>::ExpectDoesntUpdateAnyTimestamps =
|
||||
[] (struct stat statBeforeOperation, struct stat statAfterOperation, timespec timeBeforeOperation, timespec timeAfterOperation) {
|
||||
ExpectDoesntUpdateAccessTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
|
||||
ExpectDoesntUpdateModificationTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
|
||||
ExpectDoesntUpdateMetadataTimestamp(statBeforeOperation, statAfterOperation, timeBeforeOperation, timeAfterOperation);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "../fuse/FuseErrnoException.h"
|
||||
#include "../fs_interface/File.h"
|
||||
#include "../fs_interface/Node.h"
|
||||
|
||||
#include <cpp-utils/logging/logging.h>
|
||||
#include <cpp-utils/pointer/unique_ref.h>
|
||||
@ -93,62 +94,31 @@ FilesystemImpl::~FilesystemImpl() {
|
||||
|
||||
unique_ref<File> FilesystemImpl::LoadFile(const bf::path &path) {
|
||||
PROFILE(_loadFileNanosec);
|
||||
auto node = _device->Load(path);
|
||||
if (node == none) {
|
||||
throw fuse::FuseErrnoException(EIO);
|
||||
}
|
||||
auto file = dynamic_pointer_move<File>(*node);
|
||||
auto file = _device->LoadFile(path);
|
||||
if (file == none) {
|
||||
throw fuse::FuseErrnoException(EISDIR);
|
||||
throw fuse::FuseErrnoException(EIO);
|
||||
}
|
||||
return std::move(*file);
|
||||
}
|
||||
|
||||
unique_ref<Dir> FilesystemImpl::LoadDir(const bf::path &path) {
|
||||
PROFILE(_loadDirNanosec);
|
||||
auto node = _device->Load(path);
|
||||
if (node == none) {
|
||||
throw fuse::FuseErrnoException(EIO);
|
||||
}
|
||||
auto dir = dynamic_pointer_move<Dir>(*node);
|
||||
auto dir = _device->LoadDir(path);
|
||||
if (dir == none) {
|
||||
throw fuse::FuseErrnoException(ENOTDIR);
|
||||
throw fuse::FuseErrnoException(EIO);
|
||||
}
|
||||
return std::move(*dir);
|
||||
}
|
||||
|
||||
unique_ref<Symlink> FilesystemImpl::LoadSymlink(const bf::path &path) {
|
||||
PROFILE(_loadSymlinkNanosec);
|
||||
auto node = _device->Load(path);
|
||||
if (node == none) {
|
||||
throw fuse::FuseErrnoException(EIO);
|
||||
}
|
||||
auto lnk = dynamic_pointer_move<Symlink>(*node);
|
||||
auto lnk = _device->LoadSymlink(path);
|
||||
if (lnk == none) {
|
||||
throw fuse::FuseErrnoException(ENOTDIR);
|
||||
throw fuse::FuseErrnoException(EIO);
|
||||
}
|
||||
return std::move(*lnk);
|
||||
}
|
||||
|
||||
unique_ref<Node> FilesystemImpl::LoadFileOrSymlink(const bf::path &path) {
|
||||
PROFILE(_loadFileOrSymlinkNanosec);
|
||||
auto node = _device->Load(path);
|
||||
if (node == none) {
|
||||
throw fuse::FuseErrnoException(EIO);
|
||||
}
|
||||
auto file = dynamic_pointer_move<File>(*node);
|
||||
if (file != none) {
|
||||
return std::move(*file);
|
||||
}
|
||||
|
||||
auto symlink = dynamic_pointer_move<Symlink>(*node);
|
||||
if (symlink != none) {
|
||||
return std::move(*symlink);
|
||||
}
|
||||
|
||||
throw fuse::FuseErrnoException(EISDIR);
|
||||
}
|
||||
|
||||
int FilesystemImpl::openFile(const bf::path &path, int flags) {
|
||||
auto file = LoadFile(path);
|
||||
return openFile(file.get(), flags);
|
||||
@ -260,17 +230,25 @@ void FilesystemImpl::mkdir(const bf::path &path, mode_t mode, uid_t uid, gid_t g
|
||||
}
|
||||
|
||||
void FilesystemImpl::rmdir(const bf::path &path) {
|
||||
//TODO Don't allow removing files/symlinks with this
|
||||
PROFILE(_rmdirNanosec);
|
||||
auto dir = LoadDir(path);
|
||||
auto node = _device->Load(path);
|
||||
if(node == none) {
|
||||
throw fuse::FuseErrnoException(ENOENT);
|
||||
}
|
||||
PROFILE(_rmdirNanosec_withoutLoading);
|
||||
dir->remove();
|
||||
(*node)->remove();
|
||||
}
|
||||
|
||||
void FilesystemImpl::unlink(const bf::path &path) {
|
||||
//TODO Don't allow removing directories with this
|
||||
PROFILE(_unlinkNanosec);
|
||||
auto node = LoadFileOrSymlink(path);
|
||||
auto node = _device->Load(path);
|
||||
if (node == none) {
|
||||
throw fuse::FuseErrnoException(ENOENT);
|
||||
}
|
||||
PROFILE(_unlinkNanosec_withoutLoading);
|
||||
node->remove();
|
||||
(*node)->remove();
|
||||
}
|
||||
|
||||
void FilesystemImpl::rename(const bf::path &from, const bf::path &to) {
|
||||
|
@ -56,8 +56,8 @@ TEST_F(CryFsTest, CreatedRootdirIsLoadableAfterClosing) {
|
||||
CryDevice dev(loadOrCreateConfig(), blockStore());
|
||||
}
|
||||
CryDevice dev(loadOrCreateConfig(), blockStore());
|
||||
auto root = dev.Load(bf::path("/"));
|
||||
dynamic_pointer_move<CryDir>(root.get()).get()->children();
|
||||
auto rootDir = dev.LoadDir(bf::path("/"));
|
||||
rootDir.value()->children();
|
||||
}
|
||||
|
||||
TEST_F(CryFsTest, LoadingFilesystemDoesntModifyConfigFile) {
|
||||
|
@ -17,11 +17,10 @@ public:
|
||||
static constexpr mode_t MODE_PUBLIC = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
|
||||
|
||||
unique_ref<CryNode> CreateFile(const bf::path &path) {
|
||||
auto _parentDir = device().Load(path.parent_path()).value();
|
||||
auto parentDir = dynamic_pointer_move<CryDir>(_parentDir).value();
|
||||
auto parentDir = device().LoadDir(path.parent_path()).value();
|
||||
parentDir->createAndOpenFile(path.filename().native(), MODE_PUBLIC, 0, 0);
|
||||
auto createdFile = device().Load(path).value();
|
||||
return dynamic_pointer_move<CryNode>(createdFile).value();
|
||||
auto file = device().Load(path).value();
|
||||
return dynamic_pointer_move<CryNode>(file).value();
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user