From 023b595b1c8e71be2ee2864940a6d5d6b730bc24 Mon Sep 17 00:00:00 2001 From: Falk Werner Date: Fri, 6 Jan 2023 21:59:19 +0100 Subject: [PATCH] implemented filesystem provider --- src/provider_main.cpp | 203 +++++++++++++++++++++--- src/webfuse/filesystem/filesystem_i.hpp | 2 + 2 files changed, 181 insertions(+), 24 deletions(-) diff --git a/src/provider_main.cpp b/src/provider_main.cpp index c869e12..fa0d22f 100644 --- a/src/provider_main.cpp +++ b/src/provider_main.cpp @@ -2,6 +2,7 @@ #include "webfuse/version.hpp" #include +#include #include #include @@ -120,9 +121,22 @@ class filesystem: public webfuse::filesystem_i { public: explicit filesystem(std::string const & base_path) - : base_path_(base_path) { + char buffer[PATH_MAX]; + char * resolved_path = ::realpath(base_path.c_str(), buffer); + if (nullptr == resolved_path) + { + throw std::runtime_error("failed to resolve path"); + } + struct stat info; + int const rc = stat(resolved_path, &info); + if (!S_ISDIR(info.st_mode)) + { + throw std::runtime_error("path is not a directory"); + } + + base_path_ = resolved_path; } ~filesystem() override @@ -133,7 +147,6 @@ public: int access(std::string const & path, int mode) override { auto const full_path = get_full_path(path); - std::cout << "access: " << full_path << std::endl; auto const result = ::access(full_path.c_str(), mode); return (result == 0) ? 0 : -errno; @@ -142,7 +155,6 @@ public: int getattr(std::string const & path, struct stat * attr) override { auto const full_path = get_full_path(path); - std::cout << "getattr: " << full_path << std::endl; auto const result = lstat(full_path.c_str(), attr); return (result == 0) ? 0 : -errno; @@ -150,93 +162,219 @@ public: int readlink(std::string const & path, std::string & out) override { - return -ENOENT; + auto const full_path = get_full_path(path); + + char buffer[PATH_MAX]; + int const result = ::readlink(full_path.c_str(), buffer, PATH_MAX); + if ((0 <= result) && (result < PATH_MAX)) + { + buffer[result] = '\0'; + out = buffer; + } + + return (result >= 0) ? 0 : -errno; } - int symlink(std::string const & target, std::string const & linkpath) override + int symlink(std::string const & from, std::string const & to) override { - return -ENOENT; + auto const full_from = ('/' == from.at(0)) ? get_full_path(from) : from; + auto const full_to = get_full_path(to); + + int const result = ::symlink(full_from.c_str(), full_to.c_str()); + return (result == 0) ? 0 : -errno; } int link(std::string const & old_path, std::string const & new_path) override { - return -ENOENT; + auto const from = get_full_path(old_path); + auto const to = get_full_path(new_path); + + int const result = ::link(from.c_str(), to.c_str()); + return (result == 0) ? 0 : -errno; } int rename(std::string const & old_path, std::string const & new_path, int flags) override { - return -ENOENT; + auto const full_old = get_full_path(old_path); + auto const full_new = get_full_path(new_path); + + int const result = ::renameat2(-1, full_old.c_str(), -1, full_new.c_str(), flags); + return (result == 0) ? 0 : -errno; } int chmod(std::string const & path, mode_t mode) override { - return -ENOENT; + auto const full_path = get_full_path(path); + + int const result = ::chmod(full_path.c_str(), mode); + return (result == 0) ? 0 : -errno; } int chown(std::string const & path, uid_t uid, gid_t gid) override { - return -ENOENT; + auto const full_path = get_full_path(path); + + int const result = ::chown(full_path.c_str(), uid, gid); + return (result == 0) ? 0 : -errno; } int truncate(std::string const & path, uint64_t size, uint64_t handle) override { - return -ENOENT; + auto const full_path = get_full_path(path); + + int result = 0; + if (handle == webfuse::invalid_handle) + { + result = ::truncate(full_path.c_str(), size); + } + else + { + result = ::ftruncate(static_cast(handle), size); + } + + return (result == 0) ? 0 : -errno; } int fsync(std::string const & path, bool is_datasync, uint64_t handle) override { - return -ENOENT; + int result = 0; + if (handle != webfuse::invalid_handle) + { + if (!is_datasync) + { + result = ::fsync(static_cast(handle)); + } + else + { + result = ::fdatasync(static_cast(handle)); + } + } + // we do not sync files, which are not open + + return (result == 0) ? 0 : -errno; } int utimens(std::string const &path, struct timespec const tv[2], uint64_t handle) override { - return -ENOENT; + int result = 0; + if (handle == webfuse::invalid_handle) + { + auto const full_path = get_full_path(path); + result = ::utimensat(-1, full_path.c_str(), tv, 0); + } + else + { + result = ::futimens(static_cast(handle), tv); + } + + return (result == 0) ? 0 : -errno; } int open(std::string const & path, int flags, uint64_t & handle) override { - return -ENOENT; + auto const full_path = get_full_path(path); + int const fd = ::open(full_path.c_str(), flags); + if (0 <= fd) + { + handle = static_cast(fd); + } + + return (0 <= fd) ? 0 : -errno; } int mknod(std::string const & path, mode_t mode, dev_t rdev) override { - return -ENOENT; + auto const full_path = get_full_path(path); + int const result = ::mknod(full_path.c_str(), mode, rdev); + + return (result == 0) ? 0 : -errno; } int create(std::string const & path, mode_t mode, uint64_t & handle) override { - return -ENOENT; + auto const full_path = get_full_path(path); + int const fd = ::creat(full_path.c_str(), mode); + if (0 <= fd) + { + handle = static_cast(fd); + } + + return (0 <= fd) ? 0 : -errno; } int release(std::string const & path, uint64_t handle) override { - return -ENOENT; + int result = 0; + if (handle != webfuse::invalid_handle) + { + result = ::close(static_cast(handle)); + } + + return (result == 0) ? 0 : -errno; } int unlink(std::string const & path) override { - return -ENOENT; + auto const full_path = get_full_path(path); + int const result = ::unlink(full_path.c_str()); + + return (result == 0) ? 0 : -errno; } int read(std::string const & path, char * buffer, size_t buffer_size, uint64_t offset, uint64_t handle) override { - return -ENOENT; + int result = -1; + if (handle != webfuse::invalid_handle) + { + auto const full_path = get_full_path(path); + int fd = ::open(full_path.c_str(), O_RDONLY); + if (0 <= fd) + { + result = ::pread(fd, buffer, buffer_size, offset); + ::close(fd); + } + } + else + { + result = ::pread(static_cast(handle), buffer, buffer_size, offset); + } + + return (result >= 0) ? result : -errno; } int write(std::string const & path, char const * buffer, size_t buffer_size, uint64_t offset, uint64_t handle) override { - return -ENOENT; + int result = -1; + if (handle == webfuse::invalid_handle) + { + auto const full_path = get_full_path(path); + int fd = ::open(full_path.c_str(), O_WRONLY); + if (0 <= fd) + { + result = ::pwrite(fd, buffer, buffer_size, offset); + ::close(fd); + } + } + else + { + result = ::pwrite(static_cast(handle), buffer, buffer_size, offset); + + } + + return (result >= 0) ? result : -errno; } int mkdir(std::string const & path, mode_t mode) override { - return -ENOENT; + auto const full_path = get_full_path(path); + int const result = ::mkdir(full_path.c_str(), mode); + + return (result == 0) ? 0 : -errno; } int readdir(std::string const & path, std::vector & entries) override { auto const full_path = get_full_path(path); - std::cout << "readdir: " << full_path << std::endl; int result = 0; DIR * directory = opendir(full_path.c_str()); @@ -260,12 +398,18 @@ public: int rmdir(std::string const & path) override { - return -ENOENT; + auto const full_path = get_full_path(path); + int const result = ::rmdir(full_path.c_str()); + + return (result == 0) ? 0 : -errno; } int statfs(std::string const & path, struct statvfs * statistics) override { - return -ENOENT; + auto const full_path = get_full_path(path); + int const result = ::statvfs(full_path.c_str(), statistics); + + return (result == 0) ? 0 : -errno; } @@ -289,6 +433,7 @@ int main(int argc, char* argv[]) switch (ctx.cmd) { case command::run: + try { signal(SIGINT, &on_signal); signal(SIGTERM, &on_signal); @@ -307,6 +452,16 @@ int main(int argc, char* argv[]) provider.service(); } } + catch (std::exception const & ex) + { + std::cerr << "error: " << ex.what() << std::endl; + ctx.exit_code = EXIT_FAILURE; + } + catch (...) + { + std::cerr << "error: unspecified error" << std::endl; + ctx.exit_code = EXIT_FAILURE; + } break; case command::show_version: print_version(); diff --git a/src/webfuse/filesystem/filesystem_i.hpp b/src/webfuse/filesystem/filesystem_i.hpp index fe94ed8..cf2f0ce 100644 --- a/src/webfuse/filesystem/filesystem_i.hpp +++ b/src/webfuse/filesystem/filesystem_i.hpp @@ -13,6 +13,8 @@ namespace webfuse { +constexpr uint64_t const invalid_handle = static_cast(-1); + class filesystem_i { public: