From eddec21bbd83495a02185bb8a45fbd38b9ec8b99 Mon Sep 17 00:00:00 2001 From: Falk Werner Date: Sun, 13 Nov 2022 18:18:44 +0100 Subject: [PATCH] provide empty filesystem --- CMakeLists.txt | 3 + src/main.cpp | 4 +- src/webfuse/filesystem/empty_filesystem.cpp | 135 ++++++++ src/webfuse/filesystem/empty_filesystem.hpp | 45 +++ src/webfuse/filesystem/filesystem_i.hpp | 5 +- .../filesystem/filesystem_statistics.cpp | 43 +++ src/webfuse/filesystem/status.cpp | 6 + src/webfuse/filesystem/status.hpp | 2 + src/webfuse/fuse.cpp | 319 ++++++++++++++++++ src/webfuse/fuse.hpp | 6 +- src/webfuse/webfuse.cpp | 23 +- src/webfuse/webfuse.hpp | 11 +- test-src/webfuse/test_app.cpp | 4 +- 13 files changed, 569 insertions(+), 37 deletions(-) create mode 100644 src/webfuse/filesystem/empty_filesystem.cpp create mode 100644 src/webfuse/filesystem/empty_filesystem.hpp create mode 100644 src/webfuse/filesystem/filesystem_statistics.cpp create mode 100644 src/webfuse/fuse.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 123d8ec..f54bb8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ pkg_check_modules(LWS REQUIRED IMPORTED_TARGET libwebsockets) add_library(webfuse_static STATIC src/webfuse/webfuse.cpp + src/webfuse/fuse.cpp src/webfuse/filesystem/status.cpp src/webfuse/filesystem/accessmode.cpp src/webfuse/filesystem/openflags.cpp @@ -17,6 +18,8 @@ add_library(webfuse_static STATIC src/webfuse/filesystem/filemode.cpp src/webfuse/filesystem/filetime.cpp src/webfuse/filesystem/fileattributes.cpp + src/webfuse/filesystem/filesystem_statistics.cpp + src/webfuse/filesystem/empty_filesystem.cpp ) target_include_directories(webfuse_static PUBLIC src) diff --git a/src/main.cpp b/src/main.cpp index 702f132..f582bd2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,6 @@ int main(int argc, char* argv[]) { - webfuse::app app(argc, argv); - return app.run(); + webfuse::app app; + return app.run(argc, argv); } \ No newline at end of file diff --git a/src/webfuse/filesystem/empty_filesystem.cpp b/src/webfuse/filesystem/empty_filesystem.cpp new file mode 100644 index 0000000..9993cda --- /dev/null +++ b/src/webfuse/filesystem/empty_filesystem.cpp @@ -0,0 +1,135 @@ +#include "webfuse/filesystem/empty_filesystem.hpp" + +namespace webfuse +{ + +status empty_filesystem::access(std::string const & path, access_mode mode) +{ + if (path == "/") + { + return status::good; + } + else + { + return status::bad_enoent; + } +} + +status empty_filesystem::getattr(std::string const & path, file_attributes & attr) +{ + if (path == "/") + { + attr.inode = 1; + attr.nlink = 1; + attr.mode = filemode(filemode::dir | 0x444); + return status::good; + } + else + { + return status::bad_enoent; + } +} + +status empty_filesystem::readlink(std::string const & path, std::string & out) +{ + return status::bad_enoent; +} + +status empty_filesystem::symlink(std::string const & target, std::string const & linkpath) +{ + return status::bad_enoent; +} + +status empty_filesystem::link(std::string const & old_path, std::string const & new_path) +{ + return status::bad_enoent; +} + +status empty_filesystem::rename(std::string const & old_path, std::string const & new_path) +{ + return status::bad_enoent; +} + +status empty_filesystem::chmod(std::string const & path, filemode mode) +{ + return status::bad_eperm; +} + +status empty_filesystem::chown(std::string const & path, user_id uid, group_id gid) +{ + return status::bad_eperm; +} + +status empty_filesystem::truncate(std::string const & path, uint64_t offset, filehandle handle) +{ + return status::bad_eperm; +} + +status empty_filesystem::fsync(std::string const & path, bool is_datasync, filehandle handle) +{ + return status::good; +} + +status empty_filesystem::open(std::string const & path, openflags flags, filehandle & handle) +{ + return status::bad_enoent; +} + +status empty_filesystem::mknod(std::string const & path, filemode mode, uint64_t rdev) +{ + return status::bad_eperm; + +} +status empty_filesystem::create(std::string const & path, filemode mode, filehandle & handle) +{ + return status::bad_eperm; +} + +status empty_filesystem::release(std::string const & path, filehandle handle) +{ + return status::good; +} + +status empty_filesystem::unlink(std::string const & path) +{ + return status::bad_eperm; +} + +status empty_filesystem::read(std::string const & path, char * buffer, size_t buffer_size, uint64_t offset, filehandle handle) +{ + return status::bad_ebadf; +} +status empty_filesystem::write(std::string const & path, char const * buffer, size_t buffer_size, uint64_t offset, filehandle handle) +{ + return status::bad_ebadf; +} + +status empty_filesystem::mkdir(std::string const & path, filemode mode) +{ + return status::bad_eperm; +} + +status empty_filesystem::readdir(std::string const & path, std::vector & entries, filehandle handle) +{ + if (path == "/") + { + return status::good; + } + else + { + return status::bad_enoent; + } +} + +status empty_filesystem::rmdir(std::string const & path) +{ + return status::bad_eperm; +} + +status empty_filesystem::statfs(std::string const & path, filesystem_statistics & statistics) +{ + return status::bad_enosys; +} + + +} \ No newline at end of file diff --git a/src/webfuse/filesystem/empty_filesystem.hpp b/src/webfuse/filesystem/empty_filesystem.hpp new file mode 100644 index 0000000..b020f03 --- /dev/null +++ b/src/webfuse/filesystem/empty_filesystem.hpp @@ -0,0 +1,45 @@ +#ifndef WEBFUSE_EMPTYFILESYSTEM_HPP +#define WEBFUSE_EMPTYFILESYSTEM_HPP + +#include "webfuse/filesystem/filesystem_i.hpp" + +namespace webfuse +{ + +class empty_filesystem: public filesystem_i +{ +public: + ~empty_filesystem() override = default; + + status access(std::string const & path, access_mode mode) override; + status getattr(std::string const & path, file_attributes & attr) override; + + status readlink(std::string const & path, std::string & out) override; + status symlink(std::string const & target, std::string const & linkpath) override; + status link(std::string const & old_path, std::string const & new_path) override; + + status rename(std::string const & old_path, std::string const & new_path) override; + status chmod(std::string const & path, filemode mode) override; + status chown(std::string const & path, user_id uid, group_id gid) override; + status truncate(std::string const & path, uint64_t offset, filehandle handle) override; + status fsync(std::string const & path, bool is_datasync, filehandle handle) override; + + status open(std::string const & path, openflags flags, filehandle & handle) override; + status mknod(std::string const & path, filemode mode, uint64_t rdev) override; + status create(std::string const & path, filemode mode, filehandle & handle) override; + status release(std::string const & path, filehandle handle) override; + status unlink(std::string const & path) override; + + status read(std::string const & path, char * buffer, size_t buffer_size, uint64_t offset, filehandle handle) override; + status write(std::string const & path, char const * buffer, size_t buffer_size, uint64_t offset, filehandle handle) override; + + status mkdir(std::string const & path, filemode mode) override; + status readdir(std::string const & path, std::vector & entries, filehandle handle) override; + status rmdir(std::string const & path) override; + + status statfs(std::string const & path, filesystem_statistics & statistics) override; +}; + +} + +#endif diff --git a/src/webfuse/filesystem/filesystem_i.hpp b/src/webfuse/filesystem/filesystem_i.hpp index 03f2e58..84b585e 100644 --- a/src/webfuse/filesystem/filesystem_i.hpp +++ b/src/webfuse/filesystem/filesystem_i.hpp @@ -32,7 +32,7 @@ public: virtual status rename(std::string const & old_path, std::string const & new_path) = 0; virtual status chmod(std::string const & path, filemode mode) = 0; - virtual status chown(std::string const & path, user_id uid, group_id gid); + virtual status chown(std::string const & path, user_id uid, group_id gid) = 0; virtual status truncate(std::string const & path, uint64_t offset, filehandle handle) = 0; virtual status fsync(std::string const & path, bool is_datasync, filehandle handle) = 0; @@ -45,7 +45,8 @@ public: virtual status read(std::string const & path, char * buffer, size_t buffer_size, uint64_t offset, filehandle handle) = 0; virtual status write(std::string const & path, char const * buffer, size_t buffer_size, uint64_t offset, filehandle handle) = 0; - virtual status readdir(std::string const & path, std::vector entries, filehandle handle) = 0; + virtual status mkdir(std::string const & path, filemode mode) = 0; + virtual status readdir(std::string const & path, std::vector & entries, filehandle handle) = 0; virtual status rmdir(std::string const & path) = 0; virtual status statfs(std::string const & path, filesystem_statistics & statistics) = 0; diff --git a/src/webfuse/filesystem/filesystem_statistics.cpp b/src/webfuse/filesystem/filesystem_statistics.cpp new file mode 100644 index 0000000..5422b80 --- /dev/null +++ b/src/webfuse/filesystem/filesystem_statistics.cpp @@ -0,0 +1,43 @@ +#include "webfuse/filesystem/filesystem_statistics.hpp" + +namespace webfuse +{ + +filesystem_statistics::filesystem_statistics() +: bsize(0) +, frsize(0) +, blocks(0) +, bfree(0) +, bavail(0) +, files(0) +, ffree(0) +, f_namemax(0) +{ + +} + +filesystem_statistics::filesystem_statistics(struct statvfs const & other) +{ + bsize = other.f_bsize; + frsize = other.f_frsize; + blocks = other.f_blocks; + bfree = other.f_bfree; + bavail = other.f_bavail; + files = other.f_files; + ffree = other.f_ffree; + f_namemax = other.f_namemax; +} + +void filesystem_statistics::copy_to(struct statvfs & other) const +{ + other.f_bsize = bsize; + other.f_frsize = frsize; + other.f_blocks = blocks; + other.f_bfree = bfree; + other.f_bavail = bavail; + other.f_files = files; + other.f_ffree = ffree; + other.f_namemax = f_namemax; +} + +} \ No newline at end of file diff --git a/src/webfuse/filesystem/status.cpp b/src/webfuse/filesystem/status.cpp index cda71cc..b3b3977 100644 --- a/src/webfuse/filesystem/status.cpp +++ b/src/webfuse/filesystem/status.cpp @@ -117,4 +117,10 @@ int status::to_fusestatus() const } } +bool status::is_good() const +{ + return (value_ == status::good); +} + + } \ No newline at end of file diff --git a/src/webfuse/filesystem/status.hpp b/src/webfuse/filesystem/status.hpp index ee322a1..5b3f6af 100644 --- a/src/webfuse/filesystem/status.hpp +++ b/src/webfuse/filesystem/status.hpp @@ -53,6 +53,8 @@ public: static status from_fusestatus(int value); int to_fusestatus() const; + + bool is_good() const; private: int32_t value_; }; diff --git a/src/webfuse/fuse.cpp b/src/webfuse/fuse.cpp new file mode 100644 index 0000000..4ed7a49 --- /dev/null +++ b/src/webfuse/fuse.cpp @@ -0,0 +1,319 @@ +#define FUSE_USE_VERSION 31 + +#include "webfuse/fuse.hpp" +#include +#include +#include + +extern "C" +{ + +static webfuse::filesystem_i * fs_get_filesystem() +{ + struct fuse_context * context = fuse_get_context(); + void * private_data = context->private_data; + return reinterpret_cast(private_data); +} + +static webfuse::filehandle fs_get_handle(fuse_file_info * info) +{ + return (nullptr != info) ? info->fh : webfuse::invalid_handle; +} + +static void * fs_init(fuse_conn_info * connection, fuse_config * config) +{ + (void) connection; + config->use_ino = 1; + config->entry_timeout = 0; + config->attr_timeout = 0; + config->negative_timeout = 0; + + struct fuse_context * context = fuse_get_context(); + return context->private_data; +} + + +static int fs_access(char const * path, int raw_mode) +{ + auto * const fs = fs_get_filesystem(); + auto const mode = webfuse::access_mode::from_int(raw_mode); + auto const result = fs->access(path, mode); + + return result.to_fusestatus(); +} + +static int fs_getattr(char const * path, struct stat * buffer, fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + webfuse::file_attributes attributes(*buffer); + + auto const result = fs->getattr(path, attributes); + attributes.to_stat(*buffer); + + return result.to_fusestatus(); +} + +static int fs_readlink(char const * path, char * buffer, size_t buffer_size) +{ + auto * const fs = fs_get_filesystem(); + + std::string out; + auto result = fs->readlink(path, out); + if (webfuse::status::good == result) + { + snprintf(buffer, buffer_size, "%s", out.c_str()); + result = strlen(buffer); + } + + return result.to_fusestatus(); +} + +static int fs_symlink(char const * target, char const * linkpath) +{ + auto * const fs = fs_get_filesystem(); + auto const result = fs->symlink(target, linkpath); + return result.to_fusestatus(); +} + +static int fs_link(char const * old_path, char const * new_path) +{ + auto * const fs = fs_get_filesystem(); + auto const result = fs->link(old_path, new_path); + return result.to_fusestatus(); +} + +static int fs_rename(char const * from, char const * to, unsigned int flags) +{ + // ToDo: provide flags + auto * const fs = fs_get_filesystem(); + auto const result = fs->rename(from, to); + return result.to_fusestatus(); +} + +static int fs_chmod(char const * path, mode_t raw_mode, fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + auto const mode = webfuse::filemode::from_mode(raw_mode); + auto const result = fs->chmod(path, mode); + return result.to_fusestatus(); +} + +static int fs_chown(char const * path, uid_t raw_uid, + gid_t raw_gid, fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + auto const uid = webfuse::user_id::from_uid(raw_uid); + auto const gid = webfuse::group_id::from_gid(raw_gid); + auto const result = fs->chown(path, uid, gid); + return result.to_fusestatus(); +} + +static int fs_truncate(char const * path, off_t raw_size, fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + auto const size = static_cast(raw_size); + auto const handle = fs_get_handle(info); + + auto const result = fs->truncate(path, size, handle); + return result.to_fusestatus(); +} + +static int fs_fsync(char const * path, int isdatasync, fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + bool const is_datasync = (is_datasync != 0); + auto const handle = fs_get_handle(info); + + auto const result = fs->fsync(path, is_datasync, handle); + return result.to_fusestatus(); +} + +static int fs_open(char const * path, fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + auto const flags = webfuse::openflags::from_int(info->flags); + + auto const result = fs->open(path, flags, info->fh); + return result.to_fusestatus(); +} + +static int fs_mknod(char const * path, mode_t raw_mode, dev_t raw_rdev) +{ + auto * const fs = fs_get_filesystem(); + auto const mode = webfuse::filemode::from_mode(raw_mode); + auto const rdev = static_cast(raw_rdev); + + auto const result = fs->mknod(path, mode, rdev); + return result.to_fusestatus(); +} + +static int fs_create(char const * path, mode_t raw_mode, fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + auto const mode = webfuse::filemode::from_mode(raw_mode); + + auto const result = fs->create(path, mode, info->fh); + return result.to_fusestatus(); +} + +static int fs_release(char const * path, fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + auto const handle = fs_get_handle(info); + + auto const result = fs->release(path, handle); + return result.to_fusestatus(); +} + +static int fs_unlink(char const * path) +{ + auto * const fs = fs_get_filesystem(); + auto const result = fs->unlink(path); + return result.to_fusestatus(); +} + +static int fs_read(char const * path, char * buffer, + size_t buffer_size, off_t raw_offset, + fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + auto const offset = static_cast(raw_offset); + auto const handle = fs_get_handle(info); + + auto const result = fs->read(path, buffer, buffer_size, offset, handle); + return result.to_fusestatus(); +} + +static int fs_write(char const * path, char const * buffer, + size_t buffer_size, off_t raw_offset, + fuse_file_info * info) +{ + auto * const fs = fs_get_filesystem(); + auto const offset = static_cast(raw_offset); + auto const handle = fs_get_handle(info); + + auto const result = fs->write(path, buffer, buffer_size, offset, handle); + return result.to_fusestatus(); +} + +static int fs_mkdir(char const * path, mode_t raw_mode) +{ + auto * const fs = fs_get_filesystem(); + auto const mode = webfuse::filemode::from_mode(raw_mode); + + auto const result = fs->mkdir(path, mode); + return result.to_fusestatus(); +} + +static int fs_readdir(char const * path, void * buffer, + fuse_fill_dir_t filler, off_t offset, fuse_file_info * info, + fuse_readdir_flags flags) +{ + auto * const fs = fs_get_filesystem(); + auto handle = fs_get_handle(info); + std::vector names; + auto const result = fs->readdir(path, names, handle); + if (result.is_good()) + { + filler(buffer, ".", nullptr, 0, static_cast(0)); + filler(buffer, "..", nullptr, 0, static_cast(0)); + for (auto const & name: names) + { + filler(buffer, name.c_str(), nullptr, 0, static_cast(0)); + } + } + + return result.to_fusestatus(); +} + +static int fs_rmdir(char const * path) +{ + auto * const fs = fs_get_filesystem(); + auto const result = fs->rmdir(path); + return result.to_fusestatus(); +} + +static int fs_statfs(char const * path, struct statvfs * buffer) +{ + auto * const fs = fs_get_filesystem(); + webfuse::filesystem_statistics statistics(*buffer); + + auto const result = fs->statfs(path, statistics); + statistics.copy_to(*buffer); + + return result.to_fusestatus(); + +} + +} + +namespace webfuse +{ + +class fuse::detail +{ +public: + filesystem_i & filesystem; +}; + +fuse::fuse(filesystem_i & filesystem) +: d(new detail{filesystem}) +{ + +} + +fuse::~fuse() +{ + delete d; +} + +fuse::fuse(fuse && other) +{ + this->d = other.d; + other.d = nullptr; +} + +fuse& fuse::operator=(fuse && other) +{ + if (this != &other) + { + delete d; + this->d = other.d; + other.d = nullptr; + } + + return *this; +} + +int fuse::run(int argc, char * argv[]) +{ + void * context = reinterpret_cast(&d->filesystem); + struct fuse_operations operations; + memset(reinterpret_cast(&operations), 0, sizeof(operations)); + operations.init = fs_init; + operations.access = fs_access; + operations.getattr = fs_getattr; + operations.readlink = fs_readlink; + operations.symlink = fs_symlink; + operations.link = fs_link; + operations.rename = fs_rename; + operations.chmod = fs_chmod; + operations.chown = fs_chown; + operations.truncate = fs_truncate; + operations.fsync = fs_fsync; + operations.open = fs_open; + operations.mknod = fs_mknod; + operations.create = fs_create; + operations.release = fs_release; + operations.unlink = fs_unlink; + operations.read = fs_read; + operations.write = fs_write; + operations.mkdir = fs_mkdir; + operations.readdir = fs_readdir; + operations.rmdir = fs_rmdir; + operations.statfs = fs_statfs; + + return fuse_main(argc, argv, &operations, context); +} + +} \ No newline at end of file diff --git a/src/webfuse/fuse.hpp b/src/webfuse/fuse.hpp index 39acb9e..aa5bbbb 100644 --- a/src/webfuse/fuse.hpp +++ b/src/webfuse/fuse.hpp @@ -13,9 +13,9 @@ class fuse public: explicit fuse(filesystem_i & filesystem); ~fuse(); - fuse (fuse &&) = delete; - fuse& operator=(fuse &&) = delete; - void run(int argc, char * argv[]); + fuse (fuse && other); + fuse& operator=(fuse && other); + int run(int argc, char * argv[]); private: class detail; detail * d; diff --git a/src/webfuse/webfuse.cpp b/src/webfuse/webfuse.cpp index 2d69d06..6ebb5b2 100644 --- a/src/webfuse/webfuse.cpp +++ b/src/webfuse/webfuse.cpp @@ -1,27 +1,16 @@ #include "webfuse/webfuse.hpp" +#include "webfuse/fuse.hpp" +#include "webfuse/filesystem/empty_filesystem.hpp" namespace webfuse { -class app::detail +int app::run(int argc, char * argv[]) { - int dummy; -}; + empty_filesystem filesystem; + fuse fuse_fs(filesystem); -app::app(int argc, char * argv[]) -: d(new detail) -{ - -} - -app::~app() -{ - delete d; -} - -int app::run() -{ - return 0; + return fuse_fs.run(argc, argv); } } \ No newline at end of file diff --git a/src/webfuse/webfuse.hpp b/src/webfuse/webfuse.hpp index 60c5989..6e76c1e 100644 --- a/src/webfuse/webfuse.hpp +++ b/src/webfuse/webfuse.hpp @@ -6,17 +6,8 @@ namespace webfuse class app { - app(app const &) = delete; - app& operator=(app const &) = delete; - app(app &&) = delete; - app& operator=(app &&) = delete; public: - app(int argc, char * argv[]); - ~app(); - int run(); -private: - class detail; - detail * d; + int run(int argc, char * argv[]); }; } diff --git a/test-src/webfuse/test_app.cpp b/test-src/webfuse/test_app.cpp index ff08344..d15cfde 100644 --- a/test-src/webfuse/test_app.cpp +++ b/test-src/webfuse/test_app.cpp @@ -3,7 +3,5 @@ TEST(app, init) { - char args0[] = "webfuse"; - char * args[] = { args0, nullptr }; - webfuse::app(1, args); + webfuse::app app; } \ No newline at end of file