From b3b8e793f901c13c3cb93a9bfc08ec2c008ce77d Mon Sep 17 00:00:00 2001 From: Antonio SJ Musumeci Date: Thu, 13 Nov 2025 20:45:52 -0600 Subject: [PATCH] Change getattr and statx to bespoke policies * Provides: slight improvement in performance as it no longer will need to find and then act on the files. * It doesn't make sense to support all original policy types. Most people used 'newest' or 'ff' and 'combine' is a better default which has same runtime as 'newest' but with better output. --- libfuse/lib/debug.cpp | 77 ++++++++------- libfuse/lib/debug.hpp | 1 + libfuse/lib/fuse_lowlevel.cpp | 2 + src/atomicsharedptr.hpp | 108 +++++++++++++++++++++ src/category.hpp | 11 --- src/config.cpp | 28 +++--- src/config.hpp | 32 +++++++ src/config_follow_symlinks.hpp | 8 +- src/config_getattr_statx.hpp | 41 ++++++++ src/error.hpp | 21 +++-- src/follow_symlinks_enum.hpp | 9 ++ src/fs_lstat.hpp | 19 +--- src/fs_stat.cpp | 0 src/fs_stat.hpp | 61 ++++++++++-- src/fs_statx.hpp | 62 ++++++++++-- src/fsproxy.cpp | 36 +++++++ src/fsproxy.hpp | 54 +++++++++++ src/func_access.hpp | 16 ++++ src/func_access_all.cpp | 31 ++++++ src/func_access_all.hpp | 19 ++++ src/func_access_base.hpp | 24 +++++ src/func_access_factory.cpp | 30 ++++++ src/func_access_factory.hpp | 13 +++ src/func_chmod.hpp | 17 ++++ src/func_chmod_all.cpp | 35 +++++++ src/func_chmod_all.hpp | 19 ++++ src/func_chmod_base.hpp | 26 +++++ src/func_chmod_factory.cpp | 30 ++++++ src/func_chmod_factory.hpp | 13 +++ src/func_chown.hpp | 18 ++++ src/func_chown_all.cpp | 36 +++++++ src/func_chown_all.hpp | 20 ++++ src/func_chown_base.hpp | 27 ++++++ src/func_chown_factory.cpp | 30 ++++++ src/func_chown_factory.hpp | 13 +++ src/func_getattr.hpp | 19 ++++ src/func_getattr_base.hpp | 35 +++++++ src/func_getattr_cdco.cpp | 74 +++++++++++++++ src/func_getattr_cdco.hpp | 21 +++++ src/func_getattr_cdfo.cpp | 78 +++++++++++++++ src/func_getattr_cdfo.hpp | 21 +++++ src/func_getattr_factory.cpp | 44 +++++++++ src/func_getattr_factory.hpp | 13 +++ src/func_getattr_ff.cpp | 44 +++++++++ src/func_getattr_ff.hpp | 23 +++++ src/func_getattr_newest.cpp | 59 ++++++++++++ src/func_getattr_newest.hpp | 21 +++++ src/func_getxattr.hpp | 19 ++++ src/func_getxattr_base.hpp | 25 +++++ src/func_getxattr_factory.cpp | 30 ++++++ src/func_getxattr_factory.hpp | 13 +++ src/func_getxattr_ff.cpp | 35 +++++++ src/func_getxattr_ff.hpp | 21 +++++ src/func_ioctl.hpp | 16 ++++ src/func_ioctl_base.hpp | 22 +++++ src/func_ioctl_factory.cpp | 30 ++++++ src/func_ioctl_factory.hpp | 13 +++ src/func_ioctl_ff.cpp | 25 +++++ src/func_ioctl_ff.hpp | 18 ++++ src/func_listxattr.hpp | 18 ++++ src/func_listxattr_base.hpp | 24 +++++ src/func_listxattr_factory.cpp | 30 ++++++ src/func_listxattr_factory.hpp | 13 +++ src/func_listxattr_ff.cpp | 53 +++++++++++ src/func_listxattr_ff.hpp | 20 ++++ src/func_open.hpp | 17 ++++ src/func_open_base.hpp | 26 +++++ src/func_open_factory.cpp | 30 ++++++ src/func_open_factory.hpp | 13 +++ src/func_open_ff.cpp | 27 ++++++ src/func_open_ff.hpp | 19 ++++ src/func_readlink.hpp | 19 ++++ src/func_readlink_base.hpp | 25 +++++ src/func_readlink_factory.cpp | 30 ++++++ src/func_readlink_factory.hpp | 13 +++ src/func_readlink_ff.cpp | 104 ++++++++++++++++++++ src/func_readlink_ff.hpp | 21 +++++ src/func_removexattr.hpp | 17 ++++ src/func_removexattr_all.cpp | 35 +++++++ src/func_removexattr_all.hpp | 19 ++++ src/func_removexattr_base.hpp | 23 +++++ src/func_removexattr_factory.cpp | 30 ++++++ src/func_removexattr_factory.hpp | 13 +++ src/func_rmdir.hpp | 16 ++++ src/func_rmdir_all.cpp | 49 ++++++++++ src/func_rmdir_all.hpp | 18 ++++ src/func_rmdir_base.hpp | 22 +++++ src/func_rmdir_factory.cpp | 30 ++++++ src/func_rmdir_factory.hpp | 13 +++ src/func_setxattr.hpp | 20 ++++ src/func_setxattr_all.cpp | 38 ++++++++ src/func_setxattr_all.hpp | 22 +++++ src/func_setxattr_base.hpp | 26 +++++ src/func_setxattr_factory.cpp | 30 ++++++ src/func_setxattr_factory.hpp | 13 +++ src/func_statx.hpp | 21 +++++ src/func_statx_base.hpp | 38 ++++++++ src/func_statx_cdco.cpp | 81 ++++++++++++++++ src/func_statx_cdco.hpp | 23 +++++ src/func_statx_cdfo.cpp | 84 +++++++++++++++++ src/func_statx_cdfo.hpp | 23 +++++ src/func_statx_factory.cpp | 44 +++++++++ src/func_statx_factory.hpp | 13 +++ src/func_statx_ff.cpp | 50 ++++++++++ src/func_statx_ff.hpp | 25 +++++ src/func_statx_newest.cpp | 66 +++++++++++++ src/func_statx_newest.hpp | 23 +++++ src/func_truncate.hpp | 17 ++++ src/func_truncate_all.cpp | 35 +++++++ src/func_truncate_all.hpp | 19 ++++ src/func_truncate_base.hpp | 23 +++++ src/func_truncate_factory.cpp | 30 ++++++ src/func_truncate_factory.hpp | 13 +++ src/func_unlink.hpp | 16 ++++ src/func_unlink_all.cpp | 34 +++++++ src/func_unlink_all.hpp | 18 ++++ src/func_unlink_base.hpp | 22 +++++ src/func_unlink_factory.cpp | 30 ++++++ src/func_unlink_factory.hpp | 13 +++ src/func_utimens.hpp | 17 ++++ src/func_utimens_all.cpp | 35 +++++++ src/func_utimens_all.hpp | 19 ++++ src/func_utimens_base.hpp | 23 +++++ src/func_utimens_factory.cpp | 30 ++++++ src/func_utimens_factory.hpp | 13 +++ src/func_wrapper.hpp | 55 +++++++++++ src/funcs.hpp | 11 --- src/fuse_access.cpp | 7 +- src/fuse_chmod.cpp | 89 +----------------- src/fuse_chmod.hpp | 2 +- src/fuse_chown.cpp | 88 ++--------------- src/fuse_getattr.cpp | 103 +------------------- src/fuse_getxattr.cpp | 74 ++++++++------- src/fuse_listxattr.cpp | 116 ++--------------------- src/fuse_readlink.cpp | 107 +-------------------- src/fuse_removexattr.cpp | 76 +-------------- src/fuse_rmdir.cpp | 80 +--------------- src/fuse_setxattr.cpp | 120 +++-------------------- src/fuse_statx_supported.icpp | 126 +++---------------------- src/fuse_truncate.cpp | 76 +-------------- src/fuse_unlink.cpp | 49 +--------- src/fuse_utimens.cpp | 77 +-------------- src/timespec_utils.hpp | 157 +++++++++++++++++++++++++++++++ src/to_cstr.hpp | 22 +++++ tests/tests.cpp | 22 ++++- 145 files changed, 3804 insertions(+), 1193 deletions(-) create mode 100644 src/atomicsharedptr.hpp create mode 100644 src/config_getattr_statx.hpp create mode 100644 src/follow_symlinks_enum.hpp create mode 100644 src/fs_stat.cpp create mode 100644 src/fsproxy.cpp create mode 100644 src/fsproxy.hpp create mode 100644 src/func_access.hpp create mode 100644 src/func_access_all.cpp create mode 100644 src/func_access_all.hpp create mode 100644 src/func_access_base.hpp create mode 100644 src/func_access_factory.cpp create mode 100644 src/func_access_factory.hpp create mode 100644 src/func_chmod.hpp create mode 100644 src/func_chmod_all.cpp create mode 100644 src/func_chmod_all.hpp create mode 100644 src/func_chmod_base.hpp create mode 100644 src/func_chmod_factory.cpp create mode 100644 src/func_chmod_factory.hpp create mode 100644 src/func_chown.hpp create mode 100644 src/func_chown_all.cpp create mode 100644 src/func_chown_all.hpp create mode 100644 src/func_chown_base.hpp create mode 100644 src/func_chown_factory.cpp create mode 100644 src/func_chown_factory.hpp create mode 100644 src/func_getattr.hpp create mode 100644 src/func_getattr_base.hpp create mode 100644 src/func_getattr_cdco.cpp create mode 100644 src/func_getattr_cdco.hpp create mode 100644 src/func_getattr_cdfo.cpp create mode 100644 src/func_getattr_cdfo.hpp create mode 100644 src/func_getattr_factory.cpp create mode 100644 src/func_getattr_factory.hpp create mode 100644 src/func_getattr_ff.cpp create mode 100644 src/func_getattr_ff.hpp create mode 100644 src/func_getattr_newest.cpp create mode 100644 src/func_getattr_newest.hpp create mode 100644 src/func_getxattr.hpp create mode 100644 src/func_getxattr_base.hpp create mode 100644 src/func_getxattr_factory.cpp create mode 100644 src/func_getxattr_factory.hpp create mode 100644 src/func_getxattr_ff.cpp create mode 100644 src/func_getxattr_ff.hpp create mode 100644 src/func_ioctl.hpp create mode 100644 src/func_ioctl_base.hpp create mode 100644 src/func_ioctl_factory.cpp create mode 100644 src/func_ioctl_factory.hpp create mode 100644 src/func_ioctl_ff.cpp create mode 100644 src/func_ioctl_ff.hpp create mode 100644 src/func_listxattr.hpp create mode 100644 src/func_listxattr_base.hpp create mode 100644 src/func_listxattr_factory.cpp create mode 100644 src/func_listxattr_factory.hpp create mode 100644 src/func_listxattr_ff.cpp create mode 100644 src/func_listxattr_ff.hpp create mode 100644 src/func_open.hpp create mode 100644 src/func_open_base.hpp create mode 100644 src/func_open_factory.cpp create mode 100644 src/func_open_factory.hpp create mode 100644 src/func_open_ff.cpp create mode 100644 src/func_open_ff.hpp create mode 100644 src/func_readlink.hpp create mode 100644 src/func_readlink_base.hpp create mode 100644 src/func_readlink_factory.cpp create mode 100644 src/func_readlink_factory.hpp create mode 100644 src/func_readlink_ff.cpp create mode 100644 src/func_readlink_ff.hpp create mode 100644 src/func_removexattr.hpp create mode 100644 src/func_removexattr_all.cpp create mode 100644 src/func_removexattr_all.hpp create mode 100644 src/func_removexattr_base.hpp create mode 100644 src/func_removexattr_factory.cpp create mode 100644 src/func_removexattr_factory.hpp create mode 100644 src/func_rmdir.hpp create mode 100644 src/func_rmdir_all.cpp create mode 100644 src/func_rmdir_all.hpp create mode 100644 src/func_rmdir_base.hpp create mode 100644 src/func_rmdir_factory.cpp create mode 100644 src/func_rmdir_factory.hpp create mode 100644 src/func_setxattr.hpp create mode 100644 src/func_setxattr_all.cpp create mode 100644 src/func_setxattr_all.hpp create mode 100644 src/func_setxattr_base.hpp create mode 100644 src/func_setxattr_factory.cpp create mode 100644 src/func_setxattr_factory.hpp create mode 100644 src/func_statx.hpp create mode 100644 src/func_statx_base.hpp create mode 100644 src/func_statx_cdco.cpp create mode 100644 src/func_statx_cdco.hpp create mode 100644 src/func_statx_cdfo.cpp create mode 100644 src/func_statx_cdfo.hpp create mode 100644 src/func_statx_factory.cpp create mode 100644 src/func_statx_factory.hpp create mode 100644 src/func_statx_ff.cpp create mode 100644 src/func_statx_ff.hpp create mode 100644 src/func_statx_newest.cpp create mode 100644 src/func_statx_newest.hpp create mode 100644 src/func_truncate.hpp create mode 100644 src/func_truncate_all.cpp create mode 100644 src/func_truncate_all.hpp create mode 100644 src/func_truncate_base.hpp create mode 100644 src/func_truncate_factory.cpp create mode 100644 src/func_truncate_factory.hpp create mode 100644 src/func_unlink.hpp create mode 100644 src/func_unlink_all.cpp create mode 100644 src/func_unlink_all.hpp create mode 100644 src/func_unlink_base.hpp create mode 100644 src/func_unlink_factory.cpp create mode 100644 src/func_unlink_factory.hpp create mode 100644 src/func_utimens.hpp create mode 100644 src/func_utimens_all.cpp create mode 100644 src/func_utimens_all.hpp create mode 100644 src/func_utimens_base.hpp create mode 100644 src/func_utimens_factory.cpp create mode 100644 src/func_utimens_factory.hpp create mode 100644 src/func_wrapper.hpp create mode 100644 src/timespec_utils.hpp create mode 100644 src/to_cstr.hpp diff --git a/libfuse/lib/debug.cpp b/libfuse/lib/debug.cpp index b82bce98..2ea2689f 100644 --- a/libfuse/lib/debug.cpp +++ b/libfuse/lib/debug.cpp @@ -275,7 +275,9 @@ static void debug_open_flags(const uint32_t flags_) { - fmt::print("{}, ",open_accmode_to_str(flags_)); + fmt::print(g_OUTPUT, + "{}, ", + open_accmode_to_str(flags_)); for(size_t i = 0; i < (sizeof(flags_) * 8); i++) { const char *str; @@ -287,7 +289,7 @@ debug_open_flags(const uint32_t flags_) if(str == NULL) continue; - fmt::print("{}, ",str); + fmt::print(g_OUTPUT,"{}, ",str); } } @@ -315,7 +317,7 @@ fuse_fopen_flag_to_str(const uint32_t offset_) void debug_fuse_open_out(const struct fuse_open_out *arg_) { - fmt::print(stderr, + fmt::print(g_OUTPUT, "fuse_open_out:" " fh=0x{:#08x};" " open_flags=0x{:#04x} (", @@ -332,9 +334,9 @@ debug_fuse_open_out(const struct fuse_open_out *arg_) if(str == NULL) continue; - fmt::print(stderr,"{},",str); + fmt::print(g_OUTPUT,"{},",str); } - fmt::print(stderr,");\n"); + fmt::print(g_OUTPUT,");\n"); } static @@ -445,7 +447,7 @@ debug_fuse_mkdir_in(const void *arg_) "fuse_mkdir_in:" " mode={:o};" " umask={:o};" - " name=%s;" + " name={};" "\n" , arg->mode, @@ -461,7 +463,7 @@ debug_fuse_unlink(const void *arg_) fmt::print(g_OUTPUT, "fuse_unlink:" - " name=%s;" + " name={};" "\n" , name); @@ -475,7 +477,7 @@ debug_fuse_rmdir(const void *arg_) fmt::print(g_OUTPUT, "fuse_mkdir:" - " name=%s;" + " name={};" "\n" , name); @@ -493,8 +495,8 @@ debug_fuse_symlink(const void *arg_) fmt::print(g_OUTPUT, "fuse_mkdir:" - " linkname=%s;" - " name=%s;" + " linkname={};" + " name={};" "\n" , linkname, @@ -514,9 +516,9 @@ debug_fuse_rename_in(const void *arg_) fmt::print(g_OUTPUT, "fuse_rename_in:" - " oldname=%s;" + " oldname={};" " newdir={};" - " newname=%s;" + " newname={};" "\n" , oldname, @@ -536,7 +538,7 @@ debug_fuse_link_in(const void *arg_) fmt::print(g_OUTPUT, "fuse_link_in:" " oldnodeid={};" - " name=%s;" + " name={};" "\n" , arg->oldnodeid, @@ -556,7 +558,7 @@ debug_fuse_create_in(const void *arg_) "fuse_create_in:" " mode={:o};" " umask={:o};" - " name=%s;" + " name={};" " flags=0x%X (", arg->mode, arg->umask, @@ -574,7 +576,7 @@ debug_fuse_open_in(const void *arg_) fmt::print(g_OUTPUT, "fuse_open_in:" - " flags=0x%08X (", + " flags=0x{:08X} (", arg->flags); debug_open_flags(arg->flags); fmt::print(g_OUTPUT,");\n"); @@ -639,7 +641,7 @@ debug_fuse_write_in(const void *arg_) if(str == NULL) continue; - fmt::print(g_OUTPUT,"%s,",str); + fmt::print(g_OUTPUT,"{},",str); } fmt::print(g_OUTPUT,");\n"); } @@ -712,8 +714,8 @@ debug_fuse_setxattr_in(const void *arg_) "fuse_setxattr_in:" " size={};" " flags=0x%X;" - " name=%s;" - " value=%s;" + " name={};" + " value={};" "\n" , arg->size, @@ -734,7 +736,7 @@ debug_fuse_getxattr_in(const void *arg_) fmt::print(g_OUTPUT, "fuse_getxattr_in:" " size={};" - " name=%s;" + " name={};" "\n" , arg->size, @@ -763,7 +765,7 @@ debug_fuse_removexattr(const void *arg_) fmt::print(g_OUTPUT, "fuse_removexattr:" - " name=%s;" + " name={};" "\n" , name); @@ -816,7 +818,7 @@ debug_fuse_init_in(const struct fuse_init_in *arg_) if(str == NULL) continue; - fmt::print(g_OUTPUT,"%s, ",str); + fmt::print(g_OUTPUT,"{}, ",str); } fmt::print(g_OUTPUT,")\n"); } @@ -932,7 +934,7 @@ debug_fuse_init_out(const uint64_t unique_, if(str == NULL) continue; - fmt::print(g_OUTPUT,"%s, ",str); + fmt::print(g_OUTPUT,"{}, ",str); } fmt::print(g_OUTPUT, @@ -1100,13 +1102,14 @@ opcode_name(enum fuse_opcode op_) { static const char *names[] = { - "INVALID", + "INVALID0", "LOOKUP", "FORGET", "GETATTR", "SETATTR", "READLINK", "SYMLINK", + "INVALID1", "MKNOD", "MKDIR", "UNLINK", @@ -1118,6 +1121,7 @@ opcode_name(enum fuse_opcode op_) "WRITE", "STATFS", "RELEASE", + "INVALID3", "FSYNC", "SETXATTR", "GETXATTR", @@ -1147,7 +1151,10 @@ opcode_name(enum fuse_opcode op_) "LSEEK", "COPY_FILE_RANGE", "SETUPMAPPING", - "REMOVEMAPPING" + "REMOVEMAPPING", + "SYNCFS", + "TMPFILE", + "STATX" }; if(op_ >= (sizeof(names) / sizeof(names[0]))) @@ -1161,9 +1168,9 @@ debug_fuse_in_header(const struct fuse_in_header *hdr_) { const void *arg = &hdr_[1]; - fmt::print(stderr, - "unique=0x%016" PRIx64 ";" - " opcode=%s ({});" + fmt::print(g_OUTPUT, + "unique=0x{:016x};" + " opcode={} ({});" " nodeid={};" " uid={};" " gid={};" @@ -1265,8 +1272,14 @@ debug_fuse_in_header(const struct fuse_in_header *hdr_) case FUSE_INTERRUPT: debug_fuse_interrupt_in(arg); break; + case FUSE_SYNCFS: + break; + case FUSE_TMPFILE: + break; + case FUSE_STATX: + break; default: - fmt::print(g_OUTPUT,"FIXME\n"); + fmt::print(g_OUTPUT,"FIXME: {}\n",hdr_->opcode); break; } } @@ -1275,10 +1288,10 @@ void debug_fuse_out_header(const struct fuse_out_header *hdr_) { fmt::print(g_OUTPUT, - "unique=0x%016" PRIx64 ";" + "unique=0x{:016x};" " opcode=RESPONSE;" - " error=%d (%s);" - " len={};" + " error={} ({});" + " len={};\n" , hdr_->unique, hdr_->error, @@ -1312,7 +1325,7 @@ debug_fuse_readlink(const uint64_t unique_, " opcode=RESPONSE;" " error=0 (Success);" " len={}; || " - "readlink: linkname=%s" + "readlink: linkname={}" "\n" , unique_, diff --git a/libfuse/lib/debug.hpp b/libfuse/lib/debug.hpp index f1ce235e..cbd350bf 100644 --- a/libfuse/lib/debug.hpp +++ b/libfuse/lib/debug.hpp @@ -51,6 +51,7 @@ void debug_fuse_lk_out(const uint64_t unique, void debug_fuse_bmap_out(const uint64_t unique, const struct fuse_bmap_out *arg); void debug_fuse_in_header(const struct fuse_in_header *hdr); +void debug_fuse_out_header(const struct fuse_out_header *hdr); std::string fuse_debug_init_flag_name(const uint64_t); diff --git a/libfuse/lib/fuse_lowlevel.cpp b/libfuse/lib/fuse_lowlevel.cpp index ad0df588..f362cb47 100644 --- a/libfuse/lib/fuse_lowlevel.cpp +++ b/libfuse/lib/fuse_lowlevel.cpp @@ -1797,6 +1797,8 @@ fuse_ll_buf_process_read(struct fuse_session *se_, if(fuse_ll_funcs[in->opcode] == NULL) goto reply_err; + // debug_fuse_in_header(in); + fuse_ll_funcs[in->opcode](req, in); return; diff --git a/src/atomicsharedptr.hpp b/src/atomicsharedptr.hpp new file mode 100644 index 00000000..ab175a0c --- /dev/null +++ b/src/atomicsharedptr.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include +#include + +template +class AtomicSharedPtr +{ +private: + std::shared_ptr _ptr; + +public: + AtomicSharedPtr() = default; + + explicit + AtomicSharedPtr(std::shared_ptr ptr_) + : _ptr(std::move(ptr_)) + { + } + + template + explicit + AtomicSharedPtr(Args&&... args) + : _ptr(std::make_shared(std::forward(args)...)) + { + } + + AtomicSharedPtr(const AtomicSharedPtr&) = delete; + AtomicSharedPtr& operator=(const AtomicSharedPtr&) = delete; + + AtomicSharedPtr(AtomicSharedPtr&& other_) noexcept + : _ptr(std::move(other_._ptr)) + { + } + + AtomicSharedPtr& + operator=(AtomicSharedPtr&& other_) noexcept + { + if(this != &other_) + _ptr = std::move(other_._ptr); + + return *this; + } + + std::shared_ptr + load() const + { + return std::atomic_load(&_ptr); + } + + void + store(std::shared_ptr desired_) + { + std::atomic_store(&_ptr, std::move(desired_)); + } + + std::shared_ptr + exchange(std::shared_ptr desired_) + { + return std::atomic_exchange(&_ptr, std::move(desired_)); + } + + bool + compare_exchange_strong(std::shared_ptr& expected_, + std::shared_ptr desired_) + { + return std::atomic_compare_exchange_strong(&_ptr, + &expected_, + std::move(desired_)); + } + + bool + compare_exchange_weak(std::shared_ptr& expected_, + std::shared_ptr desired_) + { + return std::atomic_compare_exchange_weak(&_ptr, + &expected_, + std::move(desired_)); + } + + bool + is_null() const + { + return !std::atomic_load(&_ptr); + } + + void + reset() + { + std::atomic_store(&_ptr, std::shared_ptr()); + } + + T* + get() const + { + return std::atomic_load(&_ptr).get(); + } + + template + auto + operator()(Args&&... args) const -> + decltype(std::declval()(std::forward(args)...)) + { + auto ptr = load(); + + return (*ptr)(std::forward(args)...); + } +}; diff --git a/src/category.hpp b/src/category.hpp index da530103..5a23c7fa 100644 --- a/src/category.hpp +++ b/src/category.hpp @@ -42,16 +42,8 @@ namespace Category public: Action(Funcs &funcs_) { - funcs.push_back(&funcs_.chmod); - funcs.push_back(&funcs_.chown); funcs.push_back(&funcs_.link); - funcs.push_back(&funcs_.removexattr); funcs.push_back(&funcs_.rename); - funcs.push_back(&funcs_.rmdir); - funcs.push_back(&funcs_.setxattr); - funcs.push_back(&funcs_.truncate); - funcs.push_back(&funcs_.unlink); - funcs.push_back(&funcs_.utimens); } }; @@ -78,12 +70,9 @@ namespace Category public: Search(Funcs &funcs_) { - funcs.push_back(&funcs_.access); funcs.push_back(&funcs_.getattr); - funcs.push_back(&funcs_.getxattr); funcs.push_back(&funcs_.listxattr); funcs.push_back(&funcs_.open); - funcs.push_back(&funcs_.readlink); } }; } diff --git a/src/config.cpp b/src/config.cpp index 691dd2bc..2eb6cb30 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -138,6 +138,7 @@ Config::Config() _congestion_threshold(fuse_cfg.congestion_threshold), _debug(fuse_cfg.debug), + _getattr_statx(getattr,statx), _gid(fuse_cfg.gid), _max_background(fuse_cfg.max_background), _mount(mountpoint), @@ -225,27 +226,28 @@ Config::Config() _map["flush-on-close"] = &flushonclose; _map["follow-symlinks"] = &follow_symlinks; _map["fsname"] = &fsname; - _map["func.access"] = &func.access; - _map["func.chmod"] = &func.chmod; - _map["func.chown"] = &func.chown; + _map["func.access"] = &access; + _map["func.chmod"] = &chmod; + _map["func.chown"] = &chown; _map["func.create"] = &func.create; - _map["func.getattr"] = &func.getattr; - _map["func.getxattr"] = &func.getxattr; + _map["func.getattr"] = &_getattr_statx; + _map["func.getxattr"] = &getxattr; _map["func.link"] = &func.link; - _map["func.listxattr"] = &func.listxattr; + _map["func.listxattr"] = &listxattr; _map["func.mkdir"] = &func.mkdir; _map["func.mknod"] = &func.mknod; _map["func.open"] = &func.open; _map["func.readdir"] = &readdir; - _map["func.readlink"] = &func.readlink; - _map["func.removexattr"] = &func.removexattr; + _map["func.readlink"] = &readlink; + _map["func.removexattr"] = &removexattr; _map["func.rename"] = &func.rename; - _map["func.rmdir"] = &func.rmdir; - _map["func.setxattr"] = &func.setxattr; + _map["func.rmdir"] = &rmdir; + _map["func.setxattr"] = &setxattr; + _map["func.statx"] = &_getattr_statx; _map["func.symlink"] = &func.symlink; - _map["func.truncate"] = &func.truncate; - _map["func.unlink"] = &func.unlink; - _map["func.utimens"] = &func.utimens; + _map["func.truncate"] = &truncate; + _map["func.unlink"] = &unlink; + _map["func.utimens"] = &utimens; _map["fuse-msg-size"] = &fuse_msg_size; _map["gid"] = &_gid; _map["gid-cache.expire-timeout"] = &_dummy; diff --git a/src/config.hpp b/src/config.hpp index c16e46d3..938fe7fd 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -16,12 +16,28 @@ #pragma once +#include "func_access.hpp" +#include "func_chmod.hpp" +#include "func_chown.hpp" +#include "func_getattr.hpp" +#include "func_getxattr.hpp" +#include "func_listxattr.hpp" +#include "func_readlink.hpp" +#include "func_removexattr.hpp" +#include "func_rmdir.hpp" +#include "func_setxattr.hpp" +#include "func_statx.hpp" +#include "func_truncate.hpp" +#include "func_unlink.hpp" +#include "func_utimens.hpp" + #include "branches.hpp" #include "category.hpp" #include "config_cachefiles.hpp" #include "config_dummy.hpp" #include "config_flushonclose.hpp" #include "config_follow_symlinks.hpp" +#include "config_getattr_statx.hpp" #include "config_inodecalc.hpp" #include "config_link_exdev.hpp" #include "config_log_metrics.hpp" @@ -108,6 +124,21 @@ public: Config& operator=(const Config&); public: + Func2::Access access{"all"}; + Func2::Chmod chmod{"all"}; + Func2::Chown chown{"all"}; + Func2::GetAttr getattr{"cdfo"}; + Func2::Getxattr getxattr{"ff"}; + Func2::Listxattr listxattr{"ff"}; + Func2::Readlink readlink{"ff"}; + Func2::Removexattr removexattr{"all"}; + Func2::Rmdir rmdir{"all"}; + Func2::Setxattr setxattr{"all"}; + Func2::Statx statx{"cdfo"}; + Func2::Truncate truncate{"all"}; + Func2::Unlink unlink{"all"}; + Func2::Utimens utimens{"all"}; + ConfigBOOL allow_idmap; ConfigBOOL async_read; Branches branches; @@ -171,6 +202,7 @@ private: TFSRef _congestion_threshold; TFSRef _debug; CfgDummy _dummy; + ConfigGetAttrStatx _getattr_statx; TFSRef _gid; TFSRef _max_background; TFSRef _mount; diff --git a/src/config_follow_symlinks.hpp b/src/config_follow_symlinks.hpp index 1ebbdecf..a6df2bce 100644 --- a/src/config_follow_symlinks.hpp +++ b/src/config_follow_symlinks.hpp @@ -19,12 +19,6 @@ #pragma once #include "enum.hpp" +#include "follow_symlinks_enum.hpp" -enum class FollowSymlinksEnum - { - NEVER, - DIRECTORY, - REGULAR, - ALL - }; typedef Enum FollowSymlinks; diff --git a/src/config_getattr_statx.hpp b/src/config_getattr_statx.hpp new file mode 100644 index 00000000..67db24de --- /dev/null +++ b/src/config_getattr_statx.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include "config.hpp" +#include "tofrom_string.hpp" + +class ConfigGetAttrStatx : public ToFromString +{ +private: + Func2::GetAttr &_getattr; + Func2::Statx &_statx; + +public: + ConfigGetAttrStatx() = delete; + ConfigGetAttrStatx(Func2::GetAttr &getattr_, + Func2::Statx &statx_) + : _getattr(getattr_), + _statx(statx_) + { + } + + std::string + to_string() const + { + return _getattr.to_string(); + } + + int + from_string(const std::string_view str_) + { + int rv; + + rv = _getattr.from_string(str_); + if(rv < 0) + return rv; + + rv = _statx.from_string(str_); + assert(rv == 0); + + return rv; + } +}; diff --git a/src/error.hpp b/src/error.hpp index 9e496cd9..199f01d9 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -15,27 +15,34 @@ public: { } - operator int() + operator int() const { - return (_err.has_value() ? _err.value() : -ENOENT); + return (_err.has_value() ? _err.value() : 0); } + // A rough heuristic for prioritizing errors. Success always + // overrides failures. ENOENT is lowest errno priority, then EROFS + // (which can be set due to branch mode = RO) then any other error. Err& - operator=(int v_) + operator=(int new_err_) { if(!_err.has_value()) - _err = ((v_ >= 0) ? 0 : v_); - else if(v_ >= 0) + _err = ((new_err_ >= 0) ? 0 : new_err_); + else if(new_err_ >= 0) _err = 0; + else if(_err == -ENOENT) + _err = new_err_; + else if((_err == -EROFS) && (new_err_ != -ENOENT)) + _err = new_err_; return *this; } bool - operator==(int v_) + operator==(int other_) { if(_err.has_value()) - return (_err.value() == v_); + return (_err.value() == other_); return false; } }; diff --git a/src/follow_symlinks_enum.hpp b/src/follow_symlinks_enum.hpp new file mode 100644 index 00000000..c708b898 --- /dev/null +++ b/src/follow_symlinks_enum.hpp @@ -0,0 +1,9 @@ +#pragma once + +enum class FollowSymlinksEnum + { + NEVER, + DIRECTORY, + REGULAR, + ALL + }; diff --git a/src/fs_lstat.hpp b/src/fs_lstat.hpp index 574fd80b..ece50c9c 100644 --- a/src/fs_lstat.hpp +++ b/src/fs_lstat.hpp @@ -19,8 +19,7 @@ #pragma once #include "to_neg_errno.hpp" - -#include +#include "to_cstr.hpp" #include #include @@ -29,25 +28,17 @@ namespace fs { + template static inline int - lstat(const char *path_, - struct stat *st_) + lstat(const PathType &path_, + struct stat *st_) { int rv; - rv = ::lstat(path_,st_); + rv = ::lstat(to_cstr(path_),st_); return ::to_neg_errno(rv); } - - static - inline - int - lstat(const std::string &path_, - struct stat *st_) - { - return fs::lstat(path_.c_str(),st_); - } } diff --git a/src/fs_stat.cpp b/src/fs_stat.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/fs_stat.hpp b/src/fs_stat.hpp index 0e85f7f3..c3e60c98 100644 --- a/src/fs_stat.hpp +++ b/src/fs_stat.hpp @@ -18,7 +18,10 @@ #pragma once +#include "follow_symlinks_enum.hpp" #include "to_neg_errno.hpp" +#include "to_cstr.hpp" +#include "fs_lstat.hpp" #include @@ -29,25 +32,71 @@ namespace fs { + template static inline int - stat(const char *path_, - struct stat *st_) + stat(const PathType &path_, + struct stat *st_) { int rv; - rv = ::stat(path_,st_); + rv = ::stat(to_cstr(path_),st_); return ::to_neg_errno(rv); } + template static inline int - stat(const std::string &path_, - struct stat *st_) + stat(const PathType &path_, + struct stat *st_, + FollowSymlinksEnum follow_) { - return fs::stat(path_.c_str(),st_); + int rv; + + switch(follow_) + { + default: + case FollowSymlinksEnum::NEVER: + rv = fs::lstat(path_,st_); + return rv; + case FollowSymlinksEnum::DIRECTORY: + rv = fs::lstat(path_,st_); + if((rv >= 0) && S_ISLNK(st_->st_mode)) + { + struct stat st; + + rv = fs::stat(path_,&st); + if(rv < 0) + return rv; + + if(S_ISDIR(st.st_mode)) + *st_ = st; + } + return rv; + case FollowSymlinksEnum::REGULAR: + rv = fs::lstat(path_,st_); + if((rv >= 0) && S_ISLNK(st_->st_mode)) + { + struct stat st; + + rv = fs::stat(path_,&st); + if(rv < 0) + return rv; + + if(S_ISREG(st.st_mode)) + *st_ = st; + } + return rv; + case FollowSymlinksEnum::ALL: + rv = fs::stat(path_,st_); + if(rv < 0) + rv = fs::lstat(path_,st_); + return rv; + } + + return -ENOENT; } } diff --git a/src/fs_statx.hpp b/src/fs_statx.hpp index 6c0365b0..d7a2358f 100644 --- a/src/fs_statx.hpp +++ b/src/fs_statx.hpp @@ -1,5 +1,7 @@ #pragma once +#include "follow_symlinks_enum.hpp" +#include "to_cstr.hpp" #include "to_neg_errno.hpp" #include "fuse_kernel.h" @@ -15,13 +17,15 @@ #include "supported_statx.hpp" + namespace fs { + template static inline int statx(const int dirfd_, - const char *pathname_, + const PathType &pathname_, const int flags_, const unsigned int mask_, struct fuse_statx *st_) @@ -30,7 +34,7 @@ namespace fs int rv; rv = ::statx(dirfd_, - pathname_, + to_cstr(pathname_), flags_, mask_, (struct statx*)st_); @@ -41,19 +45,59 @@ namespace fs #endif } + template static inline int statx(const int dirfd_, - const std::string &pathname_, + const PathType &pathname_, const int flags_, const unsigned int mask_, - struct fuse_statx *st_) + struct fuse_statx *st_, + FollowSymlinksEnum followsymlinks_) { - return fs::statx(dirfd_, - pathname_.c_str(), - flags_, - mask_, - st_); + int rv; + + switch(followsymlinks_) + { + case FollowSymlinksEnum::NEVER: + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); + return rv; + case FollowSymlinksEnum::DIRECTORY: + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); + if((rv >= 0) && S_ISLNK(st_->mode)) + { + struct fuse_statx st; + + rv = fs::statx(AT_FDCWD,pathname_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st); + if(rv < 0) + return rv; + + if(S_ISDIR(st.mode)) + *st_ = st; + } + return rv; + case FollowSymlinksEnum::REGULAR: + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); + if((rv >= 0) && S_ISLNK(st_->mode)) + { + struct fuse_statx st; + + rv = fs::statx(AT_FDCWD,pathname_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st); + if(rv < 0) + return rv; + + if(S_ISREG(st.mode)) + *st_ = st; + } + return rv; + case FollowSymlinksEnum::ALL: + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_FOLLOW,mask_,st_); + if(rv < 0) + rv = fs::statx(AT_FDCWD,pathname_,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); + return rv; + } + + return -ENOENT; } } diff --git a/src/fsproxy.cpp b/src/fsproxy.cpp new file mode 100644 index 00000000..aa4d3716 --- /dev/null +++ b/src/fsproxy.cpp @@ -0,0 +1,36 @@ +#include "fsproxy.hpp" + +#include "fs_close.hpp" + +int +FSProxy::_spawn_proxy_if_needed(const uid_t uid_, + const gid_t gid_) +{ + int rv; + FSProxy::Process process; + + if(_proxies.count({uid_,gid_})) + return 0; + + rv = pipe(process.req_pipe); + if(rv == -1) + return rv; + rv = pipe(process.res_pipe); + if(rv == -1) + return rv; + + process.pid = fork(); + if(process.pid != 0) + { + fs::close(process.req_pipe[1]); + fs::close(process.res_pipe[0]); + // listen on req in loop for instructions + return 0; + } + + fs::close(process.req_pipe[0]); + fs::close(process.res_pipe[1]); + _proxies[UGID{uid_,gid_}] = process; + + return 0; +} diff --git a/src/fsproxy.hpp b/src/fsproxy.hpp new file mode 100644 index 00000000..95043769 --- /dev/null +++ b/src/fsproxy.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include + +#include +#include + +class FSProxy +{ +public: + struct UGID + { + bool + operator==(const UGID &other_) const + { + return ((uid == other_.uid) && + (gid == other_.gid)); + } + + uid_t uid; + gid_t gid; + }; + + struct UGIDHash + { + size_t + operator()(const UGID &key_) const + { + size_t h0 = std::hash{}(key_.uid); + size_t h1 = std::hash{}(key_.gid); + + return (h0 ^ (h1 << 1)); + } + }; + + struct Process + { + int pid; + int req_pipe[2]; + int res_pipe[2]; + }; + +public: + int create(uid_t uid, + gid_t gid, + const char *pathname, + mode_t mode); + +private: + int _spawn_proxy_if_needed(uid_t,gid_t); + +private: + std::unordered_map _proxies; +}; diff --git a/src/func_access.hpp b/src/func_access.hpp new file mode 100644 index 00000000..524b32a4 --- /dev/null +++ b/src/func_access.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "func_access_base.hpp" +#include "func_access_factory.hpp" + +#include "func_wrapper.hpp" + +namespace Func2 +{ + using Access = FuncWrapper; +} diff --git a/src/func_access_all.cpp b/src/func_access_all.cpp new file mode 100644 index 00000000..b5f5561a --- /dev/null +++ b/src/func_access_all.cpp @@ -0,0 +1,31 @@ +#include "func_access_all.hpp" + +#include "error.hpp" +#include "fs_eaccess.hpp" + + +std::string_view +Func2::AccessAll::name() const +{ + return "all"; +} + +int +Func2::AccessAll::operator()(const Branches &branches_, + const fs::path &fusepath_, + const int mode_) +{ + int rv; + fs::path fullpath; + + for(const auto &branch : branches_) + { + fullpath = branch.path / fusepath_; + + rv = fs::eaccess(fullpath,mode_); + if(rv < 0) + return rv; + } + + return 0; +} diff --git a/src/func_access_all.hpp b/src/func_access_all.hpp new file mode 100644 index 00000000..d8a90349 --- /dev/null +++ b/src/func_access_all.hpp @@ -0,0 +1,19 @@ +#include "func_access_base.hpp" + +namespace Func2 +{ + class AccessAll : public AccessBase + { + public: + AccessAll() {} + ~AccessAll() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const int mode); + }; +} diff --git a/src/func_access_base.hpp b/src/func_access_base.hpp new file mode 100644 index 00000000..0be5ee2b --- /dev/null +++ b/src/func_access_base.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + + +namespace Func2 +{ + class AccessBase + { + public: + AccessBase() {} + ~AccessBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const int mode) = 0; + }; +} diff --git a/src/func_access_factory.cpp b/src/func_access_factory.cpp new file mode 100644 index 00000000..39e7fd23 --- /dev/null +++ b/src/func_access_factory.cpp @@ -0,0 +1,30 @@ +#include "func_access_factory.hpp" + +#include "func_access_all.hpp" + +#include "policies.hpp" + + +bool +Func2::AccessFactory::valid(const std::string str_) +{ + if(str_ == "all") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::AccessFactory::make(const std::string_view str_) +{ + if(str_ == "all") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_access_factory.hpp b/src/func_access_factory.hpp new file mode 100644 index 00000000..786592a5 --- /dev/null +++ b/src/func_access_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_access_base.hpp" + +namespace Func2 +{ + class AccessFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_chmod.hpp b/src/func_chmod.hpp new file mode 100644 index 00000000..03894ece --- /dev/null +++ b/src/func_chmod.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "func_chmod_base.hpp" +#include "func_chmod_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Chmod = FuncWrapper; +} diff --git a/src/func_chmod_all.cpp b/src/func_chmod_all.cpp new file mode 100644 index 00000000..1b701e1a --- /dev/null +++ b/src/func_chmod_all.cpp @@ -0,0 +1,35 @@ +#include "func_chmod_all.hpp" + +#include "error.hpp" +#include "fs_lchmod.hpp" + + +std::string_view +Func2::ChmodAll::name() const +{ + return "all"; +} + +int +Func2::ChmodAll::operator()(const Branches &branches_, + const fs::path &fusepath_, + const mode_t mode_) +{ + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + if(branch.ro()) + { + err = -EROFS; + continue; + } + + fullpath = branch.path / fusepath_; + + err = fs::lchmod(fullpath,mode_); + } + + return err; +} diff --git a/src/func_chmod_all.hpp b/src/func_chmod_all.hpp new file mode 100644 index 00000000..eb3fe9cc --- /dev/null +++ b/src/func_chmod_all.hpp @@ -0,0 +1,19 @@ +#include "func_chmod_base.hpp" + +namespace Func2 +{ + class ChmodAll : public ChmodBase + { + public: + ChmodAll() {} + ~ChmodAll() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const mode_t mode); + }; +} diff --git a/src/func_chmod_base.hpp b/src/func_chmod_base.hpp new file mode 100644 index 00000000..4c350bc6 --- /dev/null +++ b/src/func_chmod_base.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +#include + + +namespace Func2 +{ + class ChmodBase + { + public: + ChmodBase() {} + ~ChmodBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const mode_t mode) = 0; + }; +} diff --git a/src/func_chmod_factory.cpp b/src/func_chmod_factory.cpp new file mode 100644 index 00000000..2b6536fd --- /dev/null +++ b/src/func_chmod_factory.cpp @@ -0,0 +1,30 @@ +#include "func_chmod_factory.hpp" + +#include "func_chmod_all.hpp" + +#include "policies.hpp" + + +bool +Func2::ChmodFactory::valid(const std::string str_) +{ + if(str_ == "all") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::ChmodFactory::make(const std::string_view str_) +{ + if(str_ == "all") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_chmod_factory.hpp b/src/func_chmod_factory.hpp new file mode 100644 index 00000000..4d6ad154 --- /dev/null +++ b/src/func_chmod_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_chmod_base.hpp" + +namespace Func2 +{ + class ChmodFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_chown.hpp b/src/func_chown.hpp new file mode 100644 index 00000000..7a63c04b --- /dev/null +++ b/src/func_chown.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "func_chown_base.hpp" +#include "func_chown_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Chown = FuncWrapper; +} diff --git a/src/func_chown_all.cpp b/src/func_chown_all.cpp new file mode 100644 index 00000000..2a476afd --- /dev/null +++ b/src/func_chown_all.cpp @@ -0,0 +1,36 @@ +#include "func_chown_all.hpp" + +#include "error.hpp" +#include "fs_lchown.hpp" + + +std::string_view +Func2::ChownAll::name() const +{ + return "all"; +} + +int +Func2::ChownAll::operator()(const Branches &branches_, + const fs::path &fusepath_, + const uid_t uid_, + const gid_t gid_) +{ + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + if(branch.ro()) + { + err = -EROFS; + continue; + } + + fullpath = branch.path / fusepath_; + + err = fs::lchown(fullpath,uid_,gid_); + } + + return err; +} diff --git a/src/func_chown_all.hpp b/src/func_chown_all.hpp new file mode 100644 index 00000000..cd5516d7 --- /dev/null +++ b/src/func_chown_all.hpp @@ -0,0 +1,20 @@ +#include "func_chown_base.hpp" + +namespace Func2 +{ + class ChownAll : public ChownBase + { + public: + ChownAll() {} + ~ChownAll() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const uid_t uid, + const gid_t gid); + }; +} diff --git a/src/func_chown_base.hpp b/src/func_chown_base.hpp new file mode 100644 index 00000000..8ad6ad3c --- /dev/null +++ b/src/func_chown_base.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +#include + + +namespace Func2 +{ + class ChownBase + { + public: + ChownBase() {} + ~ChownBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const uid_t uid, + const gid_t gid) = 0; + }; +} diff --git a/src/func_chown_factory.cpp b/src/func_chown_factory.cpp new file mode 100644 index 00000000..9c13e5c9 --- /dev/null +++ b/src/func_chown_factory.cpp @@ -0,0 +1,30 @@ +#include "func_chown_factory.hpp" + +#include "func_chown_all.hpp" + +#include "policies.hpp" + + +bool +Func2::ChownFactory::valid(const std::string str_) +{ + if(str_ == "all") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::ChownFactory::make(const std::string_view str_) +{ + if(str_ == "all") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_chown_factory.hpp b/src/func_chown_factory.hpp new file mode 100644 index 00000000..72529519 --- /dev/null +++ b/src/func_chown_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_chown_base.hpp" + +namespace Func2 +{ + class ChownFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_getattr.hpp b/src/func_getattr.hpp new file mode 100644 index 00000000..99a130ae --- /dev/null +++ b/src/func_getattr.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "func_getattr_base.hpp" +#include "func_getattr_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using GetAttr = FuncWrapper; +} diff --git a/src/func_getattr_base.hpp b/src/func_getattr_base.hpp new file mode 100644 index 00000000..bdbcd439 --- /dev/null +++ b/src/func_getattr_base.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "follow_symlinks_enum.hpp" + +#include "fs_path.hpp" +#include "branches.hpp" +#include "base_types.h" + +#include "fuse.h" + +#include + +#include +#include +#include + +namespace Func2 +{ + class GetAttrBase + { + public: + GetAttrBase() {} + ~GetAttrBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + struct stat *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout) = 0; + }; +} diff --git a/src/func_getattr_cdco.cpp b/src/func_getattr_cdco.cpp new file mode 100644 index 00000000..bdf9c485 --- /dev/null +++ b/src/func_getattr_cdco.cpp @@ -0,0 +1,74 @@ +#include "func_getattr_cdco.hpp" + +#include "error.hpp" +#include "fs_inode.hpp" +#include "fs_stat.hpp" +#include "symlinkify.hpp" +#include "timespec_utils.hpp" + + +std::string_view +Func2::GetAttrCDCO::name() const +{ + return "cdco"; +} + +int +Func2::GetAttrCDCO::operator()(const Branches &branches_, + const fs::path &fusepath_, + struct stat *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + Err err; + fs::path fullpath; + const Branch *first_branch; + + first_branch = nullptr; + for(const auto &branch : branches_) + { + struct stat tmp_st; + + fullpath = branch.path / fusepath_; + + err = rv = fs::stat(fullpath,&tmp_st,follow_symlinks_); + if(rv < 0) + continue; + + if(not first_branch) + { + *st_ = tmp_st; + first_branch = &branch; + continue; + } + + // This upgrades the uid:gid because mergerfs now does most + // file interaction as root and relies on `default_permissions` + // to manage permissions. Want to ensure that root owned files + // can't be changed so we treat them all as root owned. + if(tmp_st.st_uid == 0) + st_->st_uid = 0; + if(tmp_st.st_gid == 0) + st_->st_gid = 0; + st_->st_atim = TimeSpec::newest(st_->st_atim,tmp_st.st_atim); + st_->st_ctim = TimeSpec::newest(st_->st_ctim,tmp_st.st_ctim); + st_->st_mtim = TimeSpec::newest(st_->st_mtim,tmp_st.st_mtim); + st_->st_nlink += tmp_st.st_nlink; + } + + if(!first_branch) + return err; + + if(symlinkify_timeout_ >= 0) + { + fullpath = first_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(first_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_getattr_cdco.hpp b/src/func_getattr_cdco.hpp new file mode 100644 index 00000000..7bb22805 --- /dev/null +++ b/src/func_getattr_cdco.hpp @@ -0,0 +1,21 @@ +#include "func_getattr_base.hpp" + +namespace Func2 +{ + class GetAttrCDCO : public GetAttrBase + { + public: + GetAttrCDCO() {} + ~GetAttrCDCO() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + struct stat *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_getattr_cdfo.cpp b/src/func_getattr_cdfo.cpp new file mode 100644 index 00000000..cec75067 --- /dev/null +++ b/src/func_getattr_cdfo.cpp @@ -0,0 +1,78 @@ +#include "func_getattr_cdfo.hpp" + +#include "error.hpp" +#include "fs_inode.hpp" +#include "fs_stat.hpp" +#include "symlinkify.hpp" +#include "timespec_utils.hpp" + + +std::string_view +Func2::GetAttrCDFO::name() const +{ + return "cdfo"; +} + +int +Func2::GetAttrCDFO::operator()(const Branches &branches_, + const fs::path &fusepath_, + struct stat *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + Err err; + fs::path fullpath; + const Branch *first_branch; + + first_branch = nullptr; + for(const auto &branch : branches_) + { + struct stat tmp_st; + + fullpath = branch.path / fusepath_; + + err = rv = fs::stat(fullpath, + &tmp_st, + follow_symlinks_); + if(rv < 0) + continue; + + if(not first_branch) + { + *st_ = tmp_st; + first_branch = &branch; + if(not S_ISDIR(tmp_st.st_mode)) + break; + continue; + } + + // This upgrades the uid:gid because mergerfs now does most + // file interaction as root and relies on `default_permissions` + // to manage permissions. Want to ensure that root owned files + // can't be changed so we treat them all as root owned. + if(tmp_st.st_uid == 0) + st_->st_uid = 0; + if(tmp_st.st_gid == 0) + st_->st_gid = 0; + st_->st_atim = TimeSpec::newest(st_->st_atim,tmp_st.st_atim); + st_->st_ctim = TimeSpec::newest(st_->st_ctim,tmp_st.st_ctim); + st_->st_mtim = TimeSpec::newest(st_->st_mtim,tmp_st.st_mtim); + st_->st_nlink += tmp_st.st_nlink; + } + + if(!first_branch) + return err; + + if(symlinkify_timeout_ >= 0) + { + fullpath = first_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(first_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_getattr_cdfo.hpp b/src/func_getattr_cdfo.hpp new file mode 100644 index 00000000..03a1a223 --- /dev/null +++ b/src/func_getattr_cdfo.hpp @@ -0,0 +1,21 @@ +#include "func_getattr_base.hpp" + +namespace Func2 +{ + class GetAttrCDFO : public GetAttrBase + { + public: + GetAttrCDFO() {} + ~GetAttrCDFO() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + struct stat *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_getattr_factory.cpp b/src/func_getattr_factory.cpp new file mode 100644 index 00000000..014ed442 --- /dev/null +++ b/src/func_getattr_factory.cpp @@ -0,0 +1,44 @@ +#include "func_getattr_factory.hpp" + +#include "func_getattr_cdfo.hpp" +#include "func_getattr_cdco.hpp" +#include "func_getattr_ff.hpp" +#include "func_getattr_newest.hpp" + +#include "policies.hpp" + +bool +Func2::GetAttrFactory::valid(const std::string str_) +{ + if(str_ == "cdfo") + return true; + if(str_ == "cdco") + return true; + if(str_ == "ff") + return true; + if(str_ == "newest") + return true; + + if(Policies::Search::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::GetAttrFactory::make(const std::string_view str_) +{ + if(str_ == "cdfo") + return std::make_shared(); + if(str_ == "cdco") + return std::make_shared(); + if(str_ == "ff") + return std::make_shared(); + if(str_ == "newest") + return std::make_shared(); + + if(Policies::Search::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_getattr_factory.hpp b/src/func_getattr_factory.hpp new file mode 100644 index 00000000..1e085980 --- /dev/null +++ b/src/func_getattr_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_getattr_base.hpp" + +namespace Func2 +{ + class GetAttrFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_getattr_ff.cpp b/src/func_getattr_ff.cpp new file mode 100644 index 00000000..5517e6b0 --- /dev/null +++ b/src/func_getattr_ff.cpp @@ -0,0 +1,44 @@ +#include "func_getattr_ff.hpp" + +#include "error.hpp" +#include "fs_stat.hpp" +#include "fs_inode.hpp" +#include "symlinkify.hpp" + + +std::string_view +Func2::GetAttrFF::name() const +{ + return "ff"; +} + +int +Func2::GetAttrFF::operator()(const Branches &branches_, + const fs::path &fusepath_, + struct stat *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + fullpath = branch.path / fusepath_; + + err = rv = fs::stat(fullpath,st_,follow_symlinks_); + if(rv < 0) + continue; + + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + + fs::inode::calc(branch.path,fusepath_,st_); + + return 0; + } + + return err; +} diff --git a/src/func_getattr_ff.hpp b/src/func_getattr_ff.hpp new file mode 100644 index 00000000..e3d4b18f --- /dev/null +++ b/src/func_getattr_ff.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "func_getattr_base.hpp" + +namespace Func2 +{ + class GetAttrFF : public GetAttrBase + { + public: + GetAttrFF() {} + ~GetAttrFF() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + struct stat *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_getattr_newest.cpp b/src/func_getattr_newest.cpp new file mode 100644 index 00000000..65daec14 --- /dev/null +++ b/src/func_getattr_newest.cpp @@ -0,0 +1,59 @@ +#include "func_getattr_newest.hpp" + +#include "error.hpp" +#include "fs_stat.hpp" +#include "fs_inode.hpp" +#include "timespec_utils.hpp" +#include "symlinkify.hpp" + + +std::string_view +Func2::GetAttrNewest::name() const +{ + return "newest"; +} + +int +Func2::GetAttrNewest::operator()(const Branches &branches_, + const fs::path &fusepath_, + struct stat *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + Err err; + fs::path fullpath; + const Branch *newest_branch; + + newest_branch = nullptr; + for(const auto &branch : branches_) + { + struct stat tmp_st; + + fullpath = branch.path / fusepath_; + err = rv = fs::stat(fullpath,&tmp_st,follow_symlinks_); + if(rv < 0) + continue; + + if(st_->st_mtim > tmp_st.st_mtim) + continue; + + *st_ = tmp_st; + newest_branch = &branch; + } + + if(!newest_branch) + return err; + + if(symlinkify_timeout_ >= 0) + { + fullpath = newest_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(newest_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_getattr_newest.hpp b/src/func_getattr_newest.hpp new file mode 100644 index 00000000..b08d0a67 --- /dev/null +++ b/src/func_getattr_newest.hpp @@ -0,0 +1,21 @@ +#include "func_getattr_base.hpp" + +namespace Func2 +{ + class GetAttrNewest : public GetAttrBase + { + public: + GetAttrNewest() {} + ~GetAttrNewest() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + struct stat *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_getxattr.hpp b/src/func_getxattr.hpp new file mode 100644 index 00000000..e5c41986 --- /dev/null +++ b/src/func_getxattr.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "func_getxattr_base.hpp" +#include "func_getxattr_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Getxattr = FuncWrapper; +} diff --git a/src/func_getxattr_base.hpp b/src/func_getxattr_base.hpp new file mode 100644 index 00000000..563ac6be --- /dev/null +++ b/src/func_getxattr_base.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class GetxattrBase + { + public: + GetxattrBase() {} + ~GetxattrBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const char *attrname, + char *attrval, + const size_t attrval_size) = 0; + }; +} diff --git a/src/func_getxattr_factory.cpp b/src/func_getxattr_factory.cpp new file mode 100644 index 00000000..416393f9 --- /dev/null +++ b/src/func_getxattr_factory.cpp @@ -0,0 +1,30 @@ +#include "func_getxattr_factory.hpp" + +#include "func_getxattr_ff.hpp" + +#include "policies.hpp" + + +bool +Func2::GetxattrFactory::valid(const std::string str_) +{ + if(str_ == "ff") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::GetxattrFactory::make(const std::string_view str_) +{ + if(str_ == "ff") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_getxattr_factory.hpp b/src/func_getxattr_factory.hpp new file mode 100644 index 00000000..0d8c7c87 --- /dev/null +++ b/src/func_getxattr_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_getxattr_base.hpp" + +namespace Func2 +{ + class GetxattrFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_getxattr_ff.cpp b/src/func_getxattr_ff.cpp new file mode 100644 index 00000000..17876887 --- /dev/null +++ b/src/func_getxattr_ff.cpp @@ -0,0 +1,35 @@ +#include "func_getxattr_ff.hpp" + +#include "error.hpp" +#include "fs_lgetxattr.hpp" + + +std::string_view +Func2::GetxattrFF::name() const +{ + return "ff"; +} + +int +Func2::GetxattrFF::operator()(const Branches &branches_, + const fs::path &fusepath_, + const char *attrname_, + char *attrval_, + const size_t attrvalsize_) +{ + int rv; + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + fullpath = branch.path / fusepath_; + + rv = fs::lgetxattr(fullpath,attrname_,attrval_,attrvalsize_); + if(rv >= 0) + return rv; + err = rv; + } + + return err; +} diff --git a/src/func_getxattr_ff.hpp b/src/func_getxattr_ff.hpp new file mode 100644 index 00000000..0f13577a --- /dev/null +++ b/src/func_getxattr_ff.hpp @@ -0,0 +1,21 @@ +#include "func_getxattr_base.hpp" + +namespace Func2 +{ + class GetxattrFF : public GetxattrBase + { + public: + GetxattrFF() {} + ~GetxattrFF() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const char *attrname, + char *attrval, + const size_t attrvalsize); + }; +} diff --git a/src/func_ioctl.hpp b/src/func_ioctl.hpp new file mode 100644 index 00000000..3719256a --- /dev/null +++ b/src/func_ioctl.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "func_ioctl_base.hpp" +#include "func_ioctl_factory.hpp" + +#include "func_wrapper.hpp" + +namespace Func2 +{ + using Ioctl = FuncWrapper; +} diff --git a/src/func_ioctl_base.hpp b/src/func_ioctl_base.hpp new file mode 100644 index 00000000..7601c6f1 --- /dev/null +++ b/src/func_ioctl_base.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class IoctlBase + { + public: + IoctlBase() {} + ~IoctlBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath) = 0; + }; +} diff --git a/src/func_ioctl_factory.cpp b/src/func_ioctl_factory.cpp new file mode 100644 index 00000000..4b8ba59a --- /dev/null +++ b/src/func_ioctl_factory.cpp @@ -0,0 +1,30 @@ +#include "func_ioctl_factory.hpp" + +#include "func_ioctl_ff.hpp" + +#include "policies.hpp" + + +bool +Func2::IoctlFactory::valid(const std::string str_) +{ + if(str_ == "ff") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::IoctlFactory::make(const std::string_view str_) +{ + if(str_ == "ff") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_ioctl_factory.hpp b/src/func_ioctl_factory.hpp new file mode 100644 index 00000000..353df41b --- /dev/null +++ b/src/func_ioctl_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_ioctl_base.hpp" + +namespace Func2 +{ + class IoctlFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_ioctl_ff.cpp b/src/func_ioctl_ff.cpp new file mode 100644 index 00000000..c9bca36e --- /dev/null +++ b/src/func_ioctl_ff.cpp @@ -0,0 +1,25 @@ +#include "func_ioctl_ff.hpp" + +#include "error.hpp" +#include "fs_ioctl.hpp" + + +std::string_view +Func2::IoctlFF::name() const +{ + return "ff"; +} + +int +Func2::IoctlFF::operator()(const Branches &branches_, + const fs::path &fusepath_) +{ + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + } + + return err; +} diff --git a/src/func_ioctl_ff.hpp b/src/func_ioctl_ff.hpp new file mode 100644 index 00000000..a9fa377a --- /dev/null +++ b/src/func_ioctl_ff.hpp @@ -0,0 +1,18 @@ +#include "func_ioctl_base.hpp" + +namespace Func2 +{ + class IoctlFF : public IoctlBase + { + public: + IoctlFF() {} + ~IoctlFF() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath); + }; +} diff --git a/src/func_listxattr.hpp b/src/func_listxattr.hpp new file mode 100644 index 00000000..82084df7 --- /dev/null +++ b/src/func_listxattr.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "func_listxattr_base.hpp" +#include "func_listxattr_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Listxattr = FuncWrapper; +} diff --git a/src/func_listxattr_base.hpp b/src/func_listxattr_base.hpp new file mode 100644 index 00000000..46dbe089 --- /dev/null +++ b/src/func_listxattr_base.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class ListxattrBase + { + public: + ListxattrBase() {} + ~ListxattrBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual ssize_t operator()(const Branches &branches, + const fs::path &fusepath, + char *list, + const size_t size) = 0; + }; +} diff --git a/src/func_listxattr_factory.cpp b/src/func_listxattr_factory.cpp new file mode 100644 index 00000000..41682ee5 --- /dev/null +++ b/src/func_listxattr_factory.cpp @@ -0,0 +1,30 @@ +#include "func_listxattr_factory.hpp" + +#include "func_listxattr_ff.hpp" + +#include "policies.hpp" + + +bool +Func2::ListxattrFactory::valid(const std::string str_) +{ + if(str_ == "ff") + return true; + + if(Policies::Search::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::ListxattrFactory::make(const std::string_view str_) +{ + if(str_ == "ff") + return std::make_shared(); + + if(Policies::Search::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_listxattr_factory.hpp b/src/func_listxattr_factory.hpp new file mode 100644 index 00000000..52b13f17 --- /dev/null +++ b/src/func_listxattr_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_listxattr_base.hpp" + +namespace Func2 +{ + class ListxattrFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_listxattr_ff.cpp b/src/func_listxattr_ff.cpp new file mode 100644 index 00000000..8673a23e --- /dev/null +++ b/src/func_listxattr_ff.cpp @@ -0,0 +1,53 @@ +#include "func_listxattr_ff.hpp" + +#include "error.hpp" +#include "fs_llistxattr.hpp" + + +std::string_view +Func2::ListxattrFF::name() const +{ + return "ff"; +} + +static +ssize_t +_listxattr_ff(const Branches &branches_, + const fs::path &fusepath_, + char *list_, + const size_t size_) +{ + Err err; + ssize_t rv; + fs::path fullpath; + + for(const auto &branch : branches_) + { + fullpath = branch.path / fusepath_; + + rv = fs::llistxattr(fullpath,list_,size_); + switch(rv) + { + case -ERANGE: + case -ENOTSUP: + case -E2BIG: + return rv; + default: + if(rv >= 0) + return rv; + err = rv; + break; + } + } + + return err; +} + +ssize_t +Func2::ListxattrFF::operator()(const Branches &branches_, + const fs::path &fusepath_, + char *list_, + const size_t size_) +{ + return ::_listxattr_ff(branches_,fusepath_,list_,size_); +} diff --git a/src/func_listxattr_ff.hpp b/src/func_listxattr_ff.hpp new file mode 100644 index 00000000..f7891b33 --- /dev/null +++ b/src/func_listxattr_ff.hpp @@ -0,0 +1,20 @@ +#include "func_listxattr_base.hpp" + +namespace Func2 +{ + class ListxattrFF : public ListxattrBase + { + public: + ListxattrFF() {} + ~ListxattrFF() {} + + public: + std::string_view name() const; + + public: + ssize_t operator()(const Branches &branches, + const fs::path &fusepath, + char *list, + const size_t size); + }; +} diff --git a/src/func_open.hpp b/src/func_open.hpp new file mode 100644 index 00000000..093c529e --- /dev/null +++ b/src/func_open.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "func_open_base.hpp" +#include "func_open_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Open = FuncWrapper; +} diff --git a/src/func_open_base.hpp b/src/func_open_base.hpp new file mode 100644 index 00000000..f83aa055 --- /dev/null +++ b/src/func_open_base.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +#include + + +namespace Func2 +{ + class OpenBase + { + public: + OpenBase() {} + ~OpenBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const mode_t mode) = 0; + }; +} diff --git a/src/func_open_factory.cpp b/src/func_open_factory.cpp new file mode 100644 index 00000000..716e0cf2 --- /dev/null +++ b/src/func_open_factory.cpp @@ -0,0 +1,30 @@ +#include "func_open_factory.hpp" + +#include "func_open_ff.hpp" + +#include "policies.hpp" + + +bool +Func2::OpenFactory::valid(const std::string str_) +{ + if(str_ == "ff") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::OpenFactory::make(const std::string_view str_) +{ + if(str_ == "ff") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_open_factory.hpp b/src/func_open_factory.hpp new file mode 100644 index 00000000..c36164e9 --- /dev/null +++ b/src/func_open_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_open_base.hpp" + +namespace Func2 +{ + class OpenFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_open_ff.cpp b/src/func_open_ff.cpp new file mode 100644 index 00000000..377534d2 --- /dev/null +++ b/src/func_open_ff.cpp @@ -0,0 +1,27 @@ +#include "func_open_ff.hpp" + +#include "error.hpp" +#include "fs_open.hpp" + + +std::string_view +Func2::OpenFF::name() const +{ + return "ff"; +} + +int +Func2::OpenFF::operator()(const Branches &branches_, + const fs::path &fusepath_, + const mode_t mode_) +{ + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + + } + + return err; +} diff --git a/src/func_open_ff.hpp b/src/func_open_ff.hpp new file mode 100644 index 00000000..7558013f --- /dev/null +++ b/src/func_open_ff.hpp @@ -0,0 +1,19 @@ +#include "func_open_base.hpp" + +namespace Func2 +{ + class OpenFF : public OpenBase + { + public: + OpenFF() {} + ~OpenFF() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const mode_t mode); + }; +} diff --git a/src/func_readlink.hpp b/src/func_readlink.hpp new file mode 100644 index 00000000..8c50179c --- /dev/null +++ b/src/func_readlink.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "func_readlink_base.hpp" +#include "func_readlink_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Readlink = FuncWrapper; +} diff --git a/src/func_readlink_base.hpp b/src/func_readlink_base.hpp new file mode 100644 index 00000000..5527fbaa --- /dev/null +++ b/src/func_readlink_base.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class ReadlinkBase + { + public: + ReadlinkBase() {} + ~ReadlinkBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + char *buf, + const size_t bufsize, + const time_t symlinkify_timeout) = 0; + }; +} diff --git a/src/func_readlink_factory.cpp b/src/func_readlink_factory.cpp new file mode 100644 index 00000000..7782fc5a --- /dev/null +++ b/src/func_readlink_factory.cpp @@ -0,0 +1,30 @@ +#include "func_readlink_factory.hpp" + +#include "func_readlink_ff.hpp" + +#include "policies.hpp" + + +bool +Func2::ReadlinkFactory::valid(const std::string str_) +{ + if(str_ == "ff") + return true; + + if(Policies::Search::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::ReadlinkFactory::make(const std::string_view str_) +{ + if(str_ == "ff") + return std::make_shared(); + + if(Policies::Search::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_readlink_factory.hpp b/src/func_readlink_factory.hpp new file mode 100644 index 00000000..bdc833a3 --- /dev/null +++ b/src/func_readlink_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_readlink_base.hpp" + +namespace Func2 +{ + class ReadlinkFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_readlink_ff.cpp b/src/func_readlink_ff.cpp new file mode 100644 index 00000000..86e7cd85 --- /dev/null +++ b/src/func_readlink_ff.cpp @@ -0,0 +1,104 @@ +#include "func_readlink_ff.hpp" + +#include "error.hpp" +#include "fs_readlink.hpp" +#include "fs_lstat.hpp" +#include "symlinkify.hpp" + +#include + + +std::string_view +Func2::ReadlinkFF::name() const +{ + return "ff"; +} + +static +int +_readlink_symlinkify(const Branches &branches_, + const fs::path &fusepath_, + char *buf_, + const size_t bufsize_, + const time_t symlinkify_timeout_) +{ + int rv; + Err err; + struct stat st; + fs::path fullpath; + + for(const auto &branch : branches_) + { + fullpath = branch.path / fusepath_; + + err = rv = fs::lstat(fullpath,&st); + if(rv < 0) + continue; + + if(not symlinkify::can_be_symlink(st,symlinkify_timeout_)) + { + err = rv = fs::readlink(fusepath_,buf_,bufsize_); + if(rv < 0) + continue; + + buf_[rv] = '\0'; + + return 0; + } + + strncpy(buf_,fullpath.c_str(),bufsize_); + + return 0; + } + + return err; +} + +static +int +_readlink(const Branches &branches_, + const fs::path &fusepath_, + char *buf_, + const size_t bufsize_) +{ + int rv; + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + fullpath = branch.path / fusepath_; + + err = rv = fs::readlink(fusepath_,buf_,bufsize_); + if(rv < 0) + continue; + + buf_[rv] = '\0'; + + return 0; + } + + return err; +} + + + +int +Func2::ReadlinkFF::operator()(const Branches &branches_, + const fs::path &fusepath_, + char *buf_, + const size_t bufsize_, + const time_t symlinkify_timeout_) +{ + if(symlinkify_timeout_ > 0) + return ::_readlink_symlinkify(branches_, + fusepath_, + buf_, + bufsize_, + symlinkify_timeout_); + + return ::_readlink(branches_, + fusepath_, + buf_, + bufsize_); +} diff --git a/src/func_readlink_ff.hpp b/src/func_readlink_ff.hpp new file mode 100644 index 00000000..85e50479 --- /dev/null +++ b/src/func_readlink_ff.hpp @@ -0,0 +1,21 @@ +#include "func_readlink_base.hpp" + +namespace Func2 +{ + class ReadlinkFF : public ReadlinkBase + { + public: + ReadlinkFF() {} + ~ReadlinkFF() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + char *buf, + const size_t bufsize, + const time_t symlinkify_timeout); + }; +} diff --git a/src/func_removexattr.hpp b/src/func_removexattr.hpp new file mode 100644 index 00000000..aef5e65e --- /dev/null +++ b/src/func_removexattr.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "func_removexattr_base.hpp" +#include "func_removexattr_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Removexattr = FuncWrapper; +} diff --git a/src/func_removexattr_all.cpp b/src/func_removexattr_all.cpp new file mode 100644 index 00000000..2e92478f --- /dev/null +++ b/src/func_removexattr_all.cpp @@ -0,0 +1,35 @@ +#include "func_removexattr_all.hpp" + +#include "error.hpp" +#include "fs_lremovexattr.hpp" + + +std::string_view +Func2::RemovexattrAll::name() const +{ + return "all"; +} + +int +Func2::RemovexattrAll::operator()(const Branches &branches_, + const fs::path &fusepath_, + const char *attrname_) +{ + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + if(branch.ro()) + { + err = -EROFS; + continue; + } + + fullpath = branch.path / fusepath_; + + err = fs::lremovexattr(fullpath,attrname_); + } + + return err; +} diff --git a/src/func_removexattr_all.hpp b/src/func_removexattr_all.hpp new file mode 100644 index 00000000..560ed3dd --- /dev/null +++ b/src/func_removexattr_all.hpp @@ -0,0 +1,19 @@ +#include "func_removexattr_base.hpp" + +namespace Func2 +{ + class RemovexattrAll : public RemovexattrBase + { + public: + RemovexattrAll() {} + ~RemovexattrAll() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const char *attrname); + }; +} diff --git a/src/func_removexattr_base.hpp b/src/func_removexattr_base.hpp new file mode 100644 index 00000000..a9d6aa8f --- /dev/null +++ b/src/func_removexattr_base.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class RemovexattrBase + { + public: + RemovexattrBase() {} + ~RemovexattrBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const char *attrname) = 0; + }; +} diff --git a/src/func_removexattr_factory.cpp b/src/func_removexattr_factory.cpp new file mode 100644 index 00000000..dc2e010b --- /dev/null +++ b/src/func_removexattr_factory.cpp @@ -0,0 +1,30 @@ +#include "func_removexattr_factory.hpp" + +#include "func_removexattr_all.hpp" + +#include "policies.hpp" + + +bool +Func2::RemovexattrFactory::valid(const std::string str_) +{ + if(str_ == "all") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::RemovexattrFactory::make(const std::string_view str_) +{ + if(str_ == "all") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_removexattr_factory.hpp b/src/func_removexattr_factory.hpp new file mode 100644 index 00000000..6057550f --- /dev/null +++ b/src/func_removexattr_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_removexattr_base.hpp" + +namespace Func2 +{ + class RemovexattrFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_rmdir.hpp b/src/func_rmdir.hpp new file mode 100644 index 00000000..691ce495 --- /dev/null +++ b/src/func_rmdir.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "func_rmdir_base.hpp" +#include "func_rmdir_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Rmdir = FuncWrapper; +} diff --git a/src/func_rmdir_all.cpp b/src/func_rmdir_all.cpp new file mode 100644 index 00000000..2207bd8b --- /dev/null +++ b/src/func_rmdir_all.cpp @@ -0,0 +1,49 @@ +#include "func_rmdir_all.hpp" + +#include "config.hpp" +#include "error.hpp" +#include "fs_rmdir.hpp" +#include "fs_unlink.hpp" + + +std::string_view +Func2::RmdirAll::name() const +{ + return "all"; +} + +static +int +_should_unlink(int rv_) + +{ + return ((rv_ == -ENOTDIR) && + (cfg.follow_symlinks != FollowSymlinks::ENUM::NEVER)); +} + +int +Func2::RmdirAll::operator()(const Branches &branches_, + const fs::path &fusepath_) +{ + int rv; + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + if(branch.ro()) + { + err = -EROFS; + continue; + } + + fullpath = branch.path / fusepath_; + + rv = fs::rmdir(fullpath); + if(::_should_unlink(rv)) + rv = fs::unlink(fullpath); + err = rv; + } + + return err; +} diff --git a/src/func_rmdir_all.hpp b/src/func_rmdir_all.hpp new file mode 100644 index 00000000..9cd573c3 --- /dev/null +++ b/src/func_rmdir_all.hpp @@ -0,0 +1,18 @@ +#include "func_rmdir_base.hpp" + +namespace Func2 +{ + class RmdirAll : public RmdirBase + { + public: + RmdirAll() {} + ~RmdirAll() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath); + }; +} diff --git a/src/func_rmdir_base.hpp b/src/func_rmdir_base.hpp new file mode 100644 index 00000000..8aaf5748 --- /dev/null +++ b/src/func_rmdir_base.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class RmdirBase + { + public: + RmdirBase() {} + ~RmdirBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath) = 0; + }; +} diff --git a/src/func_rmdir_factory.cpp b/src/func_rmdir_factory.cpp new file mode 100644 index 00000000..dbb48515 --- /dev/null +++ b/src/func_rmdir_factory.cpp @@ -0,0 +1,30 @@ +#include "func_rmdir_factory.hpp" + +#include "func_rmdir_all.hpp" + +#include "policies.hpp" + + +bool +Func2::RmdirFactory::valid(const std::string str_) +{ + if(str_ == "all") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::RmdirFactory::make(const std::string_view str_) +{ + if(str_ == "all") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_rmdir_factory.hpp b/src/func_rmdir_factory.hpp new file mode 100644 index 00000000..962cc470 --- /dev/null +++ b/src/func_rmdir_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_rmdir_base.hpp" + +namespace Func2 +{ + class RmdirFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_setxattr.hpp b/src/func_setxattr.hpp new file mode 100644 index 00000000..13227109 --- /dev/null +++ b/src/func_setxattr.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "func_setxattr_base.hpp" +#include "func_setxattr_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Setxattr = FuncWrapper; +} diff --git a/src/func_setxattr_all.cpp b/src/func_setxattr_all.cpp new file mode 100644 index 00000000..f0cadd26 --- /dev/null +++ b/src/func_setxattr_all.cpp @@ -0,0 +1,38 @@ +#include "func_setxattr_all.hpp" + +#include "error.hpp" +#include "fs_lsetxattr.hpp" + + +std::string_view +Func2::SetxattrAll::name() const +{ + return "all"; +} + +int +Func2::SetxattrAll::operator()(const Branches &branches_, + const fs::path &fusepath_, + const char *attrname_, + const char *attrval_, + size_t attrvalsize_, + int flags_) +{ + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + if(branch.ro()) + { + err = -EROFS; + continue; + } + + fullpath = branch.path / fusepath_; + + err = fs::lsetxattr(fullpath,attrname_,attrval_,attrvalsize_,flags_); + } + + return err; +} diff --git a/src/func_setxattr_all.hpp b/src/func_setxattr_all.hpp new file mode 100644 index 00000000..e89890dd --- /dev/null +++ b/src/func_setxattr_all.hpp @@ -0,0 +1,22 @@ +#include "func_setxattr_base.hpp" + +namespace Func2 +{ + class SetxattrAll : public SetxattrBase + { + public: + SetxattrAll() {} + ~SetxattrAll() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const char *attrname_, + const char *attrval_, + size_t attrvalsize_, + int flags_); + }; +} diff --git a/src/func_setxattr_base.hpp b/src/func_setxattr_base.hpp new file mode 100644 index 00000000..5058a7e4 --- /dev/null +++ b/src/func_setxattr_base.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class SetxattrBase + { + public: + SetxattrBase() {} + ~SetxattrBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const char *attrname, + const char *attrval, + size_t attrvalsize, + int flags) = 0; + }; +} diff --git a/src/func_setxattr_factory.cpp b/src/func_setxattr_factory.cpp new file mode 100644 index 00000000..4eacb934 --- /dev/null +++ b/src/func_setxattr_factory.cpp @@ -0,0 +1,30 @@ +#include "func_setxattr_factory.hpp" + +#include "func_setxattr_all.hpp" + +#include "policies.hpp" + + +bool +Func2::SetxattrFactory::valid(const std::string str_) +{ + if(str_ == "all") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::SetxattrFactory::make(const std::string_view str_) +{ + if(str_ == "all") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_setxattr_factory.hpp b/src/func_setxattr_factory.hpp new file mode 100644 index 00000000..99559f5d --- /dev/null +++ b/src/func_setxattr_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_setxattr_base.hpp" + +namespace Func2 +{ + class SetxattrFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_statx.hpp b/src/func_statx.hpp new file mode 100644 index 00000000..53a82d43 --- /dev/null +++ b/src/func_statx.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "func_statx_base.hpp" +#include "func_statx_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Statx = FuncWrapper; +} diff --git a/src/func_statx_base.hpp b/src/func_statx_base.hpp new file mode 100644 index 00000000..a78c1f28 --- /dev/null +++ b/src/func_statx_base.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "follow_symlinks_enum.hpp" + +#include "fs_path.hpp" +#include "branches.hpp" +#include "base_types.h" + +#include "fuse.h" + +#include + +#include +#include +#include + + +namespace Func2 +{ + class StatxBase + { + public: + StatxBase() {} + ~StatxBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout) = 0; + }; +} diff --git a/src/func_statx_cdco.cpp b/src/func_statx_cdco.cpp new file mode 100644 index 00000000..5e313845 --- /dev/null +++ b/src/func_statx_cdco.cpp @@ -0,0 +1,81 @@ +#include "func_statx_cdco.hpp" + +#include "error.hpp" +#include "fs_inode.hpp" +#include "fs_statx.hpp" +#include "symlinkify.hpp" +#include "timespec_utils.hpp" + + +std::string_view +Func2::StatxCDCO::name() const +{ + return "cdco"; +} + +int +Func2::StatxCDCO::operator()(const Branches &branches_, + const fs::path &fusepath_, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + Err err; + fs::path fullpath; + const Branch *first_branch; + + first_branch = nullptr; + for(const auto &branch : branches_) + { + struct fuse_statx tmp_st; + + fullpath = branch.path / fusepath_; + err = rv = fs::statx(AT_FDCWD, + fullpath, + flags_|AT_SYMLINK_NOFOLLOW, + mask_, + &tmp_st, + follow_symlinks_); + if(rv < 0) + continue; + + if(!first_branch) + { + *st_ = tmp_st; + first_branch = &branch; + continue; + } + + // This upgrades the uid:gid because mergerfs now does most + // file interaction as root and relies on `default_permissions` + // to manage permissions. Want to ensure that root owned files + // can't be changed so we treat them all as root owned. + if(tmp_st.uid == 0) + st_->uid = 0; + if(tmp_st.gid == 0) + st_->gid = 0; + st_->atime = TimeSpec::newest(st_->atime,tmp_st.atime); + st_->ctime = TimeSpec::newest(st_->ctime,tmp_st.ctime); + st_->mtime = TimeSpec::newest(st_->mtime,tmp_st.mtime); + st_->btime = TimeSpec::newest(st_->btime,tmp_st.btime); + st_->nlink += tmp_st.nlink; + } + + if(!first_branch) + return err; + + if(symlinkify_timeout_ >= 0) + { + fullpath = first_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(first_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_statx_cdco.hpp b/src/func_statx_cdco.hpp new file mode 100644 index 00000000..72033d3f --- /dev/null +++ b/src/func_statx_cdco.hpp @@ -0,0 +1,23 @@ +#include "func_statx_base.hpp" + +namespace Func2 +{ + class StatxCDCO : public StatxBase + { + public: + StatxCDCO() {} + ~StatxCDCO() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_statx_cdfo.cpp b/src/func_statx_cdfo.cpp new file mode 100644 index 00000000..176c18a7 --- /dev/null +++ b/src/func_statx_cdfo.cpp @@ -0,0 +1,84 @@ +#include "func_statx_cdfo.hpp" + +#include "error.hpp" +#include "fs_inode.hpp" +#include "fs_statx.hpp" +#include "symlinkify.hpp" +#include "timespec_utils.hpp" + + +std::string_view +Func2::StatxCDFO::name() const +{ + return "cdfo"; +} + +int +Func2::StatxCDFO::operator()(const Branches &branches_, + const fs::path &fusepath_, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + Err err; + fs::path fullpath; + const Branch *first_branch; + + first_branch = nullptr; + for(const auto &branch : branches_) + { + struct fuse_statx tmp_st; + + fullpath = branch.path / fusepath_; + + err = rv = fs::statx(AT_FDCWD, + fullpath, + flags_|AT_SYMLINK_NOFOLLOW, + mask_, + &tmp_st, + follow_symlinks_); + if(rv < 0) + continue; + + if(!first_branch) + { + *st_ = tmp_st; + first_branch = &branch; + if(not S_ISDIR(tmp_st.mode)) + break; + continue; + } + + // This upgrades the uid:gid because mergerfs now does most + // file interaction as root and relies on `default_permissions` + // to manage permissions. Want to ensure that root owned files + // can't be changed so we treat them all as root owned. + if(tmp_st.uid == 0) + st_->uid = 0; + if(tmp_st.gid == 0) + st_->gid = 0; + st_->atime = TimeSpec::newest(st_->atime,tmp_st.atime); + st_->ctime = TimeSpec::newest(st_->ctime,tmp_st.ctime); + st_->mtime = TimeSpec::newest(st_->mtime,tmp_st.mtime); + st_->btime = TimeSpec::newest(st_->btime,tmp_st.btime); + st_->nlink += tmp_st.nlink; + } + + if(!first_branch) + return err; + + if(symlinkify_timeout_ >= 0) + { + fullpath = first_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(first_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_statx_cdfo.hpp b/src/func_statx_cdfo.hpp new file mode 100644 index 00000000..80fbef50 --- /dev/null +++ b/src/func_statx_cdfo.hpp @@ -0,0 +1,23 @@ +#include "func_statx_base.hpp" + +namespace Func2 +{ + class StatxCDFO : public StatxBase + { + public: + StatxCDFO() {} + ~StatxCDFO() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_statx_factory.cpp b/src/func_statx_factory.cpp new file mode 100644 index 00000000..ee85581e --- /dev/null +++ b/src/func_statx_factory.cpp @@ -0,0 +1,44 @@ +#include "func_statx_factory.hpp" + +#include "func_statx_cdfo.hpp" +#include "func_statx_cdco.hpp" +#include "func_statx_ff.hpp" +#include "func_statx_newest.hpp" + +#include "policies.hpp" + +bool +Func2::StatxFactory::valid(const std::string str_) +{ + if(str_ == "cdfo") + return true; + if(str_ == "cdco") + return true; + if(str_ == "ff") + return true; + if(str_ == "newest") + return true; + + if(Policies::Search::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::StatxFactory::make(const std::string_view str_) +{ + if(str_ == "cdfo") + return std::make_shared(); + if(str_ == "cdco") + return std::make_shared(); + if(str_ == "ff") + return std::make_shared(); + if(str_ == "newest") + return std::make_shared(); + + if(Policies::Search::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_statx_factory.hpp b/src/func_statx_factory.hpp new file mode 100644 index 00000000..50ae11e6 --- /dev/null +++ b/src/func_statx_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_statx_base.hpp" + +namespace Func2 +{ + class StatxFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_statx_ff.cpp b/src/func_statx_ff.cpp new file mode 100644 index 00000000..e041005c --- /dev/null +++ b/src/func_statx_ff.cpp @@ -0,0 +1,50 @@ +#include "func_statx_ff.hpp" + +#include "error.hpp" +#include "fs_statx.hpp" +#include "fs_inode.hpp" +#include "symlinkify.hpp" + + +std::string_view +Func2::StatxFF::name() const +{ + return "ff"; +} + +int +Func2::StatxFF::operator()(const Branches &branches_, + const fs::path &fusepath_, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + fullpath = branch.path / fusepath_; + err = rv = fs::statx(AT_FDCWD, + fullpath, + flags_|AT_SYMLINK_NOFOLLOW, + mask_, + st_, + follow_symlinks_); + if(rv < 0) + continue; + + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + + fs::inode::calc(branch.path,fusepath_,st_); + + return 0; + } + + return err; +} diff --git a/src/func_statx_ff.hpp b/src/func_statx_ff.hpp new file mode 100644 index 00000000..f216a3bf --- /dev/null +++ b/src/func_statx_ff.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "func_statx_base.hpp" + +namespace Func2 +{ + class StatxFF : public StatxBase + { + public: + StatxFF() {} + ~StatxFF() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_statx_newest.cpp b/src/func_statx_newest.cpp new file mode 100644 index 00000000..ac1f0182 --- /dev/null +++ b/src/func_statx_newest.cpp @@ -0,0 +1,66 @@ +#include "func_statx_newest.hpp" + +#include "error.hpp" +#include "fs_statx.hpp" +#include "fs_inode.hpp" +#include "symlinkify.hpp" +#include "timespec_utils.hpp" + + +std::string_view +Func2::StatxNewest::name() const +{ + return "newest"; +} + +int +Func2::StatxNewest::operator()(const Branches &branches_, + const fs::path &fusepath_, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st_, + const FollowSymlinksEnum follow_symlinks_, + const s64 symlinkify_timeout_) +{ + int rv; + Err err; + fs::path fullpath; + const Branch *newest_branch; + + newest_branch = nullptr; + for(const auto &branch : branches_) + { + struct fuse_statx tmp_st; + + fullpath = branch.path / fusepath_; + err = rv = fs::statx(AT_FDCWD, + fullpath, + flags_|AT_SYMLINK_NOFOLLOW, + mask_, + &tmp_st, + follow_symlinks_); + if(rv < 0) + continue; + + if(st_->mtime > tmp_st.mtime) + continue; + + *st_ = tmp_st; + newest_branch = &branch; + } + + if(!newest_branch) + return err; + + if(symlinkify_timeout_ >= 0) + { + fullpath = newest_branch->path / fusepath_; + symlinkify::convert_if_can_be_symlink(fullpath, + st_, + symlinkify_timeout_); + } + + fs::inode::calc(newest_branch->path,fusepath_,st_); + + return 0; +} diff --git a/src/func_statx_newest.hpp b/src/func_statx_newest.hpp new file mode 100644 index 00000000..220ed7bf --- /dev/null +++ b/src/func_statx_newest.hpp @@ -0,0 +1,23 @@ +#include "func_statx_base.hpp" + +namespace Func2 +{ + class StatxNewest : public StatxBase + { + public: + StatxNewest() {} + ~StatxNewest() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const u32 flags_, + const u32 mask_, + struct fuse_statx *st, + const FollowSymlinksEnum follow_symlinks, + const s64 symlinkify_timeout); + }; +} diff --git a/src/func_truncate.hpp b/src/func_truncate.hpp new file mode 100644 index 00000000..d6b0e79d --- /dev/null +++ b/src/func_truncate.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "func_truncate_base.hpp" +#include "func_truncate_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Truncate = FuncWrapper; +} diff --git a/src/func_truncate_all.cpp b/src/func_truncate_all.cpp new file mode 100644 index 00000000..7300cfd0 --- /dev/null +++ b/src/func_truncate_all.cpp @@ -0,0 +1,35 @@ +#include "func_truncate_all.hpp" + +#include "error.hpp" +#include "fs_truncate.hpp" + + +std::string_view +Func2::TruncateAll::name() const +{ + return "all"; +} + +int +Func2::TruncateAll::operator()(const Branches &branches_, + const fs::path &fusepath_, + const off_t size_) +{ + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + if(branch.ro()) + { + err = -EROFS; + continue; + } + + fullpath = branch.path / fusepath_; + + err = fs::truncate(fullpath,size_); + } + + return err; +} diff --git a/src/func_truncate_all.hpp b/src/func_truncate_all.hpp new file mode 100644 index 00000000..76fc7d49 --- /dev/null +++ b/src/func_truncate_all.hpp @@ -0,0 +1,19 @@ +#include "func_truncate_base.hpp" + +namespace Func2 +{ + class TruncateAll : public TruncateBase + { + public: + TruncateAll() {} + ~TruncateAll() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const off_t size_); + }; +} diff --git a/src/func_truncate_base.hpp b/src/func_truncate_base.hpp new file mode 100644 index 00000000..9a818c67 --- /dev/null +++ b/src/func_truncate_base.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class TruncateBase + { + public: + TruncateBase() {} + ~TruncateBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const off_t size) = 0; + }; +} diff --git a/src/func_truncate_factory.cpp b/src/func_truncate_factory.cpp new file mode 100644 index 00000000..077076f0 --- /dev/null +++ b/src/func_truncate_factory.cpp @@ -0,0 +1,30 @@ +#include "func_truncate_factory.hpp" + +#include "func_truncate_all.hpp" + +#include "policies.hpp" + + +bool +Func2::TruncateFactory::valid(const std::string str_) +{ + if(str_ == "all") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::TruncateFactory::make(const std::string_view str_) +{ + if(str_ == "all") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_truncate_factory.hpp b/src/func_truncate_factory.hpp new file mode 100644 index 00000000..92a03fc0 --- /dev/null +++ b/src/func_truncate_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_truncate_base.hpp" + +namespace Func2 +{ + class TruncateFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_unlink.hpp b/src/func_unlink.hpp new file mode 100644 index 00000000..5a6d86c6 --- /dev/null +++ b/src/func_unlink.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "func_unlink_base.hpp" +#include "func_unlink_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Unlink = FuncWrapper; +} diff --git a/src/func_unlink_all.cpp b/src/func_unlink_all.cpp new file mode 100644 index 00000000..5d73a186 --- /dev/null +++ b/src/func_unlink_all.cpp @@ -0,0 +1,34 @@ +#include "func_unlink_all.hpp" + +#include "error.hpp" +#include "fs_unlink.hpp" + + +std::string_view +Func2::UnlinkAll::name() const +{ + return "all"; +} + +int +Func2::UnlinkAll::operator()(const Branches &branches_, + const fs::path &fusepath_) +{ + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + if(branch.ro()) + { + err = -EROFS; + continue; + } + + fullpath = branch.path / fusepath_; + + err = fs::unlink(fullpath); + } + + return err; +} diff --git a/src/func_unlink_all.hpp b/src/func_unlink_all.hpp new file mode 100644 index 00000000..16943dcd --- /dev/null +++ b/src/func_unlink_all.hpp @@ -0,0 +1,18 @@ +#include "func_unlink_base.hpp" + +namespace Func2 +{ + class UnlinkAll : public UnlinkBase + { + public: + UnlinkAll() {} + ~UnlinkAll() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath); + }; +} diff --git a/src/func_unlink_base.hpp b/src/func_unlink_base.hpp new file mode 100644 index 00000000..9737866f --- /dev/null +++ b/src/func_unlink_base.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class UnlinkBase + { + public: + UnlinkBase() {} + ~UnlinkBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath) = 0; + }; +} diff --git a/src/func_unlink_factory.cpp b/src/func_unlink_factory.cpp new file mode 100644 index 00000000..03ee7d3d --- /dev/null +++ b/src/func_unlink_factory.cpp @@ -0,0 +1,30 @@ +#include "func_unlink_factory.hpp" + +#include "func_unlink_all.hpp" + +#include "policies.hpp" + + +bool +Func2::UnlinkFactory::valid(const std::string str_) +{ + if(str_ == "all") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::UnlinkFactory::make(const std::string_view str_) +{ + if(str_ == "all") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_unlink_factory.hpp b/src/func_unlink_factory.hpp new file mode 100644 index 00000000..1d8058e0 --- /dev/null +++ b/src/func_unlink_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_unlink_base.hpp" + +namespace Func2 +{ + class UnlinkFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_utimens.hpp b/src/func_utimens.hpp new file mode 100644 index 00000000..0aa697a5 --- /dev/null +++ b/src/func_utimens.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "func_utimens_base.hpp" +#include "func_utimens_factory.hpp" + +#include "func_wrapper.hpp" + + +namespace Func2 +{ + using Utimens = FuncWrapper; +} diff --git a/src/func_utimens_all.cpp b/src/func_utimens_all.cpp new file mode 100644 index 00000000..5b77ab40 --- /dev/null +++ b/src/func_utimens_all.cpp @@ -0,0 +1,35 @@ +#include "func_utimens_all.hpp" + +#include "error.hpp" +#include "fs_lutimens.hpp" + + +std::string_view +Func2::UtimensAll::name() const +{ + return "all"; +} + +int +Func2::UtimensAll::operator()(const Branches &branches_, + const fs::path &fusepath_, + const timespec times_[2]) +{ + Err err; + fs::path fullpath; + + for(const auto &branch : branches_) + { + if(branch.ro()) + { + err = -EROFS; + continue; + } + + fullpath = branch.path / fusepath_; + + err = fs::lutimens(fullpath,times_); + } + + return err; +} diff --git a/src/func_utimens_all.hpp b/src/func_utimens_all.hpp new file mode 100644 index 00000000..6d02a6db --- /dev/null +++ b/src/func_utimens_all.hpp @@ -0,0 +1,19 @@ +#include "func_utimens_base.hpp" + +namespace Func2 +{ + class UtimensAll : public UtimensBase + { + public: + UtimensAll() {} + ~UtimensAll() {} + + public: + std::string_view name() const; + + public: + int operator()(const Branches &branches, + const fs::path &fusepath, + const timespec times_[2]); + }; +} diff --git a/src/func_utimens_base.hpp b/src/func_utimens_base.hpp new file mode 100644 index 00000000..9f118439 --- /dev/null +++ b/src/func_utimens_base.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "branches.hpp" + +#include "fs_path.hpp" + +namespace Func2 +{ + class UtimensBase + { + public: + UtimensBase() {} + ~UtimensBase() {} + + public: + virtual std::string_view name() const = 0; + + public: + virtual int operator()(const Branches &branches, + const fs::path &fusepath, + const timespec times_[2]) = 0; + }; +} diff --git a/src/func_utimens_factory.cpp b/src/func_utimens_factory.cpp new file mode 100644 index 00000000..b2a9b313 --- /dev/null +++ b/src/func_utimens_factory.cpp @@ -0,0 +1,30 @@ +#include "func_utimens_factory.hpp" + +#include "func_utimens_all.hpp" + +#include "policies.hpp" + + +bool +Func2::UtimensFactory::valid(const std::string str_) +{ + if(str_ == "all") + return true; + + if(Policies::Action::find(str_)) + return true; + + return false; +} + +std::shared_ptr +Func2::UtimensFactory::make(const std::string_view str_) +{ + if(str_ == "all") + return std::make_shared(); + + if(Policies::Action::find(str_)) + return std::make_shared(); + + return {}; +} diff --git a/src/func_utimens_factory.hpp b/src/func_utimens_factory.hpp new file mode 100644 index 00000000..62fd94c4 --- /dev/null +++ b/src/func_utimens_factory.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "func_utimens_base.hpp" + +namespace Func2 +{ + class UtimensFactory + { + public: + static bool valid(const std::string str); + static std::shared_ptr make(const std::string_view str); + }; +} diff --git a/src/func_wrapper.hpp b/src/func_wrapper.hpp new file mode 100644 index 00000000..1f4f4c5b --- /dev/null +++ b/src/func_wrapper.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "atomicsharedptr.hpp" +#include "tofrom_string.hpp" + +#include +#include + +#include + +template +class FuncWrapper : public ToFromString +{ +private: + AtomicSharedPtr _impl; + +public: + explicit FuncWrapper(const std::string &name_) + { + _impl.store(FactoryType::make(name_)); + assert(not _impl.is_null()); + } + +public: + ReturnType + operator()(Args&&... args) + { + return _impl(std::forward(args)...); + //return _impl(args...); + } + +public: + std::string + to_string() const + { + return std::string{_impl.load()->name()}; + } + + int + from_string(const std::string_view str_) + { + std::shared_ptr p; + + p = FactoryType::make(str_); + if(!p) + return -EINVAL; + + _impl.store(p); + + return 0; + } +}; diff --git a/src/funcs.hpp b/src/funcs.hpp index dbb1eb8c..3a4fd59c 100644 --- a/src/funcs.hpp +++ b/src/funcs.hpp @@ -23,24 +23,13 @@ struct Funcs { - Func::Access access; - Func::Chmod chmod; - Func::Chown chown; Func::Create create; Func::GetAttr getattr; - Func::GetXAttr getxattr; Func::Link link; Func::ListXAttr listxattr; Func::Mkdir mkdir; Func::Mknod mknod; Func::Open open; - Func::Readlink readlink; - Func::RemoveXAttr removexattr; Func::Rename rename; - Func::Rmdir rmdir; - Func::SetXAttr setxattr; Func::Symlink symlink; - Func::Truncate truncate; - Func::Unlink unlink; - Func::Utimens utimens; }; diff --git a/src/fuse_access.cpp b/src/fuse_access.cpp index 521b75ab..7418a0d7 100644 --- a/src/fuse_access.cpp +++ b/src/fuse_access.cpp @@ -56,8 +56,7 @@ FUSE::access(const fuse_req_ctx_t *ctx_, { const fs::path fusepath{fusepath_}; - return ::_access(cfg.func.access.policy, - cfg.branches, - fusepath, - mask_); + return cfg.access(cfg.branches, + fusepath, + mask_); } diff --git a/src/fuse_chmod.cpp b/src/fuse_chmod.cpp index 79a8b1be..af185fd4 100644 --- a/src/fuse_chmod.cpp +++ b/src/fuse_chmod.cpp @@ -17,97 +17,16 @@ #include "fuse_chmod.hpp" #include "config.hpp" -#include "errno.hpp" -#include "fs_lchmod.hpp" -#include "fs_path.hpp" -#include "policy_rv.hpp" -#include "ugid.hpp" -#include "fuse.h" - -#include -#include - - -static -void -_chmod_loop_core(const std::string &basepath_, - const fs::path &fusepath_, - const mode_t mode_, - PolicyRV *prv_) -{ - fs::path fullpath; - - fullpath = basepath_ / fusepath_; - - errno = 0; - fs::lchmod(fullpath,mode_); - - prv_->insert(errno,basepath_); -} - -static -void -_chmod_loop(const std::vector &branches_, - const fs::path &fusepath_, - const mode_t mode_, - PolicyRV *prv_) -{ - for(auto &branch : branches_) - { - ::_chmod_loop_core(branch->path,fusepath_,mode_,prv_); - } -} - -static -int -_chmod(const Policy::Action &actionFunc_, - const Policy::Search &searchFunc_, - const Branches &branches_, - const fs::path &fusepath_, - const mode_t mode_) -{ - int rv; - PolicyRV prv; - std::vector branches; - - rv = actionFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - ::_chmod_loop(branches,fusepath_,mode_,&prv); - if(prv.errors.empty()) - return 0; - if(prv.successes.empty()) - return prv.errors[0].rv; - - branches.clear(); - rv = searchFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - return prv.get_error(branches[0]->path); -} - -static -int -_chmod(const fs::path &fusepath_, - const mode_t mode_) -{ - - return ::_chmod(cfg.func.chmod.policy, - cfg.func.getattr.policy, - cfg.branches, - fusepath_, - mode_); -} int FUSE::chmod(const fuse_req_ctx_t *ctx_, const char *fusepath_, - mode_t mode_) + const mode_t mode_) { const fs::path fusepath{fusepath_}; - return ::_chmod(fusepath,mode_); + return cfg.chmod(cfg.branches, + fusepath, + mode_); } diff --git a/src/fuse_chmod.hpp b/src/fuse_chmod.hpp index c2a93af7..db8c0843 100644 --- a/src/fuse_chmod.hpp +++ b/src/fuse_chmod.hpp @@ -26,5 +26,5 @@ namespace FUSE int chmod(const fuse_req_ctx_t *ctx, const char *fusepath, - mode_t mode); + const mode_t mode); } diff --git a/src/fuse_chown.cpp b/src/fuse_chown.cpp index 2abb37b6..601ec62b 100644 --- a/src/fuse_chown.cpp +++ b/src/fuse_chown.cpp @@ -17,94 +17,18 @@ #include "fuse_chown.hpp" #include "config.hpp" -#include "errno.hpp" -#include "fs_lchown.hpp" -#include "fs_path.hpp" -#include "policy_rv.hpp" -#include "ugid.hpp" -#include "fuse.h" - -#include -#include - - -static -void -_chown_loop_core(const fs::path &basepath_, - const fs::path &fusepath_, - const uid_t uid_, - const gid_t gid_, - PolicyRV *prv_) -{ - fs::path fullpath; - - fullpath = basepath_ / fusepath_; - - errno = 0; - fs::lchown(fullpath,uid_,gid_); - - prv_->insert(errno,basepath_); -} - -static -void -_chown_loop(const std::vector &branches_, - const fs::path &fusepath_, - const uid_t uid_, - const gid_t gid_, - PolicyRV *prv_) -{ - for(const auto &branch : branches_) - { - ::_chown_loop_core(branch->path,fusepath_,uid_,gid_,prv_); - } -} - -static -int -_chown(const Policy::Action &actionFunc_, - const Policy::Search &searchFunc_, - const Branches &branches_, - const fs::path &fusepath_, - const uid_t uid_, - const gid_t gid_) -{ - int rv; - PolicyRV prv; - std::vector branches; - - rv = actionFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - ::_chown_loop(branches,fusepath_,uid_,gid_,&prv); - - if(prv.errors.empty()) - return 0; - if(prv.successes.empty()) - return prv.errors[0].rv; - - branches.clear(); - rv = searchFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - return prv.get_error(branches[0]->path); -} int FUSE::chown(const fuse_req_ctx_t *ctx_, const char *fusepath_, - uid_t uid_, - gid_t gid_) + const uid_t uid_, + const gid_t gid_) { const fs::path fusepath{fusepath_}; - return ::_chown(cfg.func.chown.policy, - cfg.func.getattr.policy, - cfg.branches, - fusepath, - uid_, - gid_); + return cfg.chown(cfg.branches, + fusepath, + uid_, + gid_); } diff --git a/src/fuse_getattr.cpp b/src/fuse_getattr.cpp index 6c441004..95a68a88 100644 --- a/src/fuse_getattr.cpp +++ b/src/fuse_getattr.cpp @@ -34,42 +34,6 @@ #include -static -void -_set_stat_if_leads_to_dir(const fs::path &path_, - struct stat *st_) -{ - int rv; - struct stat st; - - rv = fs::stat(path_,&st); - if(rv < 0) - return; - - if(S_ISDIR(st.st_mode)) - *st_ = st; - - return; -} - -static -void -_set_stat_if_leads_to_reg(const fs::path &path_, - struct stat *st_) -{ - int rv; - struct stat st; - - rv = fs::stat(path_,&st); - if(rv < 0) - return; - - if(S_ISREG(st.st_mode)) - *st_ = st; - - return; -} - static int _getattr_fake_root(struct stat *st_) @@ -116,61 +80,6 @@ _getattr_controlfile(struct stat *st_) return 0; } -static -int -_getattr(const Policy::Search &searchFunc_, - const Branches &branches_, - const fs::path &fusepath_, - struct stat *st_, - const bool symlinkify_, - const time_t symlinkify_timeout_, - FollowSymlinks followsymlinks_) -{ - int rv; - fs::path fullpath; - std::vector branches; - - rv = searchFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - fullpath = branches[0]->path / fusepath_; - - switch(followsymlinks_) - { - case FollowSymlinks::ENUM::NEVER: - rv = fs::lstat(fullpath,st_); - break; - case FollowSymlinks::ENUM::DIRECTORY: - rv = fs::lstat(fullpath,st_); - if(S_ISLNK(st_->st_mode)) - ::_set_stat_if_leads_to_dir(fullpath,st_); - break; - case FollowSymlinks::ENUM::REGULAR: - rv = fs::lstat(fullpath,st_); - if(S_ISLNK(st_->st_mode)) - ::_set_stat_if_leads_to_reg(fullpath,st_); - break; - case FollowSymlinks::ENUM::ALL: - rv = fs::stat(fullpath,st_); - if(rv < 0) - rv = fs::lstat(fullpath,st_); - break; - } - - if(rv < 0) - return rv; - - if(symlinkify_ && symlinkify::can_be_symlink(*st_,symlinkify_timeout_)) - symlinkify::convert(fullpath,st_); - - fs::inode::calc(branches[0]->path, - fusepath_, - st_); - - return 0; -} - int _getattr(const fs::path &fusepath_, struct stat *st_, @@ -178,13 +87,11 @@ _getattr(const fs::path &fusepath_, { int rv; - rv = ::_getattr(cfg.func.getattr.policy, - cfg.branches, - fusepath_, - st_, - cfg.symlinkify, - cfg.symlinkify_timeout, - cfg.follow_symlinks); + rv = cfg.getattr(cfg.branches, + fusepath_, + st_, + cfg.follow_symlinks, + cfg.symlinkify_timeout); if((rv < 0) && Config::is_rootdir(fusepath_)) return ::_getattr_fake_root(st_); diff --git a/src/fuse_getxattr.cpp b/src/fuse_getxattr.cpp index 7e09ef4f..3545dc1c 100644 --- a/src/fuse_getxattr.cpp +++ b/src/fuse_getxattr.cpp @@ -121,21 +121,21 @@ _getxattr_user_mergerfs(const fs::path &basepath_, const fs::path &fullpath_, const Branches &branches_, const char *attrname_, - char *buf_, - const size_t count_) + char *attrval_, + const size_t attrvalsize_) { std::string key; key = Config::prune_ctrl_xattr(attrname_); if(key == "basepath") - return ::_getxattr_from_string(buf_,count_,basepath_); + return ::_getxattr_from_string(attrval_,attrvalsize_,basepath_); if(key == "relpath") - return ::_getxattr_from_string(buf_,count_,fusepath_); + return ::_getxattr_from_string(attrval_,attrvalsize_,fusepath_); if(key == "fullpath") - return ::_getxattr_from_string(buf_,count_,fullpath_); + return ::_getxattr_from_string(attrval_,attrvalsize_,fullpath_); if(key == "allpaths") - return ::_getxattr_user_mergerfs_allpaths(branches_,fusepath_,buf_,count_); + return ::_getxattr_user_mergerfs_allpaths(branches_,fusepath_,attrval_,attrvalsize_); return -ENOATTR; } @@ -146,45 +146,51 @@ _getxattr(const Policy::Search &searchFunc_, const Branches &branches_, const fs::path &fusepath_, const char *attrname_, - char *buf_, - const size_t count_) + char *attrval_, + const size_t attrvalsize_) { - int rv; - fs::path fullpath; - std::vector branches; - - rv = searchFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - fullpath = branches[0]->path / fusepath_; - if(Config::is_mergerfs_xattr(attrname_)) - return ::_getxattr_user_mergerfs(branches[0]->path, - fusepath_, - fullpath, - branches_, - attrname_, - buf_, - count_); - - return fs::lgetxattr(fullpath,attrname_,buf_,count_); + { + int rv; + fs::path fullpath; + std::vector branches; + + rv = searchFunc_(branches_,fusepath_,branches); + if(rv < 0) + return rv; + + fullpath = branches[0]->path / fusepath_; + + return ::_getxattr_user_mergerfs(branches[0]->path, + fusepath_, + fullpath, + branches_, + attrname_, + attrval_, + attrvalsize_); + } + + return cfg.getxattr(branches_, + fusepath_, + attrname_, + attrval_, + attrvalsize_); } int FUSE::getxattr(const fuse_req_ctx_t *ctx_, const char *fusepath_, const char *attrname_, - char *attrvalue_, - size_t attrvalue_size_) + char *attrval_, + size_t attrvalsize_) { const fs::path fusepath{fusepath_}; if(Config::is_ctrl_file(fusepath)) return ::_getxattr_ctrl_file(cfg, attrname_, - attrvalue_, - attrvalue_size_); + attrval_, + attrvalsize_); if((cfg.security_capability == false) && ::_is_attrname_security_capability(attrname_)) @@ -193,10 +199,10 @@ FUSE::getxattr(const fuse_req_ctx_t *ctx_, if(cfg.xattr.to_int()) return -cfg.xattr.to_int(); - return ::_getxattr(cfg.func.getxattr.policy, + return ::_getxattr(cfg.func.getattr.policy, cfg.branches, fusepath, attrname_, - attrvalue_, - attrvalue_size_); + attrval_, + attrvalsize_); } diff --git a/src/fuse_listxattr.cpp b/src/fuse_listxattr.cpp index 7ae092ff..06e0046a 100644 --- a/src/fuse_listxattr.cpp +++ b/src/fuse_listxattr.cpp @@ -17,117 +17,16 @@ #include "fuse_listxattr.hpp" #include "config.hpp" -#include "errno.hpp" -#include "fs_llistxattr.hpp" -#include "ugid.hpp" #include "xattr.hpp" -#include "fuse.h" - -#include -#include -#include -#include - - -static -ssize_t -_listxattr_size(const std::vector &branches_, - const fs::path &fusepath_) -{ - ssize_t size; - fs::path fullpath; - - if(branches_.empty()) - return -ENOENT; - - size = 0; - for(const auto branch : branches_) - { - ssize_t rv; - - fullpath = branch->path / fusepath_; - - rv = fs::llistxattr(fullpath,NULL,0); - if(rv < 0) - continue; - - size += rv; - } - - return size; -} - -static -ssize_t -_listxattr(const std::vector &branches_, - const fs::path &fusepath_, - char *list_, - size_t size_) -{ - ssize_t rv; - ssize_t size; - fs::path fullpath; - std::optional err; - - if(size_ == 0) - return ::_listxattr_size(branches_,fusepath_); - - size = 0; - err = -ENOENT; - for(const auto branch : branches_) - { - fullpath = branch->path / fusepath_; - - rv = fs::llistxattr(fullpath,list_,size_); - if(rv == -ERANGE) - return -ERANGE; - if(rv < 0) - { - if(!err.has_value()) - err = rv; - continue; - } - - err = 0; - list_ += rv; - size_ -= rv; - size += rv; - } - - if(err < 0) - return err.value(); - - return size; -} - -static -int -_listxattr(const Policy::Search &searchFunc_, - const Branches &ibranches_, - const fs::path &fusepath_, - char *list_, - const size_t size_) -{ - int rv; - std::vector obranches; - - rv = searchFunc_(ibranches_,fusepath_,obranches); - if(rv < 0) - return rv; - - if(size_ == 0) - return ::_listxattr_size(obranches,fusepath_); - - return ::_listxattr(obranches,fusepath_,list_,size_); -} int FUSE::listxattr(const fuse_req_ctx_t *ctx_, const char *fusepath_, char *list_, - size_t size_) + const size_t size_) { + ssize_t rv; const fs::path fusepath{fusepath_}; if(Config::is_ctrl_file(fusepath)) @@ -143,9 +42,10 @@ FUSE::listxattr(const fuse_req_ctx_t *ctx_, return -ENOSYS; } - return ::_listxattr(cfg.func.listxattr.policy, - cfg.branches, - fusepath, - list_, - size_); + rv = cfg.listxattr(cfg.branches, + fusepath, + list_, + size_); + + return rv; } diff --git a/src/fuse_readlink.cpp b/src/fuse_readlink.cpp index 3a0123eb..5a337f36 100644 --- a/src/fuse_readlink.cpp +++ b/src/fuse_readlink.cpp @@ -17,102 +17,7 @@ #include "fuse_readlink.hpp" #include "config.hpp" -#include "errno.hpp" -#include "fs_lstat.hpp" -#include "fs_path.hpp" -#include "fs_readlink.hpp" -#include "symlinkify.hpp" -#include "ugid.hpp" -#include "fuse.h" - -#include - - -static -int -_readlink_core_standard(const fs::path &fullpath_, - char *buf_, - const size_t size_) - -{ - int rv; - - rv = fs::readlink(fullpath_,buf_,size_); - if(rv < 0) - return rv; - - buf_[rv] = '\0'; - - return 0; -} - -static -int -_readlink_core_symlinkify(const fs::path &fullpath_, - char *buf_, - const size_t size_, - const time_t symlinkify_timeout_) -{ - int rv; - struct stat st; - - rv = fs::lstat(fullpath_,&st); - if(rv < 0) - return rv; - - if(!symlinkify::can_be_symlink(st,symlinkify_timeout_)) - return ::_readlink_core_standard(fullpath_,buf_,size_); - - strncpy(buf_,fullpath_.c_str(),size_); - - return 0; -} - -static -int -_readlink_core(const fs::path &basepath_, - const fs::path &fusepath_, - char *buf_, - const size_t size_, - const bool symlinkify_, - const time_t symlinkify_timeout_) -{ - fs::path fullpath; - - fullpath = basepath_ / fusepath_; - - if(symlinkify_) - return ::_readlink_core_symlinkify(fullpath,buf_,size_,symlinkify_timeout_); - - return ::_readlink_core_standard(fullpath,buf_,size_); -} - -static -int -_readlink(const Policy::Search &searchFunc_, - const Branches &ibranches_, - const fs::path &fusepath_, - char *buf_, - const size_t size_, - const bool symlinkify_, - const time_t symlinkify_timeout_) -{ - int rv; - StrVec basepaths; - std::vector obranches; - - rv = searchFunc_(ibranches_,fusepath_,obranches); - if(rv < 0) - return rv; - - return ::_readlink_core(obranches[0]->path, - fusepath_, - buf_, - size_, - symlinkify_, - symlinkify_timeout_); -} int FUSE::readlink(const fuse_req_ctx_t *ctx_, @@ -122,11 +27,9 @@ FUSE::readlink(const fuse_req_ctx_t *ctx_, { const fs::path fusepath{fusepath_}; - return ::_readlink(cfg.func.readlink.policy, - cfg.branches, - fusepath, - buf_, - size_, - cfg.symlinkify, - cfg.symlinkify_timeout); + return cfg.readlink(cfg.branches, + fusepath, + buf_, + size_, + cfg.symlinkify_timeout); } diff --git a/src/fuse_removexattr.cpp b/src/fuse_removexattr.cpp index c952d98a..8ad60189 100644 --- a/src/fuse_removexattr.cpp +++ b/src/fuse_removexattr.cpp @@ -18,75 +18,9 @@ #include "config.hpp" #include "errno.hpp" -#include "fs_lremovexattr.hpp" -#include "fs_path.hpp" -#include "policy_rv.hpp" -#include "ugid.hpp" #include "fuse.h" -#include - - -static -void -_removexattr_loop_core(const fs::path &basepath_, - const fs::path &fusepath_, - const char *attrname_, - PolicyRV *prv_) -{ - fs::path fullpath; - - fullpath = basepath_ / fusepath_; - - errno = 0; - fs::lremovexattr(fullpath,attrname_); - - prv_->insert(errno,basepath_); -} - -static -void -_removexattr_loop(const std::vector &branches_, - const fs::path &fusepath_, - const char *attrname_, - PolicyRV *prv_) -{ - for(auto &branch : branches_) - { - ::_removexattr_loop_core(branch->path,fusepath_,attrname_,prv_); - } -} - -static -int -_removexattr(const Policy::Action &actionFunc_, - const Policy::Search &searchFunc_, - const Branches &ibranches_, - const fs::path &fusepath_, - const char *attrname_) -{ - int rv; - PolicyRV prv; - std::vector obranches; - - rv = actionFunc_(ibranches_,fusepath_,obranches); - if(rv < 0) - return rv; - - ::_removexattr_loop(obranches,fusepath_,attrname_,&prv); - if(prv.errors.empty()) - return 0; - if(prv.successes.empty()) - return prv.errors[0].rv; - - obranches.clear(); - rv = searchFunc_(ibranches_,fusepath_,obranches); - if(rv < 0) - return rv; - - return prv.get_error(obranches[0]->path); -} int FUSE::removexattr(const fuse_req_ctx_t *ctx_, @@ -96,14 +30,12 @@ FUSE::removexattr(const fuse_req_ctx_t *ctx_, const fs::path fusepath{fusepath_}; if(Config::is_ctrl_file(fusepath)) - return -ENOATTR; + return -EROFS; if(cfg.xattr.to_int()) return -cfg.xattr.to_int(); - return ::_removexattr(cfg.func.removexattr.policy, - cfg.func.getxattr.policy, - cfg.branches, - fusepath, - attrname_); + return cfg.removexattr(cfg.branches, + fusepath, + attrname_); } diff --git a/src/fuse_rmdir.cpp b/src/fuse_rmdir.cpp index 5a7cff2e..d1db6150 100644 --- a/src/fuse_rmdir.cpp +++ b/src/fuse_rmdir.cpp @@ -17,88 +17,14 @@ #include "fuse_rmdir.hpp" #include "config.hpp" -#include "errno.hpp" -#include "error.hpp" -#include "fs_path.hpp" -#include "fs_rmdir.hpp" -#include "fs_unlink.hpp" -#include "ugid.hpp" -#include "fuse.h" - -#include - -#include - - -static -int -_should_unlink(int rv_, - FollowSymlinks followsymlinks_) -{ - return ((rv_ == -ENOTDIR) && - (followsymlinks_ != FollowSymlinks::ENUM::NEVER)); -} - -static -int -_rmdir_core(const fs::path &basepath_, - const fs::path &fusepath_, - const FollowSymlinks followsymlinks_) -{ - int rv; - fs::path fullpath; - - fullpath = basepath_ / fusepath_; - - rv = fs::rmdir(fullpath); - if(::_should_unlink(rv,followsymlinks_)) - rv = fs::unlink(fullpath); - - return rv; -} - -static -int -_rmdir_loop(const std::vector &branches_, - const fs::path &fusepath_, - const FollowSymlinks followsymlinks_) -{ - Err err; - - for(const auto &branch : branches_) - { - err = ::_rmdir_core(branch->path,fusepath_,followsymlinks_); - } - - return err; -} - -static -int -_rmdir(const Policy::Action &actionFunc_, - const Branches &branches_, - const FollowSymlinks followsymlinks_, - const fs::path &fusepath_) -{ - int rv; - std::vector branches; - - rv = actionFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - return ::_rmdir_loop(branches,fusepath_,followsymlinks_); -} int FUSE::rmdir(const fuse_req_ctx_t *ctx_, const char *fusepath_) { - const fs::path fusepath{fusepath_}; + const fs::path fusepath{fusepath_}; - return ::_rmdir(cfg.func.rmdir.policy, - cfg.branches, - cfg.follow_symlinks, - fusepath); + return cfg.rmdir(cfg.branches, + fusepath); } diff --git a/src/fuse_setxattr.cpp b/src/fuse_setxattr.cpp index 23dacb07..49116478 100644 --- a/src/fuse_setxattr.cpp +++ b/src/fuse_setxattr.cpp @@ -99,107 +99,6 @@ _setxattr_ctrl_file(const char *attrname_, return rv; } -static -void -_setxattr_loop_core(const fs::path &basepath_, - const fs::path &fusepath_, - const char *attrname_, - const char *attrval_, - const size_t attrvalsize_, - const int flags_, - PolicyRV *prv_) -{ - fs::path fullpath; - - fullpath = basepath_ / fusepath_; - - errno = 0; - fs::lsetxattr(fullpath,attrname_,attrval_,attrvalsize_,flags_); - - prv_->insert(errno,basepath_); -} - -static -void -_setxattr_loop(const std::vector &branches_, - const fs::path &fusepath_, - const char *attrname_, - const char *attrval_, - const size_t attrvalsize_, - const int flags_, - PolicyRV *prv_) -{ - for(auto &branch : branches_) - { - ::_setxattr_loop_core(branch->path, - fusepath_, - attrname_, - attrval_,attrvalsize_, - flags_, - prv_); - } -} - -static -int -_setxattr(const Policy::Action &setxattrPolicy_, - const Policy::Search &getxattrPolicy_, - const Branches &branches_, - const fs::path &fusepath_, - const char *attrname_, - const char *attrval_, - const size_t attrvalsize_, - const int flags_) -{ - int rv; - PolicyRV prv; - std::vector branches; - - rv = setxattrPolicy_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - ::_setxattr_loop(branches,fusepath_,attrname_,attrval_,attrvalsize_,flags_,&prv); - if(prv.errors.empty()) - return 0; - if(prv.successes.empty()) - return prv.errors[0].rv; - - branches.clear(); - rv = getxattrPolicy_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - return prv.get_error(branches[0]->path); -} - -static -int -_setxattr(const fuse_req_ctx_t *ctx_, - const fs::path &fusepath_, - const char *attrname_, - const char *attrval_, - size_t attrvalsize_, - int flags_) -{ - if((cfg.security_capability == false) && - ::_is_attrname_security_capability(attrname_)) - return -ENOATTR; - - if(cfg.xattr.to_int()) - return -cfg.xattr.to_int(); - - return ::_setxattr(cfg.func.setxattr.policy, - cfg.func.getxattr.policy, - cfg.branches, - fusepath_, - attrname_, - attrval_, - attrvalsize_, - flags_); -} - - int FUSE::setxattr(const fuse_req_ctx_t *ctx_, const char *fusepath_, @@ -216,10 +115,17 @@ FUSE::setxattr(const fuse_req_ctx_t *ctx_, attrvalsize_, flags_); - return ::_setxattr(ctx_, - fusepath, - attrname_, - attrval_, - attrvalsize_, - flags_); + if((cfg.security_capability == false) && + ::_is_attrname_security_capability(attrname_)) + return -ENOATTR; + + if(cfg.xattr.to_int()) + return -cfg.xattr.to_int(); + + return cfg.setxattr(cfg.branches, + fusepath, + attrname_, + attrval_, + attrvalsize_, + flags_); } diff --git a/src/fuse_statx_supported.icpp b/src/fuse_statx_supported.icpp index 6e99e9ef..5515b1e2 100644 --- a/src/fuse_statx_supported.icpp +++ b/src/fuse_statx_supported.icpp @@ -16,7 +16,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - #include "fuse_statx.hpp" #include "config.hpp" @@ -30,49 +29,11 @@ #include "symlinkify.hpp" #include "ugid.hpp" -#include "fmt/core.h" - #include "fuse.h" #include -static -void -_set_stat_if_leads_to_dir(const fs::path &path_, - struct fuse_statx *st_) -{ - int rv; - struct fuse_statx st; - - rv = fs::statx(AT_FDCWD,path_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st); - if(rv < 0) - return; - - if(S_ISDIR(st.mode)) - *st_ = st; - - return; -} - -static -void -_set_stat_if_leads_to_reg(const fs::path &path_, - struct fuse_statx *st_) -{ - int rv; - struct fuse_statx st; - - rv = fs::statx(AT_FDCWD,path_,AT_SYMLINK_FOLLOW,STATX_TYPE,&st); - if(rv < 0) - return; - - if(S_ISREG(st.mode)) - *st_ = st; - - return; -} - static int _statx_fake_root(struct fuse_statx *st_) @@ -113,82 +74,23 @@ _statx_controlfile(struct fuse_statx *st_) return 0; } -static -int -_statx(const Policy::Search &searchFunc_, - const Branches &branches_, - const fs::path &fusepath_, - const uint32_t flags_, - const uint32_t mask_, - struct fuse_statx *st_, - const bool symlinkify_, - const time_t symlinkify_timeout_, - FollowSymlinks followsymlinks_) -{ - int rv; - fs::path fullpath; - std::vector branches; - - rv = searchFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - fullpath = branches[0]->path / fusepath_; - - switch(followsymlinks_) - { - case FollowSymlinks::ENUM::NEVER: - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); - break; - case FollowSymlinks::ENUM::DIRECTORY: - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); - if((rv >= 0) && S_ISLNK(st_->mode)) - ::_set_stat_if_leads_to_dir(fullpath,st_); - break; - case FollowSymlinks::ENUM::REGULAR: - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); - if((rv >= 0) && S_ISLNK(st_->mode)) - ::_set_stat_if_leads_to_reg(fullpath,st_); - break; - case FollowSymlinks::ENUM::ALL: - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_FOLLOW,mask_,st_); - if(rv < 0) - rv = fs::statx(AT_FDCWD,fullpath,flags_|AT_SYMLINK_NOFOLLOW,mask_,st_); - break; - } - - if(rv < 0) - return rv; - - if(symlinkify_ && symlinkify::can_be_symlink(*st_,symlinkify_timeout_)) - symlinkify::convert(fullpath,st_); - - fs::inode::calc(branches[0]->path, - fusepath_, - st_); - - return 0; -} - static int _statx(const fs::path &fusepath_, - const uint32_t flags_, - const uint32_t mask_, + const u32 flags_, + const u32 mask_, struct fuse_statx *st_, fuse_timeouts_t *timeout_) { int rv; - rv = ::_statx(cfg.func.getattr.policy, - cfg.branches, - fusepath_, - flags_, - mask_, - st_, - cfg.symlinkify, - cfg.symlinkify_timeout, - cfg.follow_symlinks); + rv = cfg.statx(cfg.branches, + fusepath_, + flags_, + mask_, + st_, + cfg.follow_symlinks, + cfg.symlinkify_timeout); if((rv < 0) && Config::is_rootdir(fusepath_)) return ::_statx_fake_root(st_); @@ -203,8 +105,8 @@ _statx(const fs::path &fusepath_, int FUSE::statx(const fuse_req_ctx_t *ctx_, const char *fusepath_, - const uint32_t flags_, - const uint32_t mask_, + const u32 flags_, + const u32 mask_, struct fuse_statx *st_, fuse_timeouts_t *timeout_) { @@ -222,9 +124,9 @@ FUSE::statx(const fuse_req_ctx_t *ctx_, int FUSE::statx_fh(const fuse_req_ctx_t *ctx_, - const uint64_t fh_, - const uint32_t flags_, - const uint32_t mask_, + const u64 fh_, + const u32 flags_, + const u32 mask_, struct fuse_statx *st_, fuse_timeouts_t *timeout_) { diff --git a/src/fuse_truncate.cpp b/src/fuse_truncate.cpp index f3008268..bea0c97d 100644 --- a/src/fuse_truncate.cpp +++ b/src/fuse_truncate.cpp @@ -17,77 +17,7 @@ #include "fuse_truncate.hpp" #include "config.hpp" -#include "errno.hpp" -#include "fs_path.hpp" -#include "fs_truncate.hpp" -#include "policy_rv.hpp" -#include "ugid.hpp" -#include "fuse.h" - -#include -#include - - -static -void -_truncate_loop_core(const fs::path &basepath_, - const fs::path &fusepath_, - const off_t size_, - PolicyRV *prv_) -{ - int rv; - fs::path fullpath; - - fullpath = basepath_ / fusepath_; - - rv = fs::truncate(fullpath,size_); - - prv_->insert(rv,basepath_); -} - -static -void -_truncate_loop(const std::vector &branches_, - const fs::path &fusepath_, - const off_t size_, - PolicyRV *prv_) -{ - for(auto &branch : branches_) - { - ::_truncate_loop_core(branch->path,fusepath_,size_,prv_); - } -} - -static -int -_truncate(const Policy::Action &actionFunc_, - const Policy::Search &searchFunc_, - const Branches &branches_, - const fs::path &fusepath_, - const off_t size_) -{ - int rv; - PolicyRV prv; - std::vector branches; - - rv = actionFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - ::_truncate_loop(branches,fusepath_,size_,&prv); - if(prv.errors.empty()) - return 0; - if(prv.successes.empty()) - return prv.errors[0].rv; - - branches.clear(); - rv = searchFunc_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - return prv.get_error(branches[0]->path); -} int FUSE::truncate(const fuse_req_ctx_t *ctx_, @@ -96,9 +26,5 @@ FUSE::truncate(const fuse_req_ctx_t *ctx_, { const fs::path fusepath{fusepath_}; - return ::_truncate(cfg.func.truncate.policy, - cfg.func.getattr.policy, - cfg.branches, - fusepath, - size_); + return cfg.truncate(cfg.branches,fusepath,size_); } diff --git a/src/fuse_unlink.cpp b/src/fuse_unlink.cpp index a870c930..b2b29122 100644 --- a/src/fuse_unlink.cpp +++ b/src/fuse_unlink.cpp @@ -17,52 +17,7 @@ #include "fuse_unlink.hpp" #include "config.hpp" -#include "errno.hpp" -#include "error.hpp" -#include "fs_path.hpp" -#include "fs_unlink.hpp" -#include "ugid.hpp" -#include "fuse.h" - -#include - -#include - - -static -int -_unlink_loop(const std::vector &branches_, - const fs::path &fusepath_) -{ - Err err; - fs::path fullpath; - - for(const auto &branch : branches_) - { - fullpath = branch->path / fusepath_; - - err = fs::unlink(fullpath); - } - - return err; -} - -static -int -_unlink(const Policy::Action &unlinkPolicy_, - const Branches &branches_, - const fs::path &fusepath_) -{ - int rv; - std::vector branches; - - rv = unlinkPolicy_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - return ::_unlink_loop(branches,fusepath_); -} int FUSE::unlink(const fuse_req_ctx_t *ctx_, @@ -70,7 +25,5 @@ FUSE::unlink(const fuse_req_ctx_t *ctx_, { const fs::path fusepath{fusepath_}; - return ::_unlink(cfg.func.unlink.policy, - cfg.branches, - fusepath); + return cfg.unlink(cfg.branches,fusepath); } diff --git a/src/fuse_utimens.cpp b/src/fuse_utimens.cpp index 485a14f2..4df58ea2 100644 --- a/src/fuse_utimens.cpp +++ b/src/fuse_utimens.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2016, Antonio SJ Musumeci + Copyright (c) 2025, Antonio SJ Musumeci Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -17,76 +17,7 @@ #include "fuse_utimens.hpp" #include "config.hpp" -#include "errno.hpp" -#include "fs_lutimens.hpp" -#include "fs_path.hpp" -#include "policy_rv.hpp" -#include "ugid.hpp" -#include "fuse.h" - -#include - - -static -void -_utimens_loop_core(const fs::path &basepath_, - const fs::path &fusepath_, - const timespec ts_[2], - PolicyRV *prv_) -{ - int rv; - fs::path fullpath; - - fullpath = basepath_ / fusepath_; - - rv = fs::lutimens(fullpath,ts_); - - prv_->insert(rv,basepath_); -} - -static -void -_utimens_loop(const std::vector &branches_, - const fs::path &fusepath_, - const timespec ts_[2], - PolicyRV *prv_) -{ - for(auto &branch : branches_) - { - ::_utimens_loop_core(branch->path,fusepath_,ts_,prv_); - } -} - -static -int -_utimens(const Policy::Action &utimensPolicy_, - const Policy::Search &getattrPolicy_, - const Branches &branches_, - const fs::path &fusepath_, - const timespec ts_[2]) -{ - int rv; - PolicyRV prv; - std::vector branches; - - rv = utimensPolicy_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - ::_utimens_loop(branches,fusepath_,ts_,&prv); - if(prv.errors.empty()) - return 0; - if(prv.successes.empty()) - return prv.errors[0].rv; - - branches.clear(); - rv = getattrPolicy_(branches_,fusepath_,branches); - if(rv < 0) - return rv; - - return prv.get_error(branches[0]->path); -} int FUSE::utimens(const fuse_req_ctx_t *ctx_, @@ -95,9 +26,5 @@ FUSE::utimens(const fuse_req_ctx_t *ctx_, { const fs::path fusepath{fusepath_}; - return ::_utimens(cfg.func.utimens.policy, - cfg.func.getattr.policy, - cfg.branches, - fusepath, - ts_); + return cfg.utimens(cfg.branches,fusepath,ts_); } diff --git a/src/timespec_utils.hpp b/src/timespec_utils.hpp new file mode 100644 index 00000000..789d0c4a --- /dev/null +++ b/src/timespec_utils.hpp @@ -0,0 +1,157 @@ +#pragma once + +static +inline +bool +operator<(const timespec &lhs_, + const timespec &rhs_) +{ + if(lhs_.tv_sec != rhs_.tv_sec) + return lhs_.tv_sec < rhs_.tv_sec; + return lhs_.tv_nsec < rhs_.tv_nsec; +} + +static +inline +bool +operator>(const timespec &lhs_, + const timespec &rhs_) +{ + if(lhs_.tv_sec != rhs_.tv_sec) + return lhs_.tv_sec > rhs_.tv_sec; + return lhs_.tv_nsec > rhs_.tv_nsec; +} + +static +inline +bool +operator==(const timespec &lhs_, + const timespec &rhs_) +{ + return ((lhs_.tv_sec == rhs_.tv_sec) && + (lhs_.tv_nsec == rhs_.tv_nsec)); +} + +static +inline +bool +operator!=(const timespec &lhs_, + const timespec &rhs_) +{ + return !(lhs_ == rhs_); +} + +static +inline +bool +operator<=(const timespec &lhs_, + const timespec &rhs_) +{ + return !(lhs_ > rhs_); +} + +static +inline +bool +operator>=(const timespec &lhs_, + const timespec &rhs_) +{ + return !(lhs_ < rhs_); +} + +static +inline +bool +operator<(const fuse_sx_time &lhs_, + const fuse_sx_time &rhs_) +{ + if(lhs_.tv_sec != rhs_.tv_sec) + return lhs_.tv_sec < rhs_.tv_sec; + return lhs_.tv_nsec < rhs_.tv_nsec; +} + +static +inline +bool +operator>(const fuse_sx_time &lhs_, + const fuse_sx_time &rhs_) +{ + if(lhs_.tv_sec != rhs_.tv_sec) + return lhs_.tv_sec > rhs_.tv_sec; + return lhs_.tv_nsec > rhs_.tv_nsec; +} + +static +inline +bool +operator==(const fuse_sx_time &lhs_, + const fuse_sx_time &rhs_) +{ + return ((lhs_.tv_sec == rhs_.tv_sec) && + (lhs_.tv_nsec == rhs_.tv_nsec)); +} + +static +inline +bool +operator!=(const fuse_sx_time &lhs_, + const fuse_sx_time &rhs_) +{ + return !(lhs_ == rhs_); +} + +static +inline +bool +operator<=(const fuse_sx_time &lhs_, + const fuse_sx_time &rhs_) +{ + return !(lhs_ > rhs_); +} + +static +inline +bool +operator>=(const fuse_sx_time &lhs_, + const fuse_sx_time &rhs_) +{ + return !(lhs_ < rhs_); +} + + +namespace TimeSpec +{ + static + inline + timespec + newest(const timespec &t0_, + const timespec &t1_) + { + if(t0_.tv_sec > t1_.tv_sec) + return t0_; + if(t0_.tv_sec == t1_.tv_sec) + { + if(t0_.tv_nsec > t1_.tv_nsec) + return t0_; + } + + return t1_; + } + + static + inline + fuse_sx_time + newest(const fuse_sx_time &t0_, + const fuse_sx_time &t1_) + { + if(t0_.tv_sec > t1_.tv_sec) + return t0_; + if(t0_.tv_sec == t1_.tv_sec) + { + if(t0_.tv_nsec > t1_.tv_nsec) + return t0_; + } + + return t1_; + } +} diff --git a/src/to_cstr.hpp b/src/to_cstr.hpp new file mode 100644 index 00000000..85da6ff4 --- /dev/null +++ b/src/to_cstr.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + + +template +const char* +to_cstr(const PathType &p_) +{ + if constexpr (std::is_same_v, std::filesystem::path>) + return p_.c_str(); + if constexpr (std::is_same_v, std::string>) + return p_.c_str(); + if constexpr (std::is_same_v, const char*> || + std::is_same_v, char*>) + return p_; + + abort(); + return NULL; +} diff --git a/tests/tests.cpp b/tests/tests.cpp index 49e01459..9acef855 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -2,6 +2,8 @@ #include "config.hpp" #include "str.hpp" +#include "error.hpp" + void test_nop() @@ -123,12 +125,11 @@ test_str_stuff() void test_config_branches() { - uint64_t minfreespace; - Branches b(minfreespace); + Branches b; Branches::Ptr bcp0; Branches::Ptr bcp1; - minfreespace = 1234; + b.minfreespace = 1234; TEST_CHECK(b->minfreespace() == 1234); TEST_CHECK(b.to_string() == ""); @@ -304,6 +305,20 @@ test_config() TEST_CHECK(cfg.set("async-read","true") == 0); } +void +test_err() +{ + Err err; + + TEST_CHECK((err = -ENOENT) == -ENOENT); + TEST_CHECK((err = -EROFS) == -EROFS); + TEST_CHECK((err = -ENOENT) == -EROFS); + TEST_CHECK((err = -ENAMETOOLONG) == -ENAMETOOLONG); + TEST_CHECK((err = -EIO) == -ENAMETOOLONG); + TEST_CHECK((err = 0) == 0); + TEST_CHECK((err = -EIO) == 0); +} + TEST_LIST = { {"nop",test_nop}, @@ -322,5 +337,6 @@ TEST_LIST = {"config_xattr",test_config_xattr}, {"config",test_config}, {"str",test_str_stuff}, + {"err",test_err}, {NULL,NULL} };