From 382a7b89f18fe94c5ff1c232b73b19a6a9e74960 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Sat, 15 Nov 2014 16:33:24 +0100 Subject: [PATCH] Created a CryFs implementation based on the Fuse classes --- src/CryFuse.cpp | 336 ------------------------------ src/CryFuse.h | 54 ----- src/cryfs_lib/CMakeLists.txt | 2 +- src/cryfs_lib/CryDevice.cpp | 41 ++++ src/cryfs_lib/CryDevice.h | 35 ++++ src/cryfs_lib/CryDir.cpp | 81 +++++++ src/cryfs_lib/CryDir.h | 28 +++ src/cryfs_lib/CryFile.cpp | 39 ++++ src/cryfs_lib/CryFile.h | 25 +++ src/cryfs_lib/CryNode.cpp | 46 ++++ src/cryfs_lib/CryNode.h | 53 +++++ src/cryfs_lib/CryOpenFile.cpp | 63 ++++++ src/cryfs_lib/CryOpenFile.h | 31 +++ src/fusepp/Fuse.cpp | 318 +++++++++++++++++++++++++++- src/fusepp/Fuse.h | 73 +++---- src/fusepp/FuseDevice.cpp | 31 +-- src/fusepp/FuseDevice.h | 40 ++-- src/fusepp/FuseDir.cpp | 76 +------ src/fusepp/FuseDir.h | 21 +- src/fusepp/FuseErrnoException.cpp | 3 +- src/fusepp/FuseFile.cpp | 33 +-- src/fusepp/FuseFile.h | 17 +- src/fusepp/FuseNode.cpp | 41 +--- src/fusepp/FuseNode.h | 42 +--- src/fusepp/FuseOpenFile.cpp | 56 +---- src/fusepp/FuseOpenFile.h | 23 +- src/fusepp/FuseOpenFileList.cpp | 21 +- src/fusepp/FuseOpenFileList.h | 21 +- src/fusepp/IdList.cpp | 4 - src/fusepp/utils/macros.h | 2 + src/main.cpp | 9 +- 31 files changed, 882 insertions(+), 783 deletions(-) delete mode 100644 src/CryFuse.cpp delete mode 100644 src/CryFuse.h create mode 100644 src/cryfs_lib/CryDevice.cpp create mode 100644 src/cryfs_lib/CryDevice.h create mode 100644 src/cryfs_lib/CryDir.cpp create mode 100644 src/cryfs_lib/CryDir.h create mode 100644 src/cryfs_lib/CryFile.cpp create mode 100644 src/cryfs_lib/CryFile.h create mode 100644 src/cryfs_lib/CryNode.cpp create mode 100644 src/cryfs_lib/CryNode.h create mode 100644 src/cryfs_lib/CryOpenFile.cpp create mode 100644 src/cryfs_lib/CryOpenFile.h diff --git a/src/CryFuse.cpp b/src/CryFuse.cpp deleted file mode 100644 index b89d1223..00000000 --- a/src/CryFuse.cpp +++ /dev/null @@ -1,336 +0,0 @@ -#include "CryFuse.h" - -#include -#include -#include -#include -#include -#include - - -#define UNUSED(expr) (void)(expr) - -using fusepp::path; - -namespace fusepp { - -CryFuse::CryFuse(FuseDevice *device) - :_device(device) { -} - -int CryFuse::getattr(const path &path, struct stat *stbuf) { - //printf("getattr(%s, _, _)\n", path.c_str()); - try { - _device->lstat(path, stbuf); - return 0; - } catch(fusepp::FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::fgetattr(const path &path, struct stat *stbuf, fuse_file_info *fileinfo) { - //printf("fgetattr(%s, _, _)\n", path.c_str()); - - // On FreeBSD, trying to do anything with the mountpoint ends up - // opening it, and then using the FD for an fgetattr. So in the - // special case of a path of "/", I need to do a getattr on the - // underlying root directory instead of doing the fgetattr(). - // TODO Check if necessary - if (path.native() == "/") { - return getattr(path, stbuf); - } - - try { - _device->fstat(fileinfo->fh, stbuf); - return 0; - } catch(fusepp::FuseErrnoException &e) { - return -e.getErrno(); - } -} - -//TODO -int CryFuse::readlink(const path &path, char *buf, size_t size) { - //printf("readlink(%s, _, %zu)\n", path.c_str(), size); - auto real_path = _device->RootDir() / path; - //size-1, because the fuse readlink() function includes the null terminating byte in the buffer size, - //but the posix version does not and also doesn't append one. - int real_size = ::readlink(real_path.c_str(), buf, size-1); - if (real_size < 0) { - return -errno; - } - //Terminate the string - buf[real_size] = '\0'; - - return 0; -} - -int CryFuse::mknod(const path &path, mode_t mode, dev_t rdev) { - UNUSED(rdev); - UNUSED(mode); - UNUSED(path); - printf("Called non-implemented mknod(%s, %d, _)\n", path.c_str(), mode); - return ENOSYS; -} - -int CryFuse::mkdir(const path &path, mode_t mode) { - //printf("mkdir(%s, %d)\n", path.c_str(), mode); - try { - _device->mkdir(path, mode); - return 0; - } catch(fusepp::FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::unlink(const path &path) { - //printf("unlink(%s)\n", path.c_str()); - try { - _device->unlink(path); - return 0; - } catch(fusepp::FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::rmdir(const path &path) { - try { - _device->rmdir(path); - return 0; - } catch(fusepp::FuseErrnoException &e) { - return -e.getErrno(); - } -} - -//TODO -int CryFuse::symlink(const path &from, const path &to) { - printf("NOT IMPLEMENTED: symlink(%s, %s)\n", from.c_str(), to.c_str()); - //auto real_from = _device->RootDir() / from; - //auto real_to = _device->RootDir() / to; - //int retstat = ::symlink(real_from.c_str(), real_to.c_str()); - //return errcode_map(retstat); - return ENOSYS; -} - -int CryFuse::rename(const path &from, const path &to) { - //printf("rename(%s, %s)\n", from.c_str(), to.c_str()); - try { - _device->rename(from, to); - return 0; - } catch(fusepp::FuseErrnoException &e) { - return -e.getErrno(); - } -} - -//TODO -int CryFuse::link(const path &from, const path &to) { - printf("NOT IMPLEMENTED: link(%s, %s)\n", from.c_str(), to.c_str()); - //auto real_from = _device->RootDir() / from; - //auto real_to = _device->RootDir() / to; - //int retstat = ::link(real_from.c_str(), real_to.c_str()); - //return errcode_map(retstat); - return ENOSYS; -} - -//TODO -int CryFuse::chmod(const path &path, mode_t mode) { - printf("NOT IMPLEMENTED: chmod(%s, %d)\n", path.c_str(), mode); - //auto real_path = _device->RootDir() / path; - //int retstat = ::chmod(real_path.c_str(), mode); - //return errcode_map(retstat); - return ENOSYS; -} - -//TODO -int CryFuse::chown(const path &path, uid_t uid, gid_t gid) { - printf("NOT IMPLEMENTED: chown(%s, %d, %d)\n", path.c_str(), uid, gid); - //auto real_path = _device->RootDir() / path; - //int retstat = ::chown(real_path.c_str(), uid, gid); - //return errcode_map(retstat); - return ENOSYS; -} - -int CryFuse::truncate(const path &path, off_t size) { - //printf("truncate(%s, %zu)\n", path.c_str(), size); - try { - _device->truncate(path, size); - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::ftruncate(const path &path, off_t size, fuse_file_info *fileinfo) { - //printf("ftruncate(%s, %zu, _)\n", path.c_str(), size); - UNUSED(path); - try { - _device->ftruncate(fileinfo->fh, size); - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -//TODO -int CryFuse::utimens(const path &path, const timespec times[2]) { - //printf("utimens(%s, _)\n", path.c_str()); - try { - _device->utimens(path, times); - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::open(const path &path, fuse_file_info *fileinfo) { - //printf("open(%s, _)\n", path.c_str()); - try { - fileinfo->fh = _device->openFile(path, fileinfo->flags); - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::release(const path &path, fuse_file_info *fileinfo) { - //printf("release(%s, _)\n", path.c_str()); - UNUSED(path); - try { - _device->closeFile(fileinfo->fh); - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::read(const path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) { - //printf("read(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset); - UNUSED(path); - try { - //printf("Reading from file %d\n", fileinfo->fh); - //fflush(stdout); - return _device->read(fileinfo->fh, buf, size, offset); - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::write(const path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) { - //printf("write(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset); - UNUSED(path); - try { - _device->write(fileinfo->fh, buf, size, offset); - return size; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -//TODO -int CryFuse::statfs(const path &path, struct statvfs *fsstat) { - //printf("statfs(%s, _)\n", path.c_str()); - try { - _device->statfs(path, fsstat); - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -//TODO -int CryFuse::flush(const path &path, fuse_file_info *fileinfo) { - //printf("Called non-implemented flush(%s, _)\n", path.c_str()); - UNUSED(path); - UNUSED(fileinfo); - return 0; -} - -int CryFuse::fsync(const path &path, int datasync, fuse_file_info *fileinfo) { - //printf("fsync(%s, %d, _)\n", path.c_str(), datasync); - UNUSED(path); - try { - if (datasync) { - _device->fdatasync(fileinfo->fh); - } else { - _device->fsync(fileinfo->fh); - } - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::opendir(const path &path, fuse_file_info *fileinfo) { - UNUSED(path); - UNUSED(fileinfo); - //printf("opendir(%s, _)\n", path.c_str()); - //We don't need opendir, because readdir works directly on the path - return 0; -} - -int CryFuse::readdir(const path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) { - UNUSED(fileinfo); - //printf("readdir(%s, _, _, %zu, _)\n", path.c_str(), offset); - UNUSED(offset); - try { - auto entries = _device->readDir(path); - for (const auto &entry : *entries) { - //We could pass file metadata to filler() in its third parameter, - //but it doesn't help performance since fuse seems to ignore it. - //It does getattr() calls on all entries nevertheless. - if (filler(buf, entry.c_str(), nullptr, 0) != 0) { - return -ENOMEM; - } - } - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::releasedir(const path &path, fuse_file_info *fileinfo) { - UNUSED(path); - UNUSED(fileinfo); - //printf("releasedir(%s, _)\n", path.c_str()); - //We don't need releasedir, because readdir works directly on the path - return 0; -} - -//TODO -int CryFuse::fsyncdir(const path &path, int datasync, fuse_file_info *fileinfo) { - UNUSED(fileinfo); - UNUSED(datasync); - UNUSED(path); - //printf("Called non-implemented fsyncdir(%s, %d, _)\n", path.c_str(), datasync); - return 0; -} - -void CryFuse::init(fuse_conn_info *conn) { - UNUSED(conn); - //printf("init()\n"); -} - -void CryFuse::destroy() { - //printf("destroy()\n"); -} - -int CryFuse::access(const path &path, int mask) { - //printf("access(%s, %d)\n", path.c_str(), mask); - try { - _device->access(path, mask); - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -int CryFuse::create(const path &path, mode_t mode, fuse_file_info *fileinfo) { - //printf("create(%s, %d, _)\n", path.c_str(), mode); - try { - fileinfo->fh = _device->createAndOpenFile(path, mode); - return 0; - } catch (FuseErrnoException &e) { - return -e.getErrno(); - } -} - -} /* namespace cryfs */ diff --git a/src/CryFuse.h b/src/CryFuse.h deleted file mode 100644 index 6b651844..00000000 --- a/src/CryFuse.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once -#ifndef CRYFS_LIB_CRYFUSE_H_ -#define CRYFS_LIB_CRYFUSE_H_ - -#include "fusepp/Fuse.h" -#include "fusepp/FuseDevice.h" -#include "fusepp/utils/macros.h" - -namespace fusepp { - -class CryFuse: public fusepp::Fuse { -public: - CryFuse(FuseDevice *device); - - int getattr(const fusepp::path &path, struct stat *stbuf) override; - int fgetattr(const fusepp::path &path, struct stat *stbuf, fuse_file_info *fileinfo) override; - int readlink(const fusepp::path &path, char *buf, size_t size) override; - int mknod(const fusepp::path &path, mode_t mode, dev_t rdev) override; - int mkdir(const fusepp::path &path, mode_t mode) override; - int unlink(const fusepp::path &path) override; - int rmdir(const fusepp::path &path) override; - int symlink(const fusepp::path &from, const fusepp::path &to) override; - int rename(const fusepp::path &from, const fusepp::path &to) override; - int link(const fusepp::path &from, const fusepp::path &to) override; - int chmod(const fusepp::path &path, mode_t mode) override; - int chown(const fusepp::path &path, uid_t uid, gid_t gid) override; - int truncate(const fusepp::path &path, off_t size) override; - int ftruncate(const fusepp::path &path, off_t size, fuse_file_info *fileinfo) override; - int utimens(const fusepp::path &path, const timespec times[2]) override; - int open(const fusepp::path &path, fuse_file_info *fileinfo) override; - int release(const fusepp::path &path, fuse_file_info *fileinfo) override; - int read(const fusepp::path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) override; - int write(const fusepp::path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) override; - int statfs(const fusepp::path &path, struct statvfs *fsstat) override; - int flush(const fusepp::path &path, fuse_file_info *fileinfo) override; - int fsync(const fusepp::path &path, int flags, fuse_file_info *fileinfo) override; - int opendir(const fusepp::path &path, fuse_file_info *fileinfo) override; - int readdir(const fusepp::path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) override; - int releasedir(const fusepp::path &path, fuse_file_info *fileinfo) override; - int fsyncdir(const fusepp::path &path, int datasync, fuse_file_info *fileinfo) override; - void init(fuse_conn_info *conn) override; - void destroy() override; - int access(const fusepp::path &path, int mask) override; - int create(const fusepp::path &path, mode_t mode, fuse_file_info *fileinfo) override; - -private: - FuseDevice *_device; - - DISALLOW_COPY_AND_ASSIGN(CryFuse); -}; - -} /* namespace cryfs */ - -#endif /* CRYFS_LIB_CRYFUSE_H_ */ diff --git a/src/cryfs_lib/CMakeLists.txt b/src/cryfs_lib/CMakeLists.txt index 89092fb8..0c07f1ad 100644 --- a/src/cryfs_lib/CMakeLists.txt +++ b/src/cryfs_lib/CMakeLists.txt @@ -1,3 +1,3 @@ -add_library(cryfs_lib ) +add_library(cryfs_lib CryDevice.cpp CryDir.cpp CryFile.cpp CryNode.cpp CryOpenFile.cpp) target_link_libraries(cryfs_lib fusepp) diff --git a/src/cryfs_lib/CryDevice.cpp b/src/cryfs_lib/CryDevice.cpp new file mode 100644 index 00000000..f66f2cf2 --- /dev/null +++ b/src/cryfs_lib/CryDevice.cpp @@ -0,0 +1,41 @@ +#include "CryDevice.h" + +#include "CryDir.h" +#include "CryFile.h" + +#include "fusepp/FuseErrnoException.h" + +using std::unique_ptr; + +using std::unique_ptr; +using std::make_unique; + +//TODO Get rid of this in favor of exception hierarchy +using fusepp::CHECK_RETVAL; + +namespace cryfs { + +CryDevice::CryDevice(const bf::path &root_path): _root_path(root_path) { +} + +CryDevice::~CryDevice() { +} + +unique_ptr CryDevice::Load(const bf::path &path) { + auto real_path = RootDir() / path; + if(bf::is_directory(real_path)) { + return make_unique(this, path); + } else if(bf::is_regular_file(real_path)) { + return make_unique(this, path); + } + + throw fusepp::FuseErrnoException(ENOENT); +} + +void CryDevice::statfs(const bf::path &path, struct statvfs *fsstat) { + auto real_path = RootDir() / path; + int retval = ::statvfs(real_path.c_str(), fsstat); + CHECK_RETVAL(retval); +} + +} /* namespace cryfs */ diff --git a/src/cryfs_lib/CryDevice.h b/src/cryfs_lib/CryDevice.h new file mode 100644 index 00000000..b3de1843 --- /dev/null +++ b/src/cryfs_lib/CryDevice.h @@ -0,0 +1,35 @@ +#pragma once +#ifndef CRYFS_LIB_CRYDEVICE_H_ +#define CRYFS_LIB_CRYDEVICE_H_ + +#include + +#include "fusepp/FuseDevice.h" + +namespace cryfs { + +namespace bf = boost::filesystem; + +class CryDevice: public fusepp::FuseDevice { +public: + CryDevice(const bf::path &rootdir); + virtual ~CryDevice(); + + void statfs(const boost::filesystem::path &path, struct statvfs *fsstat) override; + + const bf::path &RootDir() const; +private: + std::unique_ptr Load(const bf::path &path) override; + + const bf::path _root_path; + + DISALLOW_COPY_AND_ASSIGN(CryDevice); +}; + +inline const bf::path &CryDevice::RootDir() const { + return _root_path; +} + +} /* namespace cryfs */ + +#endif /* CRYFS_LIB_CRYDEVICE_H_ */ diff --git a/src/cryfs_lib/CryDir.cpp b/src/cryfs_lib/CryDir.cpp new file mode 100644 index 00000000..f72f2836 --- /dev/null +++ b/src/cryfs_lib/CryDir.cpp @@ -0,0 +1,81 @@ +#include "CryDir.h" + +#include +#include +#include +#include + +#include "fusepp/FuseErrnoException.h" +#include "CryDevice.h" +#include "CryFile.h" + +//TODO Get rid of this in favor of exception hierarchy +using fusepp::CHECK_RETVAL; + +namespace bf = boost::filesystem; + +using std::unique_ptr; +using std::make_unique; +using std::string; +using std::vector; + +namespace cryfs { + +CryDir::CryDir(CryDevice *device, const bf::path &path) + :CryNode(device, path) { + assert(bf::is_directory(base_path())); +} + +CryDir::~CryDir() { +} + +unique_ptr CryDir::createFile(const string &name, mode_t mode) { + auto file_path = base_path() / name; + //Create file + int fd = ::creat(file_path.c_str(), mode); + CHECK_RETVAL(fd); + ::close(fd); + return make_unique(device(), path() / name); +} + +unique_ptr CryDir::createDir(const string &name, mode_t mode) { + auto dir_path = base_path() / name; + //Create dir + int retval = ::mkdir(dir_path.c_str(), mode); + CHECK_RETVAL(retval); + return make_unique(device(), path() / name); +} + +void CryDir::rmdir() { + int retval = ::rmdir(base_path().c_str()); + CHECK_RETVAL(retval); +} + +unique_ptr> CryDir::children() const { + DIR *dir = ::opendir(base_path().c_str()); + if (dir == nullptr) { + throw fusepp::FuseErrnoException(errno); + } + + // Set errno=0 so we can detect whether it changed later + errno = 0; + + auto result = make_unique>(); + + struct dirent *entry = ::readdir(dir); + while(entry != nullptr) { + result->push_back(entry->d_name); + entry = ::readdir(dir); + } + //On error, ::readdir returns nullptr and sets errno. + if (errno != 0) { + int readdir_errno = errno; + ::closedir(dir); + throw fusepp::FuseErrnoException(readdir_errno); + } + int retval = ::closedir(dir); + CHECK_RETVAL(retval); + return result; +} + +} /* namespace cryfs */ diff --git a/src/cryfs_lib/CryDir.h b/src/cryfs_lib/CryDir.h new file mode 100644 index 00000000..5653abbc --- /dev/null +++ b/src/cryfs_lib/CryDir.h @@ -0,0 +1,28 @@ +#pragma once +#ifndef CRYFS_LIB_CRYDIR_H_ +#define CRYFS_LIB_CRYDIR_H_ + +#include "fusepp/FuseDir.h" +#include "CryNode.h" + +namespace cryfs { + +class CryDir: public fusepp::FuseDir, CryNode { +public: + CryDir(CryDevice *device, const bf::path &path); + virtual ~CryDir(); + + //TODO return type variance to CryFile/CryDir? + std::unique_ptr createFile(const std::string &name, mode_t mode) override; + std::unique_ptr createDir(const std::string &name, mode_t mode) override; + void rmdir() override; + + std::unique_ptr> children() const override; + +private: + DISALLOW_COPY_AND_ASSIGN(CryDir); +}; + +} /* namespace cryfs */ + +#endif diff --git a/src/cryfs_lib/CryFile.cpp b/src/cryfs_lib/CryFile.cpp new file mode 100644 index 00000000..51a1bd5b --- /dev/null +++ b/src/cryfs_lib/CryFile.cpp @@ -0,0 +1,39 @@ +#include "CryFile.h" + +#include "CryDevice.h" +#include "CryOpenFile.h" +#include "fusepp/FuseErrnoException.h" + +namespace bf = boost::filesystem; + +//TODO Get rid of this in favor of exception hierarchy +using fusepp::CHECK_RETVAL; + +using std::unique_ptr; +using std::make_unique; + +namespace cryfs { + +CryFile::CryFile(CryDevice *device, const bf::path &path) + :CryNode(device, path) { + assert(bf::is_regular_file(base_path())); +} + +CryFile::~CryFile() { +} + +unique_ptr CryFile::open(int flags) const { + return make_unique(device(), path(), flags); +} + +void CryFile::truncate(off_t size) const { + int retval = ::truncate(base_path().c_str(), size); + CHECK_RETVAL(retval); +} + +void CryFile::unlink() { + int retval = ::unlink(base_path().c_str()); + CHECK_RETVAL(retval); +} + +} /* namespace cryfs */ diff --git a/src/cryfs_lib/CryFile.h b/src/cryfs_lib/CryFile.h new file mode 100644 index 00000000..cc872640 --- /dev/null +++ b/src/cryfs_lib/CryFile.h @@ -0,0 +1,25 @@ +#pragma once +#ifndef CRYFS_LIB_CRYFILE_H_ +#define CRYFS_LIB_CRYFILE_H_ + +#include "CryNode.h" +#include "fusepp/FuseFile.h" + +namespace cryfs { + +class CryFile: public fusepp::FuseFile, CryNode { +public: + CryFile(CryDevice *device, const boost::filesystem::path &path); + virtual ~CryFile(); + + std::unique_ptr open(int flags) const override; + void truncate(off_t size) const override; + void unlink() override; + +private: + DISALLOW_COPY_AND_ASSIGN(CryFile); +}; + +} /* namespace cryfs */ + +#endif diff --git a/src/cryfs_lib/CryNode.cpp b/src/cryfs_lib/CryNode.cpp new file mode 100644 index 00000000..855e5cba --- /dev/null +++ b/src/cryfs_lib/CryNode.cpp @@ -0,0 +1,46 @@ +#include "CryNode.h" + +#include + +#include "CryDevice.h" +#include "fusepp/FuseErrnoException.h" + +namespace bf = boost::filesystem; + +//TODO Get rid of this in favor of an exception hierarchy +using fusepp::CHECK_RETVAL; + +namespace cryfs { + +CryNode::CryNode(CryDevice *device, const bf::path &path) + :_device(device), _path(path) { +} + +CryNode::~CryNode() { +} + +void CryNode::stat(struct ::stat *result) const { + int retval = ::lstat(base_path().c_str(), result); + CHECK_RETVAL(retval); +} + +void CryNode::access(int mask) const { + int retval = ::access(base_path().c_str(), mask); + CHECK_RETVAL(retval); +} + +void CryNode::rename(const bf::path &to) { + auto new_base_path = device()->RootDir() / to; + int retval = ::rename(base_path().c_str(), new_base_path.c_str()); + CHECK_RETVAL(retval); + _path = to; +} + +void CryNode::utimens(const timespec times[2]) { + struct timeval timevals[2]; + TIMESPEC_TO_TIMEVAL(&timevals[0], ×[0]); + TIMESPEC_TO_TIMEVAL(&timevals[1], ×[1]); + ::lutimes(base_path().c_str(), timevals); +} + +} /* namespace cryfs */ diff --git a/src/cryfs_lib/CryNode.h b/src/cryfs_lib/CryNode.h new file mode 100644 index 00000000..38c3b709 --- /dev/null +++ b/src/cryfs_lib/CryNode.h @@ -0,0 +1,53 @@ +#pragma once +#ifndef CRYFS_LIB_CRYNODE_H_ +#define CRYFS_LIB_CRYNODE_H_ + +#include "fusepp/FuseNode.h" +#include "fusepp/utils/macros.h" + +#include "CryDevice.h" + +namespace cryfs { + +class CryNode: public virtual fusepp::FuseNode { +public: + CryNode(CryDevice *device, const boost::filesystem::path &path); + virtual ~CryNode(); + + void stat(struct ::stat *result) const override; + void access(int mask) const override; + void rename(const boost::filesystem::path &to) override; + void utimens(const timespec times[2]) override; + +protected: + boost::filesystem::path base_path() const; + const boost::filesystem::path &path() const; + CryDevice *device(); + const CryDevice *device() const; + +private: + CryDevice *const _device; + boost::filesystem::path _path; + + DISALLOW_COPY_AND_ASSIGN(CryNode); +}; + +inline boost::filesystem::path CryNode::base_path() const { + return _device->RootDir() / _path; +} + +inline const boost::filesystem::path &CryNode::path() const { + return _path; +} + +inline CryDevice *CryNode::device() { + return const_cast(const_cast(this)->device()); +} + +inline const CryDevice *CryNode::device() const { + return _device; +} + +} /* namespace cryfs */ + +#endif diff --git a/src/cryfs_lib/CryOpenFile.cpp b/src/cryfs_lib/CryOpenFile.cpp new file mode 100644 index 00000000..11c8eaa9 --- /dev/null +++ b/src/cryfs_lib/CryOpenFile.cpp @@ -0,0 +1,63 @@ +#include "CryOpenFile.h" + +#include +#include + +#include "CryDevice.h" +#include "fusepp/FuseErrnoException.h" + +namespace bf = boost::filesystem; + +//TODO Get rid of this in favor of a exception hierarchy +using fusepp::CHECK_RETVAL; + +namespace cryfs { + +CryOpenFile::CryOpenFile(const CryDevice *device, const bf::path &path, int flags) + :_descriptor(::open((device->RootDir() / path).c_str(), flags)) { + CHECK_RETVAL(_descriptor); +} + +CryOpenFile::~CryOpenFile() { + int retval = close(_descriptor); + CHECK_RETVAL(retval); +} + +void CryOpenFile::stat(struct ::stat *result) const { + int retval = ::fstat(_descriptor, result); + CHECK_RETVAL(retval); +} + +void CryOpenFile::truncate(off_t size) const { + int retval = ::ftruncate(_descriptor, size); + CHECK_RETVAL(retval); +} + +int CryOpenFile::read(void *buf, size_t count, off_t offset) { + //printf("Reading from real descriptor %d (%d, %d)\n", _descriptor, offset, count); + //fflush(stdout); + int retval = ::pread(_descriptor, buf, count, offset); + CHECK_RETVAL(retval); + //printf("retval: %d, count: %d\n", retval, count); + //fflush(stdout); + assert(static_cast(retval) <= count); + return retval; +} + +void CryOpenFile::write(const void *buf, size_t count, off_t offset) { + int retval = ::pwrite(_descriptor, buf, count, offset); + CHECK_RETVAL(retval); + assert(static_cast(retval) == count); +} + +void CryOpenFile::fsync() { + int retval = ::fsync(_descriptor); + CHECK_RETVAL(retval); +} + +void CryOpenFile::fdatasync() { + int retval = ::fdatasync(_descriptor); + CHECK_RETVAL(retval); +} + +} /* namespace cryfs */ diff --git a/src/cryfs_lib/CryOpenFile.h b/src/cryfs_lib/CryOpenFile.h new file mode 100644 index 00000000..e2a784b4 --- /dev/null +++ b/src/cryfs_lib/CryOpenFile.h @@ -0,0 +1,31 @@ +#pragma once +#ifndef CRYFS_LIB_CRYOPENFILE_H_ +#define CRYFS_LIB_CRYOPENFILE_H_ + +#include "fusepp/FuseOpenFile.h" +#include "fusepp/utils/macros.h" + +namespace cryfs { +class CryDevice; + +class CryOpenFile: public fusepp::FuseOpenFile { +public: + CryOpenFile(const CryDevice *device, const boost::filesystem::path &path, int flags); + virtual ~CryOpenFile(); + + void stat(struct ::stat *result) const override; + void truncate(off_t size) const override; + int read(void *buf, size_t count, off_t offset) override; + void write(const void *buf, size_t count, off_t offset) override; + void fsync() override; + void fdatasync() override; + +private: + int _descriptor; + + DISALLOW_COPY_AND_ASSIGN(CryOpenFile); +}; + +} /* namespace cryfs */ + +#endif diff --git a/src/fusepp/Fuse.cpp b/src/fusepp/Fuse.cpp index e071be28..e214d96a 100644 --- a/src/fusepp/Fuse.cpp +++ b/src/fusepp/Fuse.cpp @@ -1,7 +1,10 @@ -#include "../fusepp/Fuse.h" +#include "Fuse.h" #include #include +#include "FuseDevice.h" +#include "FuseErrnoException.h" + using std::unique_ptr; using std::make_unique; using std::string; @@ -11,7 +14,6 @@ namespace bf = boost::filesystem; using namespace fusepp; #define FUSE_OBJ ((Fuse *) fuse_get_context()->private_data) -#define UNUSED(obj) (void)obj namespace { int fusepp_getattr(const char *path, struct stat *stbuf) { @@ -203,6 +205,318 @@ fuse_operations *operations() { Fuse::~Fuse() { } +Fuse::Fuse(FuseDevice *device) + :_device(device) { +} + void Fuse::run(int argc, char **argv) { fuse_main(argc, argv, operations(), (void*)this); } + +int Fuse::getattr(const bf::path &path, struct stat *stbuf) { + //printf("getattr(%s, _, _)\n", path.c_str()); + try { + _device->lstat(path, stbuf); + return 0; + } catch(fusepp::FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::fgetattr(const bf::path &path, struct stat *stbuf, fuse_file_info *fileinfo) { + //printf("fgetattr(%s, _, _)\n", path.c_str()); + + // On FreeBSD, trying to do anything with the mountpoint ends up + // opening it, and then using the FD for an fgetattr. So in the + // special case of a path of "/", I need to do a getattr on the + // underlying root directory instead of doing the fgetattr(). + // TODO Check if necessary + if (path.native() == "/") { + return getattr(path, stbuf); + } + + try { + _device->fstat(fileinfo->fh, stbuf); + return 0; + } catch(fusepp::FuseErrnoException &e) { + return -e.getErrno(); + } +} + +//TODO +int Fuse::readlink(const bf::path &path, char *buf, size_t size) { + UNUSED(path); + UNUSED(buf); + UNUSED(size); + printf("Called non-implemented readlink(%s, _, %zu)\n", path.c_str(), size); + return ENOSYS; +} + +int Fuse::mknod(const bf::path &path, mode_t mode, dev_t rdev) { + UNUSED(rdev); + UNUSED(mode); + UNUSED(path); + printf("Called non-implemented mknod(%s, %d, _)\n", path.c_str(), mode); + return ENOSYS; +} + +int Fuse::mkdir(const bf::path &path, mode_t mode) { + //printf("mkdir(%s, %d)\n", path.c_str(), mode); + try { + _device->mkdir(path, mode); + return 0; + } catch(fusepp::FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::unlink(const bf::path &path) { + //printf("unlink(%s)\n", path.c_str()); + try { + _device->unlink(path); + return 0; + } catch(fusepp::FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::rmdir(const bf::path &path) { + try { + _device->rmdir(path); + return 0; + } catch(fusepp::FuseErrnoException &e) { + return -e.getErrno(); + } +} + +//TODO +int Fuse::symlink(const bf::path &from, const bf::path &to) { + printf("NOT IMPLEMENTED: symlink(%s, %s)\n", from.c_str(), to.c_str()); + //auto real_from = _device->RootDir() / from; + //auto real_to = _device->RootDir() / to; + //int retstat = ::symlink(real_from.c_str(), real_to.c_str()); + //return errcode_map(retstat); + return ENOSYS; +} + +int Fuse::rename(const bf::path &from, const bf::path &to) { + //printf("rename(%s, %s)\n", from.c_str(), to.c_str()); + try { + _device->rename(from, to); + return 0; + } catch(fusepp::FuseErrnoException &e) { + return -e.getErrno(); + } +} + +//TODO +int Fuse::link(const bf::path &from, const bf::path &to) { + printf("NOT IMPLEMENTED: link(%s, %s)\n", from.c_str(), to.c_str()); + //auto real_from = _device->RootDir() / from; + //auto real_to = _device->RootDir() / to; + //int retstat = ::link(real_from.c_str(), real_to.c_str()); + //return errcode_map(retstat); + return ENOSYS; +} + +//TODO +int Fuse::chmod(const bf::path &path, mode_t mode) { + printf("NOT IMPLEMENTED: chmod(%s, %d)\n", path.c_str(), mode); + //auto real_path = _device->RootDir() / path; + //int retstat = ::chmod(real_path.c_str(), mode); + //return errcode_map(retstat); + return ENOSYS; +} + +//TODO +int Fuse::chown(const bf::path &path, uid_t uid, gid_t gid) { + printf("NOT IMPLEMENTED: chown(%s, %d, %d)\n", path.c_str(), uid, gid); + //auto real_path = _device->RootDir() / path; + //int retstat = ::chown(real_path.c_str(), uid, gid); + //return errcode_map(retstat); + return ENOSYS; +} + +int Fuse::truncate(const bf::path &path, off_t size) { + //printf("truncate(%s, %zu)\n", path.c_str(), size); + try { + _device->truncate(path, size); + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::ftruncate(const bf::path &path, off_t size, fuse_file_info *fileinfo) { + //printf("ftruncate(%s, %zu, _)\n", path.c_str(), size); + UNUSED(path); + try { + _device->ftruncate(fileinfo->fh, size); + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +//TODO +int Fuse::utimens(const bf::path &path, const timespec times[2]) { + //printf("utimens(%s, _)\n", path.c_str()); + try { + _device->utimens(path, times); + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::open(const bf::path &path, fuse_file_info *fileinfo) { + //printf("open(%s, _)\n", path.c_str()); + try { + fileinfo->fh = _device->openFile(path, fileinfo->flags); + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::release(const bf::path &path, fuse_file_info *fileinfo) { + //printf("release(%s, _)\n", path.c_str()); + UNUSED(path); + try { + _device->closeFile(fileinfo->fh); + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::read(const bf::path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) { + //printf("read(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset); + UNUSED(path); + try { + //printf("Reading from file %d\n", fileinfo->fh); + //fflush(stdout); + return _device->read(fileinfo->fh, buf, size, offset); + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::write(const bf::path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) { + //printf("write(%s, _, %zu, %zu, _)\n", path.c_str(), size, offset); + UNUSED(path); + try { + _device->write(fileinfo->fh, buf, size, offset); + return size; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +//TODO +int Fuse::statfs(const bf::path &path, struct statvfs *fsstat) { + //printf("statfs(%s, _)\n", path.c_str()); + try { + _device->statfs(path, fsstat); + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +//TODO +int Fuse::flush(const bf::path &path, fuse_file_info *fileinfo) { + //printf("Called non-implemented flush(%s, _)\n", path.c_str()); + UNUSED(path); + UNUSED(fileinfo); + return 0; +} + +int Fuse::fsync(const bf::path &path, int datasync, fuse_file_info *fileinfo) { + //printf("fsync(%s, %d, _)\n", path.c_str(), datasync); + UNUSED(path); + try { + if (datasync) { + _device->fdatasync(fileinfo->fh); + } else { + _device->fsync(fileinfo->fh); + } + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::opendir(const bf::path &path, fuse_file_info *fileinfo) { + UNUSED(path); + UNUSED(fileinfo); + //printf("opendir(%s, _)\n", path.c_str()); + //We don't need opendir, because readdir works directly on the path + return 0; +} + +int Fuse::readdir(const bf::path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) { + UNUSED(fileinfo); + //printf("readdir(%s, _, _, %zu, _)\n", path.c_str(), offset); + UNUSED(offset); + try { + auto entries = _device->readDir(path); + for (const auto &entry : *entries) { + //We could pass file metadata to filler() in its third parameter, + //but it doesn't help performance since fuse seems to ignore it. + //It does getattr() calls on all entries nevertheless. + if (filler(buf, entry.c_str(), nullptr, 0) != 0) { + return -ENOMEM; + } + } + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::releasedir(const bf::path &path, fuse_file_info *fileinfo) { + UNUSED(path); + UNUSED(fileinfo); + //printf("releasedir(%s, _)\n", path.c_str()); + //We don't need releasedir, because readdir works directly on the path + return 0; +} + +//TODO +int Fuse::fsyncdir(const bf::path &path, int datasync, fuse_file_info *fileinfo) { + UNUSED(fileinfo); + UNUSED(datasync); + UNUSED(path); + //printf("Called non-implemented fsyncdir(%s, %d, _)\n", path.c_str(), datasync); + return 0; +} + +void Fuse::init(fuse_conn_info *conn) { + UNUSED(conn); + //printf("init()\n"); +} + +void Fuse::destroy() { + //printf("destroy()\n"); +} + +int Fuse::access(const bf::path &path, int mask) { + //printf("access(%s, %d)\n", path.c_str(), mask); + try { + _device->access(path, mask); + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} + +int Fuse::create(const bf::path &path, mode_t mode, fuse_file_info *fileinfo) { + //printf("create(%s, %d, _)\n", path.c_str(), mode); + try { + fileinfo->fh = _device->createAndOpenFile(path, mode); + return 0; + } catch (FuseErrnoException &e) { + return -e.getErrno(); + } +} diff --git a/src/fusepp/Fuse.h b/src/fusepp/Fuse.h index 03a40c5a..cede4982 100644 --- a/src/fusepp/Fuse.h +++ b/src/fusepp/Fuse.h @@ -8,50 +8,53 @@ #include #include #include +#include "utils/macros.h" namespace fusepp { +class FuseDevice; -typedef boost::filesystem::path path; - -//TODO If performance suffers here, we could use template -// and redirect the fuse calls directly to the FuseImpl class instead -// of using virtual functions. class Fuse { public: + Fuse(FuseDevice *device); virtual ~Fuse(); void run(int argc, char **argv); - virtual int getattr(const path &path, struct stat *stbuf) = 0; - virtual int fgetattr(const path &path, struct stat *stbuf, fuse_file_info *fileinfo) = 0; - virtual int readlink(const path &path, char *buf, size_t size) = 0; - virtual int mknod(const path &path, mode_t mode, dev_t rdev) = 0; - virtual int mkdir(const path &path, mode_t mode) = 0; - virtual int unlink(const path &path) = 0; - virtual int rmdir(const path &path) = 0; - virtual int symlink(const path &from, const path &to) = 0; - virtual int rename(const path &from, const path &to) = 0; - virtual int link(const path &from, const path &to) = 0; - virtual int chmod(const path &path, mode_t mode) = 0; - virtual int chown(const path &path, uid_t uid, gid_t gid) = 0; - virtual int truncate(const path &path, off_t size) = 0; - virtual int ftruncate(const path &path, off_t size, fuse_file_info *fileinfo) = 0; - virtual int utimens(const path &path, const timespec times[2]) = 0; - virtual int open(const path &path, fuse_file_info *fileinfo) = 0; - virtual int release(const path &path, fuse_file_info *fileinfo) = 0; - virtual int read(const path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) = 0; - virtual int write(const path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo) = 0; - virtual int statfs(const path &path, struct statvfs *fsstat) = 0; - virtual int flush(const path &path, fuse_file_info *fileinfo) = 0; - virtual int fsync(const path &path, int datasync, fuse_file_info *fileinfo) = 0; - virtual int opendir(const path &path, fuse_file_info *fileinfo) = 0; - virtual int readdir(const path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo) = 0; - virtual int releasedir(const path &path, fuse_file_info *fileinfo) = 0; - virtual int fsyncdir(const path &path, int datasync, fuse_file_info *fileinfo) = 0; - virtual void init(fuse_conn_info *conn) = 0; - virtual void destroy() = 0; - virtual int access(const path &path, int mask) = 0; - virtual int create(const path &path, mode_t mode, fuse_file_info *fileinfo) = 0; + int getattr(const boost::filesystem::path &path, struct stat *stbuf); + int fgetattr(const boost::filesystem::path &path, struct stat *stbuf, fuse_file_info *fileinfo); + int readlink(const boost::filesystem::path &path, char *buf, size_t size); + int mknod(const boost::filesystem::path &path, mode_t mode, dev_t rdev); + int mkdir(const boost::filesystem::path &path, mode_t mode); + int unlink(const boost::filesystem::path &path); + int rmdir(const boost::filesystem::path &path); + int symlink(const boost::filesystem::path &from, const boost::filesystem::path &to); + int rename(const boost::filesystem::path &from, const boost::filesystem::path &to); + int link(const boost::filesystem::path &from, const boost::filesystem::path &to); + int chmod(const boost::filesystem::path &path, mode_t mode); + int chown(const boost::filesystem::path &path, uid_t uid, gid_t gid); + int truncate(const boost::filesystem::path &path, off_t size); + int ftruncate(const boost::filesystem::path &path, off_t size, fuse_file_info *fileinfo); + int utimens(const boost::filesystem::path &path, const timespec times[2]); + int open(const boost::filesystem::path &path, fuse_file_info *fileinfo); + int release(const boost::filesystem::path &path, fuse_file_info *fileinfo); + int read(const boost::filesystem::path &path, char *buf, size_t size, off_t offset, fuse_file_info *fileinfo); + int write(const boost::filesystem::path &path, const char *buf, size_t size, off_t offset, fuse_file_info *fileinfo); + int statfs(const boost::filesystem::path &path, struct statvfs *fsstat); + int flush(const boost::filesystem::path &path, fuse_file_info *fileinfo); + int fsync(const boost::filesystem::path &path, int flags, fuse_file_info *fileinfo); + int opendir(const boost::filesystem::path &path, fuse_file_info *fileinfo); + int readdir(const boost::filesystem::path &path, void *buf, fuse_fill_dir_t filler, off_t offset, fuse_file_info *fileinfo); + int releasedir(const boost::filesystem::path &path, fuse_file_info *fileinfo); + int fsyncdir(const boost::filesystem::path &path, int datasync, fuse_file_info *fileinfo); + void init(fuse_conn_info *conn); + void destroy(); + int access(const boost::filesystem::path &path, int mask); + int create(const boost::filesystem::path &path, mode_t mode, fuse_file_info *fileinfo); + +private: + FuseDevice *_device; + + DISALLOW_COPY_AND_ASSIGN(Fuse); }; } diff --git a/src/fusepp/FuseDevice.cpp b/src/fusepp/FuseDevice.cpp index c3d54e82..84ff1c8b 100644 --- a/src/fusepp/FuseDevice.cpp +++ b/src/fusepp/FuseDevice.cpp @@ -2,10 +2,11 @@ #include #include -#include -#include -#include -#include + +#include "FuseDir.h" +#include "FuseErrnoException.h" +#include "FuseFile.h" + #include "utils/pointer.h" @@ -16,24 +17,15 @@ using std::make_unique; using std::vector; using std::string; -FuseDevice::FuseDevice(const bf::path &rootdir) - :_rootdir(rootdir), _open_files() { +namespace bf = boost::filesystem; + +FuseDevice::FuseDevice() + :_open_files() { } FuseDevice::~FuseDevice() { } -unique_ptr FuseDevice::Load(const bf::path &path) { - auto real_path = RootDir() / path; - if(bf::is_directory(real_path)) { - return make_unique(this, path); - } else if(bf::is_regular_file(real_path)) { - return make_unique(this, path); - } - - throw FuseErrnoException(ENOENT); -} - unique_ptr FuseDevice::LoadFile(const bf::path &path) { auto node = Load(path); auto file = dynamic_pointer_move(node); @@ -138,8 +130,3 @@ void FuseDevice::utimens(const bf::path &path, const timespec times[2]) { auto node = Load(path); node->utimens(times); } - -void FuseDevice::statfs(const bf::path &path, struct statvfs *fsstat) { - int retval = ::statvfs(path.c_str(), fsstat); - CHECK_RETVAL(retval); -} diff --git a/src/fusepp/FuseDevice.h b/src/fusepp/FuseDevice.h index 0c186003..2e9a1247 100644 --- a/src/fusepp/FuseDevice.h +++ b/src/fusepp/FuseDevice.h @@ -16,49 +16,41 @@ class FuseFile; class FuseOpenFile; class FuseDir; -namespace bf = boost::filesystem; - class FuseDevice { public: - FuseDevice(const bf::path &rootdir); + FuseDevice(); virtual ~FuseDevice(); - int openFile(const bf::path &path, int flags); + int openFile(const boost::filesystem::path &path, int flags); void closeFile(int descriptor); - void lstat(const bf::path &path, struct ::stat *stbuf); + void lstat(const boost::filesystem::path &path, struct ::stat *stbuf); void fstat(int descriptor, struct ::stat *stbuf); - void truncate(const bf::path &path, off_t size); + void truncate(const boost::filesystem::path &path, off_t size); void ftruncate(int descriptor, off_t size); int read(int descriptor, void *buf, size_t count, off_t offset); void write(int descriptor, const void *buf, size_t count, off_t offset); void fsync(int descriptor); void fdatasync(int descriptor); - void access(const bf::path &path, int mask); - int createAndOpenFile(const bf::path &path, mode_t mode); - void mkdir(const bf::path &path, mode_t mode); - void rmdir(const bf::path &path); - void unlink(const bf::path &path); - void rename(const bf::path &from, const bf::path &to); - std::unique_ptr> readDir(const bf::path &path); - void utimens(const bf::path &path, const timespec times[2]); - void statfs(const bf::path &path, struct statvfs *fsstat); + void access(const boost::filesystem::path &path, int mask); + int createAndOpenFile(const boost::filesystem::path &path, mode_t mode); + void mkdir(const boost::filesystem::path &path, mode_t mode); + void rmdir(const boost::filesystem::path &path); + void unlink(const boost::filesystem::path &path); + void rename(const boost::filesystem::path &from, const boost::filesystem::path &to); + std::unique_ptr> readDir(const boost::filesystem::path &path); + void utimens(const boost::filesystem::path &path, const timespec times[2]); + virtual void statfs(const boost::filesystem::path &path, struct statvfs *fsstat) = 0; - const bf::path &RootDir() const; private: - std::unique_ptr Load(const bf::path &path); - std::unique_ptr LoadFile(const bf::path &path); - std::unique_ptr LoadDir(const bf::path &path); + virtual std::unique_ptr Load(const boost::filesystem::path &path) = 0; + std::unique_ptr LoadFile(const boost::filesystem::path &path); + std::unique_ptr LoadDir(const boost::filesystem::path &path); int openFile(const FuseFile &file, int flags); - const bf::path _rootdir; FuseOpenFileList _open_files; DISALLOW_COPY_AND_ASSIGN(FuseDevice); }; -inline const bf::path &FuseDevice::RootDir() const { - return _rootdir; -} - } #endif /* FUSEPP_FUSEDEVICE_H_ */ diff --git a/src/fusepp/FuseDir.cpp b/src/fusepp/FuseDir.cpp index ea864a2d..8c3076fd 100644 --- a/src/fusepp/FuseDir.cpp +++ b/src/fusepp/FuseDir.cpp @@ -1,75 +1 @@ -#include -#include -#include -#include -#include -#include -#include -#include - - -using std::string; -using std::unique_ptr; -using std::make_unique; -using std::vector; - -namespace fusepp { - -FuseDir::FuseDir(FuseDevice *device, const bf::path &path) - :FuseNode(device, path) { - assert(bf::is_directory(base_path())); -} - -FuseDir::~FuseDir() { -} - -unique_ptr FuseDir::createFile(const string &name, mode_t mode) { - auto file_path = base_path() / name; - //Create file - int fd = ::creat(file_path.c_str(), mode); - CHECK_RETVAL(fd); - ::close(fd); - return make_unique(device(), path() / name); -} - -unique_ptr FuseDir::createDir(const string &name, mode_t mode) { - auto dir_path = base_path() / name; - //Create dir - int retval = ::mkdir(dir_path.c_str(), mode); - CHECK_RETVAL(retval); - return make_unique(device(), path() / name); -} - -void FuseDir::rmdir() { - int retval = ::rmdir(base_path().c_str()); - CHECK_RETVAL(retval); -} - -unique_ptr> FuseDir::children() const { - DIR *dir = ::opendir(base_path().c_str()); - if (dir == nullptr) { - throw FuseErrnoException(errno); - } - - // Set errno=0 so we can detect whether it changed later - errno = 0; - - auto result = make_unique>(); - - struct dirent *entry = ::readdir(dir); - while(entry != nullptr) { - result->push_back(entry->d_name); - entry = ::readdir(dir); - } - //On error, ::readdir returns nullptr and sets errno. - if (errno != 0) { - int readdir_errno = errno; - ::closedir(dir); - throw FuseErrnoException(readdir_errno); - } - int retval = ::closedir(dir); - CHECK_RETVAL(retval); - return result; -} - -} /* namespace fusepp */ +#include "FuseDir.h" diff --git a/src/fusepp/FuseDir.h b/src/fusepp/FuseDir.h index c14d3cf7..7a83e887 100644 --- a/src/fusepp/FuseDir.h +++ b/src/fusepp/FuseDir.h @@ -2,28 +2,23 @@ #ifndef FUSEPP_FUSEDIR_H_ #define FUSEPP_FUSEDIR_H_ -#include +#include "FuseNode.h" #include #include -#include "utils/macros.h" - namespace fusepp { class FuseDevice; +class FuseFile; -class FuseDir: public FuseNode { +class FuseDir: public virtual FuseNode { public: - FuseDir(FuseDevice *device, const bf::path &path); - virtual ~FuseDir(); + virtual ~FuseDir() {} - std::unique_ptr createFile(const std::string &name, mode_t mode); - std::unique_ptr createDir(const std::string &name, mode_t mode); - void rmdir(); + virtual std::unique_ptr createFile(const std::string &name, mode_t mode) = 0; + virtual std::unique_ptr createDir(const std::string &name, mode_t mode) = 0; + virtual void rmdir() = 0; - std::unique_ptr> children() const; - -private: - DISALLOW_COPY_AND_ASSIGN(FuseDir); + virtual std::unique_ptr> children() const = 0; }; } /* namespace fusepp */ diff --git a/src/fusepp/FuseErrnoException.cpp b/src/fusepp/FuseErrnoException.cpp index de91af3f..bcc4eb12 100644 --- a/src/fusepp/FuseErrnoException.cpp +++ b/src/fusepp/FuseErrnoException.cpp @@ -1,4 +1,5 @@ -#include +#include "FuseErrnoException.h" + #include #include #include diff --git a/src/fusepp/FuseFile.cpp b/src/fusepp/FuseFile.cpp index ca59371c..b3f66c26 100644 --- a/src/fusepp/FuseFile.cpp +++ b/src/fusepp/FuseFile.cpp @@ -1,32 +1 @@ -#include -#include -#include - -using std::unique_ptr; -using std::make_unique; - -namespace fusepp { - -FuseFile::FuseFile(FuseDevice *device, const bf::path &path) - :FuseNode(device, path) { - assert(bf::is_regular_file(base_path())); -} - -FuseFile::~FuseFile() { -} - -std::unique_ptr FuseFile::open(int flags) const { - return make_unique(device(), path(), flags); -} - -void FuseFile::truncate(off_t size) const { - int retval = ::truncate(base_path().c_str(), size); - CHECK_RETVAL(retval); -} - -void FuseFile::unlink() { - int retval = ::unlink(base_path().c_str()); - CHECK_RETVAL(retval); -} - -} /* namespace fusepp */ +#include "FuseFile.h" diff --git a/src/fusepp/FuseFile.h b/src/fusepp/FuseFile.h index 0e4df0ac..1f73fd83 100644 --- a/src/fusepp/FuseFile.h +++ b/src/fusepp/FuseFile.h @@ -2,25 +2,20 @@ #ifndef FUSEPP_FUSEFILE_H_ #define FUSEPP_FUSEFILE_H_ -#include +#include "FuseNode.h" #include -#include "utils/macros.h" - namespace fusepp { class FuseDevice; class FuseOpenFile; -class FuseFile: public FuseNode { +class FuseFile: public virtual FuseNode { public: - FuseFile(FuseDevice *device, const bf::path &path); - virtual ~FuseFile(); + virtual ~FuseFile() {} - std::unique_ptr open(int flags) const; - void truncate(off_t size) const; - void unlink(); -private: - DISALLOW_COPY_AND_ASSIGN(FuseFile); + virtual std::unique_ptr open(int flags) const = 0; + virtual void truncate(off_t size) const = 0; + virtual void unlink() = 0; }; } /* namespace fusepp */ diff --git a/src/fusepp/FuseNode.cpp b/src/fusepp/FuseNode.cpp index 115fdcff..feaf46c3 100644 --- a/src/fusepp/FuseNode.cpp +++ b/src/fusepp/FuseNode.cpp @@ -1,40 +1 @@ -#include -#include -#include -#include - - -namespace fusepp { - -FuseNode::FuseNode(FuseDevice *device, const bf::path &path) - :_device(device), _path(path) { -} - -FuseNode::~FuseNode() { -} - -void FuseNode::stat(struct ::stat *result) const { - int retval = ::lstat(base_path().c_str(), result); - CHECK_RETVAL(retval); -} - -void FuseNode::access(int mask) const { - int retval = ::access(base_path().c_str(), mask); - CHECK_RETVAL(retval); -} - -void FuseNode::rename(const bf::path &to) { - auto new_base_path = device()->RootDir() / to; - int retval = ::rename(base_path().c_str(), new_base_path.c_str()); - CHECK_RETVAL(retval); - _path = to; -} - -void FuseNode::utimens(const timespec times[2]) { - struct timeval timevals[2]; - TIMESPEC_TO_TIMEVAL(&timevals[0], ×[0]); - TIMESPEC_TO_TIMEVAL(&timevals[1], ×[1]); - ::lutimes(base_path().c_str(), timevals); -} - -} /* namespace fusepp */ +#include "FuseNode.h" diff --git a/src/fusepp/FuseNode.h b/src/fusepp/FuseNode.h index 1bbce062..5e7bb78f 100644 --- a/src/fusepp/FuseNode.h +++ b/src/fusepp/FuseNode.h @@ -3,54 +3,22 @@ #define FUSEPP_FUSENODE_H_ #include -#include #include "utils/macros.h" #include namespace fusepp { -namespace bf = boost::filesystem; - class FuseNode { public: - FuseNode(FuseDevice *device, const bf::path &path); - virtual ~FuseNode(); + virtual ~FuseNode() {} - void stat(struct ::stat *result) const; - void access(int mask) const; - void rename(const bf::path &to); - void utimens(const timespec times[2]); - -protected: - bf::path base_path() const; - const bf::path &path() const; - FuseDevice *device(); - const FuseDevice *device() const; - -private: - FuseDevice *const _device; - bf::path _path; - - DISALLOW_COPY_AND_ASSIGN(FuseNode); + virtual void stat(struct ::stat *result) const = 0; + virtual void access(int mask) const = 0; + virtual void rename(const boost::filesystem::path &to) = 0; + virtual void utimens(const timespec times[2]) = 0; }; -inline bf::path FuseNode::base_path() const { - return _device->RootDir() / _path; -} - -inline const bf::path &FuseNode::path() const { - return _path; -} - -inline FuseDevice *FuseNode::device() { - return const_cast(const_cast(this)->device()); -} - -inline const FuseDevice *FuseNode::device() const { - return _device; -} - } /* namespace fusepp */ #endif /* FUSEPP_FUSENODE_H_ */ diff --git a/src/fusepp/FuseOpenFile.cpp b/src/fusepp/FuseOpenFile.cpp index 56ce45b0..27e40456 100644 --- a/src/fusepp/FuseOpenFile.cpp +++ b/src/fusepp/FuseOpenFile.cpp @@ -1,55 +1 @@ -#include -#include -#include -#include -#include - - -using namespace fusepp; - -FuseOpenFile::FuseOpenFile(const FuseDevice *device, const bf::path &path, int flags) - :_descriptor(::open((device->RootDir() / path).c_str(), flags)) { - CHECK_RETVAL(_descriptor); -} - -FuseOpenFile::~FuseOpenFile() { - int retval = close(_descriptor); - CHECK_RETVAL(retval); -} - -void FuseOpenFile::stat(struct ::stat *result) const { - int retval = ::fstat(_descriptor, result); - CHECK_RETVAL(retval); -} - -void FuseOpenFile::truncate(off_t size) const { - int retval = ::ftruncate(_descriptor, size); - CHECK_RETVAL(retval); -} - -int FuseOpenFile::read(void *buf, size_t count, off_t offset) { - //printf("Reading from real descriptor %d (%d, %d)\n", _descriptor, offset, count); - //fflush(stdout); - int retval = ::pread(_descriptor, buf, count, offset); - CHECK_RETVAL(retval); - //printf("retval: %d, count: %d\n", retval, count); - //fflush(stdout); - assert(static_cast(retval) <= count); - return retval; -} - -void FuseOpenFile::write(const void *buf, size_t count, off_t offset) { - int retval = ::pwrite(_descriptor, buf, count, offset); - CHECK_RETVAL(retval); - assert(static_cast(retval) == count); -} - -void FuseOpenFile::fsync() { - int retval = ::fsync(_descriptor); - CHECK_RETVAL(retval); -} - -void FuseOpenFile::fdatasync() { - int retval = ::fdatasync(_descriptor); - CHECK_RETVAL(retval); -} +#include "FuseOpenFile.h" diff --git a/src/fusepp/FuseOpenFile.h b/src/fusepp/FuseOpenFile.h index 18f2b9e2..2d5d748c 100644 --- a/src/fusepp/FuseOpenFile.h +++ b/src/fusepp/FuseOpenFile.h @@ -5,28 +5,19 @@ #include #include -#include "utils/macros.h" - namespace fusepp { class FuseDevice; -namespace bf = boost::filesystem; - class FuseOpenFile { public: - FuseOpenFile(const FuseDevice *device, const bf::path &path, int flags); - virtual ~FuseOpenFile(); + virtual ~FuseOpenFile() {} - void stat(struct ::stat *result) const; - void truncate(off_t size) const; - int read(void *buf, size_t count, off_t offset); - void write(const void *buf, size_t count, off_t offset); - void fsync(); - void fdatasync(); -private: - int _descriptor; - - DISALLOW_COPY_AND_ASSIGN(FuseOpenFile); + virtual void stat(struct ::stat *result) const = 0; + virtual void truncate(off_t size) const = 0; + virtual int read(void *buf, size_t count, off_t offset) = 0; + virtual void write(const void *buf, size_t count, off_t offset) = 0; + virtual void fsync() = 0; + virtual void fdatasync() = 0; }; } diff --git a/src/fusepp/FuseOpenFileList.cpp b/src/fusepp/FuseOpenFileList.cpp index 4ad91fa7..7a941977 100644 --- a/src/fusepp/FuseOpenFileList.cpp +++ b/src/fusepp/FuseOpenFileList.cpp @@ -1,25 +1,6 @@ -#include -#include -#include +#include "FuseOpenFileList.h" using namespace fusepp; FuseOpenFileList::~FuseOpenFileList() { } - -FuseOpenFileList::FuseOpenFileList() - :_open_files() { -} - -int FuseOpenFileList::open(const FuseFile &file, int flags) { - return _open_files.add(file.open(flags)); -} - -FuseOpenFile *FuseOpenFileList::get(int descriptor) { - return _open_files.get(descriptor); -} - -void FuseOpenFileList::close(int descriptor) { - //The destructor of the stored FuseOpenFile closes the file - _open_files.remove(descriptor); -} diff --git a/src/fusepp/FuseOpenFileList.h b/src/fusepp/FuseOpenFileList.h index 1d00ebeb..27640146 100644 --- a/src/fusepp/FuseOpenFileList.h +++ b/src/fusepp/FuseOpenFileList.h @@ -4,10 +4,10 @@ #include "utils/macros.h" #include "IdList.h" +#include "FuseFile.h" +#include "FuseOpenFile.h" namespace fusepp { -class FuseOpenFile; -class FuseFile; class FuseOpenFileList { public: @@ -24,6 +24,23 @@ private: DISALLOW_COPY_AND_ASSIGN(FuseOpenFileList); }; +inline FuseOpenFileList::FuseOpenFileList() + :_open_files() { +} + +inline int FuseOpenFileList::open(const FuseFile &file, int flags) { + return _open_files.add(file.open(flags)); +} + +inline FuseOpenFile *FuseOpenFileList::get(int descriptor) { + return _open_files.get(descriptor); +} + +inline void FuseOpenFileList::close(int descriptor) { + //The destructor of the stored FuseOpenFile closes the file + _open_files.remove(descriptor); +} + } #endif /* FUSEPP_FUSEOPENFILELIST_H_ */ diff --git a/src/fusepp/IdList.cpp b/src/fusepp/IdList.cpp index 7d6dc54a..0950227f 100644 --- a/src/fusepp/IdList.cpp +++ b/src/fusepp/IdList.cpp @@ -1,5 +1 @@ #include "IdList.h" - -namespace fusepp { - -} /* namespace fusepp */ diff --git a/src/fusepp/utils/macros.h b/src/fusepp/utils/macros.h index bf189ed8..e4523cb6 100644 --- a/src/fusepp/utils/macros.h +++ b/src/fusepp/utils/macros.h @@ -6,4 +6,6 @@ Class(const Class &rhs) = delete; \ Class &operator=(const Class &rhs) = delete; +#define UNUSED(expr) (void)(expr) + #endif /* FUSEPP_UTILS_MACROS_H_ */ diff --git a/src/main.cpp b/src/main.cpp index a4b358f3..0818e963 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,13 +3,16 @@ #include #include "buildconfig/BuildConfig.h" -#include "CryFuse.h" +#include "fusepp/Fuse.h" +#include "cryfs_lib/CryDevice.h" + +namespace bf = boost::filesystem; int main (int argc, char *argv[]) { printf("Version: %d\n", buildconfig::VERSION::MAJOR); - fusepp::FuseDevice device(fusepp::path("/home/heinzi/cryfstest/root")); - fusepp::CryFuse fuse(&device); + cryfs::CryDevice device(bf::path("/home/heinzi/cryfstest/root")); + fusepp::Fuse fuse(&device); fuse.run(argc, argv); return 0; }