From d8ba75cca3e3bb632f3a482c9aca3c7c5b646cd8 Mon Sep 17 00:00:00 2001 From: "Antonio S. Musumeci" Date: Tue, 26 May 2026 21:30:38 -0400 Subject: [PATCH] checkpoint --- src/category.cpp | 7 ++ src/config_moveonenospc.cpp | 27 +++++- src/config_moveonenospc.hpp | 8 +- src/fs_movefile_and_open.cpp | 161 +++++++++++++++++++++++++++---- src/fs_movefile_and_open.hpp | 20 ++-- src/func_access_base.hpp | 2 +- src/func_access_factory.cpp | 25 ++++- src/func_chmod_all.cpp | 9 +- src/func_chmod_base.hpp | 2 +- src/func_chmod_factory.cpp | 23 ++++- src/func_chown_all.cpp | 9 +- src/func_chown_base.hpp | 2 +- src/func_chown_factory.cpp | 23 ++++- src/func_create_base.hpp | 2 +- src/func_create_lup.cpp | 2 +- src/func_getattr_base.hpp | 2 +- src/func_getattr_cdco.cpp | 3 +- src/func_getattr_cdfo.cpp | 4 +- src/func_getattr_factory.cpp | 22 ++++- src/func_getattr_ff.cpp | 4 +- src/func_getattr_newest.cpp | 4 +- src/func_getxattr_base.hpp | 2 +- src/func_getxattr_factory.cpp | 23 ++++- src/func_ioctl_base.hpp | 2 +- src/func_ioctl_factory.cpp | 23 ++++- src/func_link_base.hpp | 2 +- src/func_link_epall.cpp | 24 ++--- src/func_link_factory.cpp | 23 ++++- src/func_listxattr_base.hpp | 2 +- src/func_listxattr_factory.cpp | 23 ++++- src/func_mkdir_all.cpp | 77 ++++++++------- src/func_mkdir_base.hpp | 2 +- src/func_mkdir_epall.cpp | 45 +++++---- src/func_mkdir_lup.cpp | 2 +- src/func_mknod_all.cpp | 68 ++++++------- src/func_mknod_base.hpp | 2 +- src/func_mknod_epall.cpp | 36 ++++--- src/func_mknod_lup.cpp | 2 +- src/func_open_base.hpp | 2 +- src/func_open_factory.cpp | 23 ++++- src/func_readlink_base.hpp | 2 +- src/func_readlink_factory.cpp | 23 ++++- src/func_removexattr_all.cpp | 9 +- src/func_removexattr_base.hpp | 2 +- src/func_removexattr_factory.cpp | 23 ++++- src/func_rename_base.hpp | 2 +- src/func_rename_epall.cpp | 30 +++--- src/func_rename_factory.cpp | 23 ++++- src/func_rmdir_all.cpp | 15 ++- src/func_rmdir_base.hpp | 2 +- src/func_rmdir_factory.cpp | 23 ++++- src/func_setxattr_all.cpp | 9 +- src/func_setxattr_base.hpp | 2 +- src/func_setxattr_factory.cpp | 23 ++++- src/func_statx_base.hpp | 2 +- src/func_statx_cdco.cpp | 4 +- src/func_statx_cdfo.cpp | 4 +- src/func_statx_factory.cpp | 22 ++++- src/func_statx_ff.cpp | 4 +- src/func_statx_newest.cpp | 4 +- src/func_symlink_all.cpp | 83 ++++++++-------- src/func_symlink_base.hpp | 2 +- src/func_symlink_epall.cpp | 49 ++++++---- src/func_symlink_lup.cpp | 2 +- src/func_symlink_msplfs.cpp | 2 +- src/func_symlink_msplus.cpp | 2 +- src/func_symlink_mspmfs.cpp | 2 +- src/func_symlink_msppfrd.cpp | 2 +- src/func_truncate_all.cpp | 9 +- src/func_truncate_base.hpp | 2 +- src/func_truncate_factory.cpp | 23 ++++- src/func_unlink_all.cpp | 9 +- src/func_unlink_base.hpp | 2 +- src/func_unlink_factory.cpp | 21 +++- src/func_utimens_all.cpp | 9 +- src/func_utimens_base.hpp | 2 +- src/func_utimens_factory.cpp | 23 ++++- src/fuse_link.cpp | 101 ++++++++++++------- src/fuse_rename.cpp | 101 ++++++++++++++----- src/fuse_write.cpp | 6 +- 80 files changed, 1051 insertions(+), 373 deletions(-) diff --git a/src/category.cpp b/src/category.cpp index e140a30a..54f424f2 100644 --- a/src/category.cpp +++ b/src/category.cpp @@ -27,6 +27,13 @@ Category::Base::from_string(const std::string_view s_) { int rv; + // "mixed" is the sentinel to_string emits when constituent funcs + // disagree. Accepting it as a no-op makes config save/restore work + // even when per-function overrides have diverged from the + // category-wide value. + if(s_ == "mixed") + return 0; + for(auto func : funcs) { rv = func->from_string(s_); diff --git a/src/config_moveonenospc.cpp b/src/config_moveonenospc.cpp index 4811bcfc..001d7648 100644 --- a/src/config_moveonenospc.cpp +++ b/src/config_moveonenospc.cpp @@ -20,21 +20,42 @@ #include "errno.hpp" #include "from_string.hpp" +#include "func_create_factory.hpp" +MoveOnENOSPC::MoveOnENOSPC(const bool enabled_) + : enabled(enabled_), + policy_name("pfrd") +{ +} + int MoveOnENOSPC::from_string(const std::string_view s_) { bool tmp; const int rv = str::from(s_,&tmp); - if(rv != 0) + if(rv == 0) + { + enabled = tmp; + if(enabled) + policy_name = "pfrd"; + return 0; + } + + // Not a bool — try a create-policy name. + auto impl = Func2::CreateFactory::make(s_); + if(!impl) return -EINVAL; - enabled = tmp; + + policy_name = std::string(s_); + enabled = true; return 0; } std::string MoveOnENOSPC::to_string(void) const { - return (enabled ? "true" : "false"); + if(enabled) + return policy_name; + return "false"; } diff --git a/src/config_moveonenospc.hpp b/src/config_moveonenospc.hpp index 1a3d4806..078cf322 100644 --- a/src/config_moveonenospc.hpp +++ b/src/config_moveonenospc.hpp @@ -26,15 +26,13 @@ class MoveOnENOSPC : public ToFromString { public: - MoveOnENOSPC(const bool enabled_) - : enabled(enabled_) - { - } + MoveOnENOSPC(const bool enabled_); public: int from_string(const std::string_view s) final; std::string to_string() const final; public: - bool enabled; + bool enabled; + std::string policy_name; // default "pfrd"; one of the create policy names }; diff --git a/src/fs_movefile_and_open.cpp b/src/fs_movefile_and_open.cpp index e72476d4..5617ee3f 100644 --- a/src/fs_movefile_and_open.cpp +++ b/src/fs_movefile_and_open.cpp @@ -51,12 +51,109 @@ _cleanup_flags(const int flags_) return rv; } -// Pick a writable destination branch using PFRD (proportional to free -// space). Self-contained for moveonenospc — mirrors the same algorithm -// used by Func2::CreatePFRD but on a fresh selection (no clonepath/open). +// FF pick: first writable branch (excluding the source). +static +int +_pick_ff_branch(const Branches &branches_, + const fs::path &exclude_path_, + Branch *&chosen_) +{ + int err = ENOENT; + Branches::Ptr branches = branches_; + fs::info_t info; + + for(auto &branch : *branches) + { + if(branch.path == exclude_path_) + continue; + if(branch.ro_or_nc()) + { if(err == ENOENT) err = EROFS; continue; } + const int irv = fs::info(branch.path,&info); + if(irv < 0) + { if(err == ENOENT) err = ENOENT; continue; } + if(info.readonly) + { if(err == ENOENT) err = EROFS; continue; } + if(info.spaceavail < branch.minfreespace()) + { if(err == ENOENT) err = ENOSPC; continue; } + + chosen_ = &branch; + return 0; + } + return -err; +} + +// MFS pick: most-free-space branch (excluding the source). +static +int +_pick_mfs_branch(const Branches &branches_, + const fs::path &exclude_path_, + Branch *&chosen_) +{ + int err = ENOENT; + Branches::Ptr branches = branches_; + fs::info_t info; + uint64_t best = 0; + + for(auto &branch : *branches) + { + if(branch.path == exclude_path_) + continue; + if(branch.ro_or_nc()) + { if(err == ENOENT) err = EROFS; continue; } + const int irv = fs::info(branch.path,&info); + if(irv < 0) + { if(err == ENOENT) err = ENOENT; continue; } + if(info.readonly) + { if(err == ENOENT) err = EROFS; continue; } + if(info.spaceavail < branch.minfreespace()) + { if(err == ENOENT) err = ENOSPC; continue; } + + if(chosen_ && info.spaceavail <= best) + continue; + best = info.spaceavail; + chosen_ = &branch; + } + return chosen_ ? 0 : -err; +} + +// LFS pick: least-free-space branch (excluding the source). +static +int +_pick_lfs_branch(const Branches &branches_, + const fs::path &exclude_path_, + Branch *&chosen_) +{ + int err = ENOENT; + Branches::Ptr branches = branches_; + fs::info_t info; + uint64_t best = UINT64_MAX; + + for(auto &branch : *branches) + { + if(branch.path == exclude_path_) + continue; + if(branch.ro_or_nc()) + { if(err == ENOENT) err = EROFS; continue; } + const int irv = fs::info(branch.path,&info); + if(irv < 0) + { if(err == ENOENT) err = ENOENT; continue; } + if(info.readonly) + { if(err == ENOENT) err = EROFS; continue; } + if(info.spaceavail < branch.minfreespace()) + { if(err == ENOENT) err = ENOSPC; continue; } + + if(info.spaceavail >= best) + continue; + best = info.spaceavail; + chosen_ = &branch; + } + return chosen_ ? 0 : -err; +} + static int _pick_pfrd_branch(const Branches &branches_, + const fs::path &exclude_path_, Branch *&chosen_) { int err = ENOENT; @@ -68,6 +165,11 @@ _pick_pfrd_branch(const Branches &branches_, for(auto &branch : *branches) { + // Never reselect the source branch — the caller is here precisely + // because writing to this branch failed (ENOSPC/quota). Picking it + // again would cause copyfile+unlink to delete the file. + if(branch.path == exclude_path_) + continue; if(branch.ro_or_nc()) { if(err == ENOENT) err = EROFS; continue; } const int irv = fs::info(branch.path,&info); @@ -100,12 +202,33 @@ _pick_pfrd_branch(const Branches &branches_, return 0; } +// Dispatch on policy name. Implements the most common create policies +// (ff, mfs, lfs, pfrd) inline; any other valid create policy name falls +// back to pfrd (the historical default for moveonenospc). static int -_movefile_and_open(const Branches &branches_, - const fs::path &branchpath_, - const fs::path &fusepath_, - int origfd_) +_pick_branch(const std::string &policy_name_, + const Branches &branches_, + const fs::path &exclude_path_, + Branch *&chosen_) +{ + if(policy_name_ == "ff") + return ::_pick_ff_branch(branches_,exclude_path_,chosen_); + if(policy_name_ == "mfs" || policy_name_ == "epmfs" || policy_name_ == "mspmfs") + return ::_pick_mfs_branch(branches_,exclude_path_,chosen_); + if(policy_name_ == "lfs" || policy_name_ == "eplfs" || policy_name_ == "msplfs") + return ::_pick_lfs_branch(branches_,exclude_path_,chosen_); + + return ::_pick_pfrd_branch(branches_,exclude_path_,chosen_); +} + +static +int +_movefile_and_open(const std::string &policy_name_, + const Branches &branches_, + const fs::path &branchpath_, + const fs::path &fusepath_, + int origfd_) { int rv; int dstfd_flags; @@ -119,7 +242,7 @@ _movefile_and_open(const Branches &branches_, src_branch = branchpath_; - rv = ::_pick_pfrd_branch(branches_,dst_branch); + rv = ::_pick_branch(policy_name_,branches_,branchpath_,dst_branch); if(rv < 0) return rv; if(dst_branch == nullptr) @@ -160,19 +283,21 @@ _movefile_and_open(const Branches &branches_, } int -fs::movefile_and_open(const Branches &branches_, - const fs::path &branchpath_, - const fs::path &fusepath_, - const int origfd_) +fs::movefile_and_open(const std::string &policy_name_, + const Branches &branches_, + const fs::path &branchpath_, + const fs::path &fusepath_, + const int origfd_) { - return ::_movefile_and_open(branches_,branchpath_,fusepath_,origfd_); + return ::_movefile_and_open(policy_name_,branches_,branchpath_,fusepath_,origfd_); } int -fs::movefile_and_open_as_root(const Branches &branches_, - const fs::path &branchpath_, - const fs::path &fusepath_, - const int origfd_) +fs::movefile_and_open_as_root(const std::string &policy_name_, + const Branches &branches_, + const fs::path &branchpath_, + const fs::path &fusepath_, + const int origfd_) { - return fs::movefile_and_open(branches_,branchpath_,fusepath_,origfd_); + return fs::movefile_and_open(policy_name_,branches_,branchpath_,fusepath_,origfd_); } diff --git a/src/fs_movefile_and_open.hpp b/src/fs_movefile_and_open.hpp index 112611cc..25feaf66 100644 --- a/src/fs_movefile_and_open.hpp +++ b/src/fs_movefile_and_open.hpp @@ -21,18 +21,22 @@ #include "branches.hpp" #include "fs_path.hpp" +#include + namespace fs { int - movefile_and_open(const Branches &branches, - const fs::path &branchpath, - const fs::path &fusepath, - const int origfd); + movefile_and_open(const std::string &policy_name, + const Branches &branches, + const fs::path &branchpath, + const fs::path &fusepath, + const int origfd); int - movefile_and_open_as_root(const Branches &branches, - const fs::path &branchpath, - const fs::path &fusepath, - int origfd); + movefile_and_open_as_root(const std::string &policy_name, + const Branches &branches, + const fs::path &branchpath, + const fs::path &fusepath, + int origfd); } diff --git a/src/func_access_base.hpp b/src/func_access_base.hpp index 0be5ee2b..6a06f836 100644 --- a/src/func_access_base.hpp +++ b/src/func_access_base.hpp @@ -11,7 +11,7 @@ namespace Func2 { public: AccessBase() {} - ~AccessBase() {} + virtual ~AccessBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_access_factory.cpp b/src/func_access_factory.cpp index 5992dbc9..100f4c0c 100644 --- a/src/func_access_factory.cpp +++ b/src/func_access_factory.cpp @@ -15,10 +15,27 @@ Func2::AccessFactory::valid(const std::string str_) std::shared_ptr Func2::AccessFactory::make(const std::string_view str_) { - if(str_ == "all") return std::make_shared(); - if(str_ == "epall") return std::make_shared(); - if(str_ == "erofs") return std::make_shared(); - if(str_ == "ff") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_chmod_all.cpp b/src/func_chmod_all.cpp index 629e54ac..41ca4faa 100644 --- a/src/func_chmod_all.cpp +++ b/src/func_chmod_all.cpp @@ -31,8 +31,13 @@ Func2::ChmodAll::operator()(const Branches &branches_, if(rv == -ENOENT) continue; - found = true; - err = rv; + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_chmod_base.hpp b/src/func_chmod_base.hpp index 4c350bc6..69b5fbae 100644 --- a/src/func_chmod_base.hpp +++ b/src/func_chmod_base.hpp @@ -13,7 +13,7 @@ namespace Func2 { public: ChmodBase() {} - ~ChmodBase() {} + virtual ~ChmodBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_chmod_factory.cpp b/src/func_chmod_factory.cpp index 68f6b32d..b6ce87cf 100644 --- a/src/func_chmod_factory.cpp +++ b/src/func_chmod_factory.cpp @@ -13,8 +13,27 @@ Func2::ChmodFactory::valid(const std::string str_) std::shared_ptr Func2::ChmodFactory::make(const std::string_view str_) { - if(str_ == "erofs") return std::make_shared(); - if(str_ == "all" || str_ == "epall") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_chown_all.cpp b/src/func_chown_all.cpp index b4e6dfd6..f06211ec 100644 --- a/src/func_chown_all.cpp +++ b/src/func_chown_all.cpp @@ -32,8 +32,13 @@ Func2::ChownAll::operator()(const Branches &branches_, if(rv == -ENOENT) continue; - found = true; - err = rv; + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_chown_base.hpp b/src/func_chown_base.hpp index 8ad6ad3c..1ffa3934 100644 --- a/src/func_chown_base.hpp +++ b/src/func_chown_base.hpp @@ -13,7 +13,7 @@ namespace Func2 { public: ChownBase() {} - ~ChownBase() {} + virtual ~ChownBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_chown_factory.cpp b/src/func_chown_factory.cpp index 0289656d..270fc716 100644 --- a/src/func_chown_factory.cpp +++ b/src/func_chown_factory.cpp @@ -13,8 +13,27 @@ Func2::ChownFactory::valid(const std::string str_) std::shared_ptr Func2::ChownFactory::make(const std::string_view str_) { - if(str_ == "erofs") return std::make_shared(); - if(str_ == "all" || str_ == "epall") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_create_base.hpp b/src/func_create_base.hpp index 4ce875a8..26af2d40 100644 --- a/src/func_create_base.hpp +++ b/src/func_create_base.hpp @@ -13,7 +13,7 @@ namespace Func2 { public: CreateBase() {} - ~CreateBase() {} + virtual ~CreateBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_create_lup.cpp b/src/func_create_lup.cpp index 7bcba8e7..826c700a 100644 --- a/src/func_create_lup.cpp +++ b/src/func_create_lup.cpp @@ -98,7 +98,7 @@ Func2::CreateLUP::operator()(const ugid_t &ugid_, long double ratio; if(total == 0) - { used = 0; total = 1; } + { used = 1; total = 1; } ratio = (long double)used / (long double)total; if(ratio >= best_ratio) continue; diff --git a/src/func_getattr_base.hpp b/src/func_getattr_base.hpp index 784198b8..9a0d9091 100644 --- a/src/func_getattr_base.hpp +++ b/src/func_getattr_base.hpp @@ -20,7 +20,7 @@ namespace Func2 { public: GetAttrBase() {} - ~GetAttrBase() {} + virtual ~GetAttrBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_getattr_cdco.cpp b/src/func_getattr_cdco.cpp index 781ca2d2..aa50f78d 100644 --- a/src/func_getattr_cdco.cpp +++ b/src/func_getattr_cdco.cpp @@ -27,7 +27,8 @@ Func2::GetAttrCDCO::operator()(const Branches &branches_, err = 0; first_branch = nullptr; - for(const auto &branch : branches_) + Branches::Ptr branches = branches_; + for(const auto &branch : *branches) { struct stat tmp_st; diff --git a/src/func_getattr_cdfo.cpp b/src/func_getattr_cdfo.cpp index 8474ff5a..337a896a 100644 --- a/src/func_getattr_cdfo.cpp +++ b/src/func_getattr_cdfo.cpp @@ -9,6 +9,7 @@ std::string_view Func2::GetAttrCDFO::name() const { + return "cdfo"; } @@ -27,7 +28,8 @@ Func2::GetAttrCDFO::operator()(const Branches &branches_, err = 0; first_branch = nullptr; - for(const auto &branch : branches_) + Branches::Ptr branches = branches_; + for(const auto &branch : *branches) { struct stat tmp_st; diff --git a/src/func_getattr_factory.cpp b/src/func_getattr_factory.cpp index cdc7cbc0..b5ec5933 100644 --- a/src/func_getattr_factory.cpp +++ b/src/func_getattr_factory.cpp @@ -1,7 +1,7 @@ #include "func_getattr_factory.hpp" -#include "func_getattr_cdfo.hpp" #include "func_getattr_cdco.hpp" +#include "func_getattr_cdfo.hpp" #include "func_getattr_ff.hpp" #include "func_getattr_newest.hpp" @@ -19,6 +19,26 @@ Func2::GetAttrFactory::make(const std::string_view str_) if(str_ == "cdco") return std::make_shared(); if(str_ == "ff") return std::make_shared(); if(str_ == "newest") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_getattr_ff.cpp b/src/func_getattr_ff.cpp index b4e5eb43..721fc19d 100644 --- a/src/func_getattr_ff.cpp +++ b/src/func_getattr_ff.cpp @@ -9,6 +9,7 @@ std::string_view Func2::GetAttrFF::name() const { + return "ff"; } @@ -22,7 +23,8 @@ Func2::GetAttrFF::operator()(const Branches &branches_, { fs::path fullpath; - for(const auto &branch : branches_) + Branches::Ptr branches = branches_; + for(const auto &branch : *branches) { fullpath = branch.path / fusepath_; diff --git a/src/func_getattr_newest.cpp b/src/func_getattr_newest.cpp index 51ae7834..6c30b0d0 100644 --- a/src/func_getattr_newest.cpp +++ b/src/func_getattr_newest.cpp @@ -9,6 +9,7 @@ std::string_view Func2::GetAttrNewest::name() const { + return "newest"; } @@ -27,7 +28,8 @@ Func2::GetAttrNewest::operator()(const Branches &branches_, err = 0; newest_branch = nullptr; - for(const auto &branch : branches_) + Branches::Ptr branches = branches_; + for(const auto &branch : *branches) { struct stat tmp_st; diff --git a/src/func_getxattr_base.hpp b/src/func_getxattr_base.hpp index 563ac6be..8cc64baf 100644 --- a/src/func_getxattr_base.hpp +++ b/src/func_getxattr_base.hpp @@ -10,7 +10,7 @@ namespace Func2 { public: GetxattrBase() {} - ~GetxattrBase() {} + virtual ~GetxattrBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_getxattr_factory.cpp b/src/func_getxattr_factory.cpp index 944e7668..d3f39f47 100644 --- a/src/func_getxattr_factory.cpp +++ b/src/func_getxattr_factory.cpp @@ -1,7 +1,7 @@ #include "func_getxattr_factory.hpp" -#include "func_getxattr_ff.hpp" #include "func_getxattr_erofs.hpp" +#include "func_getxattr_ff.hpp" bool @@ -14,7 +14,26 @@ std::shared_ptr Func2::GetxattrFactory::make(const std::string_view str_) { if(str_ == "erofs") return std::make_shared(); - if(str_ == "ff") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_ioctl_base.hpp b/src/func_ioctl_base.hpp index 5f391af1..d7dac538 100644 --- a/src/func_ioctl_base.hpp +++ b/src/func_ioctl_base.hpp @@ -12,7 +12,7 @@ namespace Func2 { public: IoctlBase() {} - ~IoctlBase() {} + virtual ~IoctlBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_ioctl_factory.cpp b/src/func_ioctl_factory.cpp index d6fd5e60..3ed94853 100644 --- a/src/func_ioctl_factory.cpp +++ b/src/func_ioctl_factory.cpp @@ -1,7 +1,7 @@ #include "func_ioctl_factory.hpp" -#include "func_ioctl_ff.hpp" #include "func_ioctl_erofs.hpp" +#include "func_ioctl_ff.hpp" bool @@ -14,7 +14,26 @@ std::shared_ptr Func2::IoctlFactory::make(const std::string_view str_) { if(str_ == "erofs") return std::make_shared(); - if(str_ == "ff") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_link_base.hpp b/src/func_link_base.hpp index 715a6938..efa2ca89 100644 --- a/src/func_link_base.hpp +++ b/src/func_link_base.hpp @@ -9,7 +9,7 @@ namespace Func2 { public: LinkBase() {} - ~LinkBase() {} + virtual ~LinkBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_link_epall.cpp b/src/func_link_epall.cpp index 93f87673..84ae9840 100644 --- a/src/func_link_epall.cpp +++ b/src/func_link_epall.cpp @@ -1,5 +1,7 @@ #include "func_link_epall.hpp" +#include "clone_source.hpp" +#include "config.hpp" #include "errno.hpp" #include "fs_clonepath.hpp" #include "fs_exists.hpp" @@ -46,16 +48,9 @@ Func2::LinkEPAll::operator()(const Branches &branches_, continue; if(clone_src == nullptr) - { - for(auto &b : *branches) - { - if(fs::exists(b.path,newfusedirpath)) - { - clone_src = &b; - break; - } - } - } + clone_src = CloneSource::find(*branches, + newfusedirpath, + cfg.getattr.to_string()); if(clone_src != nullptr) { @@ -65,8 +60,13 @@ Func2::LinkEPAll::operator()(const Branches &branches_, } } - found = true; - err = rv; + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_link_factory.cpp b/src/func_link_factory.cpp index 0233cf4d..9657b57e 100644 --- a/src/func_link_factory.cpp +++ b/src/func_link_factory.cpp @@ -13,8 +13,27 @@ Func2::LinkFactory::valid(const std::string str_) std::shared_ptr Func2::LinkFactory::make(const std::string_view str_) { - if(str_ == "erofs") return std::make_shared(); - if(str_ == "all" || str_ == "epall") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_listxattr_base.hpp b/src/func_listxattr_base.hpp index 46dbe089..cf50d32e 100644 --- a/src/func_listxattr_base.hpp +++ b/src/func_listxattr_base.hpp @@ -10,7 +10,7 @@ namespace Func2 { public: ListxattrBase() {} - ~ListxattrBase() {} + virtual ~ListxattrBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_listxattr_factory.cpp b/src/func_listxattr_factory.cpp index a015915c..e2ec278c 100644 --- a/src/func_listxattr_factory.cpp +++ b/src/func_listxattr_factory.cpp @@ -14,10 +14,27 @@ Func2::ListxattrFactory::valid(const std::string str_) std::shared_ptr Func2::ListxattrFactory::make(const std::string_view str_) { - if(str_ == "all") return std::make_shared(); - if(str_ == "epall") return std::make_shared(); if(str_ == "erofs") return std::make_shared(); - if(str_ == "ff") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_mkdir_all.cpp b/src/func_mkdir_all.cpp index f10342be..0cb315d7 100644 --- a/src/func_mkdir_all.cpp +++ b/src/func_mkdir_all.cpp @@ -1,21 +1,15 @@ #include "func_mkdir_all.hpp" #include "errno.hpp" +#include "fs_acl.hpp" #include "fs_clonepath.hpp" #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_info_t.hpp" -#include "fs_path.hpp" -#include "fs_acl.hpp" #include "fs_mkdir_as.hpp" +#include "fs_path.hpp" -#define error_and_continue(CUR,ERR) \ - do { \ - ::_calc_error(CUR,ERR); \ - continue; \ - } while(0) - static inline void @@ -39,6 +33,12 @@ _calc_error(int &cur_, } } +#define error_and_continue(CUR,ERR) \ + do { \ + ::_calc_error(CUR,ERR); \ + continue; \ + } while(0) + std::string_view Func2::MkdirAll::name() const @@ -55,17 +55,25 @@ Func2::MkdirAll::operator()(const ugid_t &ugid_, { int rv; int error; + bool any; fs::info_t info; Branches::Ptr branches; - const Branch *chosen; const Branch *clone_src; fs::path fullpath; mode_t mode; branches = branches_; - chosen = nullptr; clone_src = nullptr; error = ENOENT; + any = false; + + for(auto &branch : *branches) + { + if(!fs::exists(branch.path,fusepath_.parent_path())) + continue; + clone_src = &branch; + break; + } for(auto &branch : *branches) { @@ -79,35 +87,30 @@ Func2::MkdirAll::operator()(const ugid_t &ugid_, if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - chosen = &branch; - break; + if(clone_src && (clone_src != &branch)) + { + rv = fs::clonepath(clone_src->path,branch.path,fusepath_.parent_path()); + if(rv < 0) + error_and_continue(error,-rv); + } + + fullpath = branch.path / fusepath_; + mode = mode_; + if(!fs::acl::dir_has_defaults(fullpath)) + mode &= ~umask_; + + rv = fs::mkdir_as(ugid_,fullpath,mode); + if(rv < 0) + { + ::_calc_error(error,-rv); + continue; + } + + any = true; } - if(!chosen) + if(!any) return -error; - for(auto &branch : *branches) - { - if(!fs::exists(branch.path,fusepath_.parent_path())) - continue; - clone_src = &branch; - break; - } - - if(!clone_src) - return -ENOENT; - - if(clone_src != chosen) - { - rv = fs::clonepath(clone_src->path,chosen->path,fusepath_.parent_path()); - if(rv < 0) - return rv; - } - - fullpath = chosen->path / fusepath_; - mode = mode_; - if(!fs::acl::dir_has_defaults(fullpath)) - mode &= ~umask_; - - return fs::mkdir_as(ugid_,fullpath,mode); + return 0; } diff --git a/src/func_mkdir_base.hpp b/src/func_mkdir_base.hpp index b66c028d..54c9b141 100644 --- a/src/func_mkdir_base.hpp +++ b/src/func_mkdir_base.hpp @@ -11,7 +11,7 @@ namespace Func2 { public: MkdirBase() {} - ~MkdirBase() {} + virtual ~MkdirBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_mkdir_epall.cpp b/src/func_mkdir_epall.cpp index 8b10ef29..b68dde20 100644 --- a/src/func_mkdir_epall.cpp +++ b/src/func_mkdir_epall.cpp @@ -1,21 +1,14 @@ #include "func_mkdir_epall.hpp" #include "errno.hpp" -#include "fs_clonepath.hpp" +#include "fs_acl.hpp" #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_info_t.hpp" -#include "fs_path.hpp" -#include "fs_acl.hpp" #include "fs_mkdir_as.hpp" +#include "fs_path.hpp" -#define error_and_continue(CUR,ERR) \ - do { \ - ::_calc_error(CUR,ERR); \ - continue; \ - } while(0) - static inline void @@ -39,6 +32,12 @@ _calc_error(int &cur_, } } +#define error_and_continue(CUR,ERR) \ + do { \ + ::_calc_error(CUR,ERR); \ + continue; \ + } while(0) + std::string_view Func2::MkdirEPALL::name() const @@ -55,15 +54,15 @@ Func2::MkdirEPALL::operator()(const ugid_t &ugid_, { int rv; int error; + bool any; fs::info_t info; Branches::Ptr branches; - const Branch *chosen; fs::path fullpath; mode_t mode; branches = branches_; - chosen = nullptr; error = ENOENT; + any = false; for(auto &branch : *branches) { @@ -79,17 +78,23 @@ Func2::MkdirEPALL::operator()(const ugid_t &ugid_, if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - chosen = &branch; - break; + fullpath = branch.path / fusepath_; + mode = mode_; + if(!fs::acl::dir_has_defaults(fullpath)) + mode &= ~umask_; + + rv = fs::mkdir_as(ugid_,fullpath,mode); + if(rv < 0) + { + ::_calc_error(error,-rv); + continue; + } + + any = true; } - if(!chosen) + if(!any) return -error; - fullpath = chosen->path / fusepath_; - mode = mode_; - if(!fs::acl::dir_has_defaults(fullpath)) - mode &= ~umask_; - - return fs::mkdir_as(ugid_,fullpath,mode); + return 0; } diff --git a/src/func_mkdir_lup.cpp b/src/func_mkdir_lup.cpp index b43f966c..9d8d9d48 100644 --- a/src/func_mkdir_lup.cpp +++ b/src/func_mkdir_lup.cpp @@ -87,7 +87,7 @@ Func2::MkdirLUP::operator()(const ugid_t &ugid_, long double ratio; if(total == 0) - { used = 0; total = 1; } + { used = 1; total = 1; } ratio = (long double)used / (long double)total; if(ratio >= best_ratio) continue; diff --git a/src/func_mknod_all.cpp b/src/func_mknod_all.cpp index 8e8e166e..431587d9 100644 --- a/src/func_mknod_all.cpp +++ b/src/func_mknod_all.cpp @@ -5,16 +5,10 @@ #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_info_t.hpp" -#include "fs_path.hpp" #include "fs_mknod_as.hpp" +#include "fs_path.hpp" -#define error_and_continue(CUR,ERR) \ - do { \ - ::_calc_error(CUR,ERR); \ - continue; \ - } while(0) - static inline void @@ -38,6 +32,12 @@ _calc_error(int &cur_, } } +#define error_and_continue(CUR,ERR) \ + do { \ + ::_calc_error(CUR,ERR); \ + continue; \ + } while(0) + std::string_view Func2::MknodAll::name() const @@ -55,16 +55,24 @@ Func2::MknodAll::operator()(const ugid_t &ugid_, { int rv; int error; + bool any; fs::info_t info; Branches::Ptr branches; - const Branch *chosen; const Branch *clone_src; fs::path fullpath; branches = branches_; - chosen = nullptr; clone_src = nullptr; error = ENOENT; + any = false; + + for(auto &branch : *branches) + { + if(!fs::exists(branch.path,fusepath_.parent_path())) + continue; + clone_src = &branch; + break; + } for(auto &branch : *branches) { @@ -78,32 +86,26 @@ Func2::MknodAll::operator()(const ugid_t &ugid_, if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - chosen = &branch; - break; + if(clone_src && (clone_src != &branch)) + { + rv = fs::clonepath(clone_src->path,branch.path,fusepath_.parent_path()); + if(rv < 0) + error_and_continue(error,-rv); + } + + fullpath = branch.path / fusepath_; + rv = fs::mknod_as(ugid_,fullpath,mode_,dev_,umask_); + if(rv < 0) + { + ::_calc_error(error,-rv); + continue; + } + + any = true; } - if(!chosen) + if(!any) return -error; - for(auto &branch : *branches) - { - if(!fs::exists(branch.path,fusepath_.parent_path())) - continue; - clone_src = &branch; - break; - } - - if(!clone_src) - return -ENOENT; - - if(clone_src != chosen) - { - rv = fs::clonepath(clone_src->path,chosen->path,fusepath_.parent_path()); - if(rv < 0) - return rv; - } - - fullpath = chosen->path / fusepath_; - - return fs::mknod_as(ugid_,fullpath,mode_,dev_,umask_); + return 0; } diff --git a/src/func_mknod_base.hpp b/src/func_mknod_base.hpp index 147fdbf5..fd488340 100644 --- a/src/func_mknod_base.hpp +++ b/src/func_mknod_base.hpp @@ -13,7 +13,7 @@ namespace Func2 { public: MknodBase() {} - ~MknodBase() {} + virtual ~MknodBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_mknod_epall.cpp b/src/func_mknod_epall.cpp index 84a63058..068dce64 100644 --- a/src/func_mknod_epall.cpp +++ b/src/func_mknod_epall.cpp @@ -1,20 +1,13 @@ #include "func_mknod_epall.hpp" #include "errno.hpp" -#include "fs_clonepath.hpp" #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_info_t.hpp" -#include "fs_path.hpp" #include "fs_mknod_as.hpp" +#include "fs_path.hpp" -#define error_and_continue(CUR,ERR) \ - do { \ - ::_calc_error(CUR,ERR); \ - continue; \ - } while(0) - static inline void @@ -38,6 +31,12 @@ _calc_error(int &cur_, } } +#define error_and_continue(CUR,ERR) \ + do { \ + ::_calc_error(CUR,ERR); \ + continue; \ + } while(0) + std::string_view Func2::MknodEPALL::name() const @@ -55,14 +54,14 @@ Func2::MknodEPALL::operator()(const ugid_t &ugid_, { int rv; int error; + bool any; fs::info_t info; Branches::Ptr branches; - const Branch *chosen; fs::path fullpath; branches = branches_; - chosen = nullptr; error = ENOENT; + any = false; for(auto &branch : *branches) { @@ -78,14 +77,19 @@ Func2::MknodEPALL::operator()(const ugid_t &ugid_, if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - chosen = &branch; - break; + fullpath = branch.path / fusepath_; + rv = fs::mknod_as(ugid_,fullpath,mode_,dev_,umask_); + if(rv < 0) + { + ::_calc_error(error,-rv); + continue; + } + + any = true; } - if(!chosen) + if(!any) return -error; - fullpath = chosen->path / fusepath_; - - return fs::mknod_as(ugid_,fullpath,mode_,dev_,umask_); + return 0; } diff --git a/src/func_mknod_lup.cpp b/src/func_mknod_lup.cpp index 177aced1..a3e697c9 100644 --- a/src/func_mknod_lup.cpp +++ b/src/func_mknod_lup.cpp @@ -86,7 +86,7 @@ Func2::MknodLUP::operator()(const ugid_t &ugid_, long double ratio; if(total == 0) - { used = 0; total = 1; } + { used = 1; total = 1; } ratio = (long double)used / (long double)total; if(ratio >= best_ratio) continue; diff --git a/src/func_open_base.hpp b/src/func_open_base.hpp index 659320fa..18bf01d1 100644 --- a/src/func_open_base.hpp +++ b/src/func_open_base.hpp @@ -15,7 +15,7 @@ namespace Func2 { public: OpenBase() {} - ~OpenBase() {} + virtual ~OpenBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_open_factory.cpp b/src/func_open_factory.cpp index 0b519dd0..01000c72 100644 --- a/src/func_open_factory.cpp +++ b/src/func_open_factory.cpp @@ -1,7 +1,7 @@ #include "func_open_factory.hpp" -#include "func_open_ff.hpp" #include "func_open_erofs.hpp" +#include "func_open_ff.hpp" bool @@ -14,7 +14,26 @@ std::shared_ptr Func2::OpenFactory::make(const std::string_view str_) { if(str_ == "erofs") return std::make_shared(); - if(str_ == "ff") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_readlink_base.hpp b/src/func_readlink_base.hpp index 2ad132e4..de94bb9a 100644 --- a/src/func_readlink_base.hpp +++ b/src/func_readlink_base.hpp @@ -10,7 +10,7 @@ namespace Func2 { public: ReadlinkBase() {} - ~ReadlinkBase() {} + virtual ~ReadlinkBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_readlink_factory.cpp b/src/func_readlink_factory.cpp index fa32deb9..591698c0 100644 --- a/src/func_readlink_factory.cpp +++ b/src/func_readlink_factory.cpp @@ -1,7 +1,7 @@ #include "func_readlink_factory.hpp" -#include "func_readlink_ff.hpp" #include "func_readlink_erofs.hpp" +#include "func_readlink_ff.hpp" bool @@ -14,7 +14,26 @@ std::shared_ptr Func2::ReadlinkFactory::make(const std::string_view str_) { if(str_ == "erofs") return std::make_shared(); - if(str_ == "ff") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_removexattr_all.cpp b/src/func_removexattr_all.cpp index a54fc7b4..faea62c3 100644 --- a/src/func_removexattr_all.cpp +++ b/src/func_removexattr_all.cpp @@ -31,8 +31,13 @@ Func2::RemovexattrAll::operator()(const Branches &branches_, if(rv == -ENOENT) continue; - found = true; - err = rv; + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_removexattr_base.hpp b/src/func_removexattr_base.hpp index a9d6aa8f..5cdd12ad 100644 --- a/src/func_removexattr_base.hpp +++ b/src/func_removexattr_base.hpp @@ -10,7 +10,7 @@ namespace Func2 { public: RemovexattrBase() {} - ~RemovexattrBase() {} + virtual ~RemovexattrBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_removexattr_factory.cpp b/src/func_removexattr_factory.cpp index 4305b840..e1a43de2 100644 --- a/src/func_removexattr_factory.cpp +++ b/src/func_removexattr_factory.cpp @@ -13,8 +13,27 @@ Func2::RemovexattrFactory::valid(const std::string str_) std::shared_ptr Func2::RemovexattrFactory::make(const std::string_view str_) { - if(str_ == "erofs") return std::make_shared(); - if(str_ == "all" || str_ == "epall") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_rename_base.hpp b/src/func_rename_base.hpp index b3c2a52d..7915ac5b 100644 --- a/src/func_rename_base.hpp +++ b/src/func_rename_base.hpp @@ -9,7 +9,7 @@ namespace Func2 { public: RenameBase() {} - ~RenameBase() {} + virtual ~RenameBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_rename_epall.cpp b/src/func_rename_epall.cpp index 5e65442c..4d9c676d 100644 --- a/src/func_rename_epall.cpp +++ b/src/func_rename_epall.cpp @@ -1,5 +1,7 @@ #include "func_rename_epall.hpp" +#include "clone_source.hpp" +#include "config.hpp" #include "errno.hpp" #include "fs_clonepath.hpp" #include "fs_exists.hpp" @@ -51,16 +53,9 @@ Func2::RenameEPAll::operator()(const Branches &branches_, if(rv == -ENOENT) { if(clone_src == nullptr) - { - for(auto &b : *branches) - { - if(fs::exists(b.path,newfusedirpath)) - { - clone_src = &b; - break; - } - } - } + clone_src = CloneSource::find(*branches, + newfusedirpath, + cfg.getattr.to_string()); if(clone_src != nullptr) { @@ -70,8 +65,19 @@ Func2::RenameEPAll::operator()(const Branches &branches_, } } - found = true; - err = rv; + // If rename failed on this branch but the source still exists, queue + // the stale source for removal on overall success so the file is not + // left at both old and new paths. + if(rv < 0) + toremove.push_back(oldfullpath); + + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_rename_factory.cpp b/src/func_rename_factory.cpp index fd3f3255..ab575719 100644 --- a/src/func_rename_factory.cpp +++ b/src/func_rename_factory.cpp @@ -13,8 +13,27 @@ Func2::RenameFactory::valid(const std::string str_) std::shared_ptr Func2::RenameFactory::make(const std::string_view str_) { - if(str_ == "erofs") return std::make_shared(); - if(str_ == "all" || str_ == "epall") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_rmdir_all.cpp b/src/func_rmdir_all.cpp index 57999135..4495f1ca 100644 --- a/src/func_rmdir_all.cpp +++ b/src/func_rmdir_all.cpp @@ -42,8 +42,19 @@ Func2::RmdirAll::operator()(const Branches &branches_, if(rv == -ENOENT) continue; - found = true; - err = rv; + if(!found) + { err = rv; found = true; continue; } + // -ENOTEMPTY / -EEXIST are strongest: a remaining-content failure must + // override a sibling-branch success since the directory is not fully gone. + if((rv == -ENOTEMPTY) || (rv == -EEXIST)) + { err = rv; continue; } + if((err == -ENOTEMPTY) || (err == -EEXIST)) + continue; + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_rmdir_base.hpp b/src/func_rmdir_base.hpp index 8aaf5748..10bf3d52 100644 --- a/src/func_rmdir_base.hpp +++ b/src/func_rmdir_base.hpp @@ -10,7 +10,7 @@ namespace Func2 { public: RmdirBase() {} - ~RmdirBase() {} + virtual ~RmdirBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_rmdir_factory.cpp b/src/func_rmdir_factory.cpp index fbf24e2c..e619d111 100644 --- a/src/func_rmdir_factory.cpp +++ b/src/func_rmdir_factory.cpp @@ -13,8 +13,27 @@ Func2::RmdirFactory::valid(const std::string str_) std::shared_ptr Func2::RmdirFactory::make(const std::string_view str_) { - if(str_ == "erofs") return std::make_shared(); - if(str_ == "all" || str_ == "epall") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_setxattr_all.cpp b/src/func_setxattr_all.cpp index ff0a93df..56451893 100644 --- a/src/func_setxattr_all.cpp +++ b/src/func_setxattr_all.cpp @@ -34,8 +34,13 @@ Func2::SetxattrAll::operator()(const Branches &branches_, if(rv == -ENOENT) continue; - found = true; - err = rv; + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_setxattr_base.hpp b/src/func_setxattr_base.hpp index 5058a7e4..7f5dac6d 100644 --- a/src/func_setxattr_base.hpp +++ b/src/func_setxattr_base.hpp @@ -10,7 +10,7 @@ namespace Func2 { public: SetxattrBase() {} - ~SetxattrBase() {} + virtual ~SetxattrBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_setxattr_factory.cpp b/src/func_setxattr_factory.cpp index 8717365b..3a34a1f0 100644 --- a/src/func_setxattr_factory.cpp +++ b/src/func_setxattr_factory.cpp @@ -13,8 +13,27 @@ Func2::SetxattrFactory::valid(const std::string str_) std::shared_ptr Func2::SetxattrFactory::make(const std::string_view str_) { - if(str_ == "erofs") return std::make_shared(); - if(str_ == "all" || str_ == "epall") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_statx_base.hpp b/src/func_statx_base.hpp index eefa5a16..fe3cf532 100644 --- a/src/func_statx_base.hpp +++ b/src/func_statx_base.hpp @@ -21,7 +21,7 @@ namespace Func2 { public: StatxBase() {} - ~StatxBase() {} + virtual ~StatxBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_statx_cdco.cpp b/src/func_statx_cdco.cpp index ee67b71f..ffb5025a 100644 --- a/src/func_statx_cdco.cpp +++ b/src/func_statx_cdco.cpp @@ -9,6 +9,7 @@ std::string_view Func2::StatxCDCO::name() const { + return "cdco"; } @@ -29,7 +30,8 @@ Func2::StatxCDCO::operator()(const Branches &branches_, err = 0; first_branch = nullptr; - for(const auto &branch : branches_) + Branches::Ptr branches = branches_; + for(const auto &branch : *branches) { struct fuse_statx tmp_st; diff --git a/src/func_statx_cdfo.cpp b/src/func_statx_cdfo.cpp index 2c829775..8d2e7dc3 100644 --- a/src/func_statx_cdfo.cpp +++ b/src/func_statx_cdfo.cpp @@ -9,6 +9,7 @@ std::string_view Func2::StatxCDFO::name() const { + return "cdfo"; } @@ -29,7 +30,8 @@ Func2::StatxCDFO::operator()(const Branches &branches_, err = 0; first_branch = nullptr; - for(const auto &branch : branches_) + Branches::Ptr branches = branches_; + for(const auto &branch : *branches) { struct fuse_statx tmp_st; diff --git a/src/func_statx_factory.cpp b/src/func_statx_factory.cpp index 96e64eeb..5fdf75b2 100644 --- a/src/func_statx_factory.cpp +++ b/src/func_statx_factory.cpp @@ -1,7 +1,7 @@ #include "func_statx_factory.hpp" -#include "func_statx_cdfo.hpp" #include "func_statx_cdco.hpp" +#include "func_statx_cdfo.hpp" #include "func_statx_ff.hpp" #include "func_statx_newest.hpp" @@ -19,6 +19,26 @@ Func2::StatxFactory::make(const std::string_view str_) if(str_ == "cdco") return std::make_shared(); if(str_ == "ff") return std::make_shared(); if(str_ == "newest") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_statx_ff.cpp b/src/func_statx_ff.cpp index 1df8577a..48adad79 100644 --- a/src/func_statx_ff.cpp +++ b/src/func_statx_ff.cpp @@ -9,6 +9,7 @@ std::string_view Func2::StatxFF::name() const { + return "ff"; } @@ -24,7 +25,8 @@ Func2::StatxFF::operator()(const Branches &branches_, { fs::path fullpath; - for(const auto &branch : branches_) + Branches::Ptr branches = branches_; + for(const auto &branch : *branches) { fullpath = branch.path / fusepath_; diff --git a/src/func_statx_newest.cpp b/src/func_statx_newest.cpp index 9b25dc79..00f732cd 100644 --- a/src/func_statx_newest.cpp +++ b/src/func_statx_newest.cpp @@ -9,6 +9,7 @@ std::string_view Func2::StatxNewest::name() const { + return "newest"; } @@ -29,7 +30,8 @@ Func2::StatxNewest::operator()(const Branches &branches_, err = 0; newest_branch = nullptr; - for(const auto &branch : branches_) + Branches::Ptr branches = branches_; + for(const auto &branch : *branches) { struct fuse_statx tmp_st; diff --git a/src/func_symlink_all.cpp b/src/func_symlink_all.cpp index 5f928bff..9383b849 100644 --- a/src/func_symlink_all.cpp +++ b/src/func_symlink_all.cpp @@ -5,18 +5,12 @@ #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_info_t.hpp" -#include "fs_path.hpp" #include "fs_inode.hpp" #include "fs_lstat.hpp" +#include "fs_path.hpp" #include "fs_symlink_as.hpp" -#define error_and_continue(CUR,ERR) \ - do { \ - ::_calc_error(CUR,ERR); \ - continue; \ - } while(0) - static inline void @@ -40,6 +34,12 @@ _calc_error(int &cur_, } } +#define error_and_continue(CUR,ERR) \ + do { \ + ::_calc_error(CUR,ERR); \ + continue; \ + } while(0) + std::string_view Func2::SymlinkAll::name() const @@ -56,16 +56,26 @@ Func2::SymlinkAll::operator()(const ugid_t &ugid_, { int rv; int error; + bool any; fs::info_t info; Branches::Ptr branches; - const Branch *chosen; const Branch *clone_src; + const Branch *last_success; fs::path fullpath; - branches = branches_; - chosen = nullptr; - clone_src = nullptr; - error = ENOENT; + branches = branches_; + clone_src = nullptr; + last_success = nullptr; + error = ENOENT; + any = false; + + for(auto &branch : *branches) + { + if(!fs::exists(branch.path,linkpath_.parent_path())) + continue; + clone_src = &branch; + break; + } for(auto &branch : *branches) { @@ -79,40 +89,35 @@ Func2::SymlinkAll::operator()(const ugid_t &ugid_, if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - chosen = &branch; - break; + if(clone_src && (clone_src != &branch)) + { + rv = fs::clonepath(clone_src->path,branch.path,linkpath_.parent_path()); + if(rv < 0) + error_and_continue(error,-rv); + } + + fullpath = branch.path / linkpath_; + rv = fs::symlink_as(ugid_,target_,fullpath); + if(rv < 0) + { + ::_calc_error(error,-rv); + continue; + } + + any = true; + last_success = &branch; } - if(!chosen) + if(!any) return -error; - for(auto &branch : *branches) - { - if(!fs::exists(branch.path,linkpath_.parent_path())) - continue; - clone_src = &branch; - break; - } - - if(!clone_src) - return -ENOENT; - - if(clone_src != chosen) - { - rv = fs::clonepath(clone_src->path,chosen->path,linkpath_.parent_path()); - if(rv < 0) - return rv; - } - - fullpath = chosen->path / linkpath_; - - rv = fs::symlink_as(ugid_,target_,fullpath); - if((rv >= 0) && (st_ != NULL) && (st_->st_ino == 0)) + if(last_success && (st_ != NULL) && (st_->st_ino == 0)) { + fullpath = last_success->path / linkpath_; fs::lstat(fullpath,st_); if(st_->st_ino != 0) - fs::inode::calc(chosen->path,linkpath_,st_); + fs::inode::calc(last_success->path,linkpath_,st_); } - return rv; + return 0; } diff --git a/src/func_symlink_base.hpp b/src/func_symlink_base.hpp index 12fcd9b9..6b01184d 100644 --- a/src/func_symlink_base.hpp +++ b/src/func_symlink_base.hpp @@ -13,7 +13,7 @@ namespace Func2 { public: SymlinkBase() {} - ~SymlinkBase() {} + virtual ~SymlinkBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_symlink_epall.cpp b/src/func_symlink_epall.cpp index ae2e8949..26769d32 100644 --- a/src/func_symlink_epall.cpp +++ b/src/func_symlink_epall.cpp @@ -1,22 +1,15 @@ #include "func_symlink_epall.hpp" #include "errno.hpp" -#include "fs_clonepath.hpp" #include "fs_exists.hpp" #include "fs_info.hpp" #include "fs_info_t.hpp" -#include "fs_path.hpp" #include "fs_inode.hpp" #include "fs_lstat.hpp" +#include "fs_path.hpp" #include "fs_symlink_as.hpp" -#define error_and_continue(CUR,ERR) \ - do { \ - ::_calc_error(CUR,ERR); \ - continue; \ - } while(0) - static inline void @@ -40,6 +33,12 @@ _calc_error(int &cur_, } } +#define error_and_continue(CUR,ERR) \ + do { \ + ::_calc_error(CUR,ERR); \ + continue; \ + } while(0) + std::string_view Func2::SymlinkEPALL::name() const @@ -56,14 +55,16 @@ Func2::SymlinkEPALL::operator()(const ugid_t &ugid_, { int rv; int error; + bool any; fs::info_t info; Branches::Ptr branches; - const Branch *chosen; + const Branch *last_success; fs::path fullpath; - branches = branches_; - chosen = nullptr; - error = ENOENT; + branches = branches_; + last_success = nullptr; + error = ENOENT; + any = false; for(auto &branch : *branches) { @@ -79,22 +80,28 @@ Func2::SymlinkEPALL::operator()(const ugid_t &ugid_, if(info.spaceavail < branch.minfreespace()) error_and_continue(error,ENOSPC); - chosen = &branch; - break; + fullpath = branch.path / linkpath_; + rv = fs::symlink_as(ugid_,target_,fullpath); + if(rv < 0) + { + ::_calc_error(error,-rv); + continue; + } + + any = true; + last_success = &branch; } - if(!chosen) + if(!any) return -error; - fullpath = chosen->path / linkpath_; - - rv = fs::symlink_as(ugid_,target_,fullpath); - if((rv >= 0) && (st_ != NULL) && (st_->st_ino == 0)) + if(last_success && (st_ != NULL) && (st_->st_ino == 0)) { + fullpath = last_success->path / linkpath_; fs::lstat(fullpath,st_); if(st_->st_ino != 0) - fs::inode::calc(chosen->path,linkpath_,st_); + fs::inode::calc(last_success->path,linkpath_,st_); } - return rv; + return 0; } diff --git a/src/func_symlink_lup.cpp b/src/func_symlink_lup.cpp index 50dda5fc..9a642d0a 100644 --- a/src/func_symlink_lup.cpp +++ b/src/func_symlink_lup.cpp @@ -87,7 +87,7 @@ Func2::SymlinkLUP::operator()(const ugid_t &ugid_, long double ratio; if(total == 0) - { used = 0; total = 1; } + { used = 1; total = 1; } ratio = (long double)used / (long double)total; if(ratio >= best_ratio) continue; diff --git a/src/func_symlink_msplfs.cpp b/src/func_symlink_msplfs.cpp index 022524ef..9d9ef6ba 100644 --- a/src/func_symlink_msplfs.cpp +++ b/src/func_symlink_msplfs.cpp @@ -117,7 +117,7 @@ Func2::SymlinkMSPLFS::operator()(const ugid_t &ugid_, p = p.parent_path()) segments.push_back(p); - dirmode = 0777; + dirmode = 0755; for(auto it = segments.rbegin(); it != segments.rend(); ++it) { const Branch *src; diff --git a/src/func_symlink_msplus.cpp b/src/func_symlink_msplus.cpp index f985f55d..96bffd15 100644 --- a/src/func_symlink_msplus.cpp +++ b/src/func_symlink_msplus.cpp @@ -117,7 +117,7 @@ Func2::SymlinkMSPLUS::operator()(const ugid_t &ugid_, p = p.parent_path()) segments.push_back(p); - dirmode = 0777; + dirmode = 0755; for(auto it = segments.rbegin(); it != segments.rend(); ++it) { const Branch *src; diff --git a/src/func_symlink_mspmfs.cpp b/src/func_symlink_mspmfs.cpp index 27544472..c806a700 100644 --- a/src/func_symlink_mspmfs.cpp +++ b/src/func_symlink_mspmfs.cpp @@ -117,7 +117,7 @@ Func2::SymlinkMSPMFS::operator()(const ugid_t &ugid_, p = p.parent_path()) segments.push_back(p); - dirmode = 0777; + dirmode = 0755; for(auto it = segments.rbegin(); it != segments.rend(); ++it) { const Branch *src; diff --git a/src/func_symlink_msppfrd.cpp b/src/func_symlink_msppfrd.cpp index afcde777..cf086f6b 100644 --- a/src/func_symlink_msppfrd.cpp +++ b/src/func_symlink_msppfrd.cpp @@ -140,7 +140,7 @@ Func2::SymlinkMSPPFRD::operator()(const ugid_t &ugid_, p = p.parent_path()) segments.push_back(p); - dirmode = 0777; + dirmode = 0755; for(auto it = segments.rbegin(); it != segments.rend(); ++it) { const Branch *src; diff --git a/src/func_truncate_all.cpp b/src/func_truncate_all.cpp index 77ecedcf..308180e2 100644 --- a/src/func_truncate_all.cpp +++ b/src/func_truncate_all.cpp @@ -31,8 +31,13 @@ Func2::TruncateAll::operator()(const Branches &branches_, if(rv == -ENOENT) continue; - found = true; - err = rv; + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_truncate_base.hpp b/src/func_truncate_base.hpp index 9a818c67..d98b656c 100644 --- a/src/func_truncate_base.hpp +++ b/src/func_truncate_base.hpp @@ -10,7 +10,7 @@ namespace Func2 { public: TruncateBase() {} - ~TruncateBase() {} + virtual ~TruncateBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_truncate_factory.cpp b/src/func_truncate_factory.cpp index 7b4b7727..1ad65dfa 100644 --- a/src/func_truncate_factory.cpp +++ b/src/func_truncate_factory.cpp @@ -13,8 +13,27 @@ Func2::TruncateFactory::valid(const std::string str_) std::shared_ptr Func2::TruncateFactory::make(const std::string_view str_) { - if(str_ == "erofs") return std::make_shared(); - if(str_ == "all" || str_ == "epall") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_unlink_all.cpp b/src/func_unlink_all.cpp index 1e564343..9794feb4 100644 --- a/src/func_unlink_all.cpp +++ b/src/func_unlink_all.cpp @@ -30,8 +30,13 @@ Func2::UnlinkAll::operator()(const Branches &branches_, if(rv == -ENOENT) continue; - found = true; - err = rv; + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_unlink_base.hpp b/src/func_unlink_base.hpp index 9737866f..9fb500fd 100644 --- a/src/func_unlink_base.hpp +++ b/src/func_unlink_base.hpp @@ -10,7 +10,7 @@ namespace Func2 { public: UnlinkBase() {} - ~UnlinkBase() {} + virtual ~UnlinkBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_unlink_factory.cpp b/src/func_unlink_factory.cpp index 884866c9..84cbc782 100644 --- a/src/func_unlink_factory.cpp +++ b/src/func_unlink_factory.cpp @@ -14,10 +14,27 @@ Func2::UnlinkFactory::valid(const std::string str_) std::shared_ptr Func2::UnlinkFactory::make(const std::string_view str_) { - if(str_ == "all") return std::make_shared(); - if(str_ == "epall") return std::make_shared(); if(str_ == "erofs") return std::make_shared(); if(str_ == "newest") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/func_utimens_all.cpp b/src/func_utimens_all.cpp index 2aed2d5a..b123d7c6 100644 --- a/src/func_utimens_all.cpp +++ b/src/func_utimens_all.cpp @@ -31,8 +31,13 @@ Func2::UtimensAll::operator()(const Branches &branches_, if(rv == -ENOENT) continue; - found = true; - err = rv; + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; } if(!found) diff --git a/src/func_utimens_base.hpp b/src/func_utimens_base.hpp index 9f118439..bc48bc9e 100644 --- a/src/func_utimens_base.hpp +++ b/src/func_utimens_base.hpp @@ -10,7 +10,7 @@ namespace Func2 { public: UtimensBase() {} - ~UtimensBase() {} + virtual ~UtimensBase() = default; public: virtual std::string_view name() const = 0; diff --git a/src/func_utimens_factory.cpp b/src/func_utimens_factory.cpp index 4516776e..0a1c5aea 100644 --- a/src/func_utimens_factory.cpp +++ b/src/func_utimens_factory.cpp @@ -13,8 +13,27 @@ Func2::UtimensFactory::valid(const std::string str_) std::shared_ptr Func2::UtimensFactory::make(const std::string_view str_) { - if(str_ == "erofs") return std::make_shared(); - if(str_ == "all" || str_ == "epall") return std::make_shared(); + if(str_ == "erofs") return std::make_shared(); + if(str_ == "all") return std::make_shared(); + if(str_ == "epall") return std::make_shared(); + if(str_ == "epff") return std::make_shared(); + if(str_ == "eplfs") return std::make_shared(); + if(str_ == "eplus") return std::make_shared(); + if(str_ == "epmfs") return std::make_shared(); + if(str_ == "eppfrd") return std::make_shared(); + if(str_ == "eprand") return std::make_shared(); + if(str_ == "ff") return std::make_shared(); + if(str_ == "lfs") return std::make_shared(); + if(str_ == "lup") return std::make_shared(); + if(str_ == "lus") return std::make_shared(); + if(str_ == "mfs") return std::make_shared(); + if(str_ == "msplfs") return std::make_shared(); + if(str_ == "msplus") return std::make_shared(); + if(str_ == "mspmfs") return std::make_shared(); + if(str_ == "msppfrd") return std::make_shared(); + if(str_ == "newest") return std::make_shared(); + if(str_ == "pfrd") return std::make_shared(); + if(str_ == "rand") return std::make_shared(); return {}; } diff --git a/src/fuse_link.cpp b/src/fuse_link.cpp index 6bccbf6d..7ecd419b 100644 --- a/src/fuse_link.cpp +++ b/src/fuse_link.cpp @@ -18,6 +18,7 @@ #include "fuse_link.hpp" +#include "clone_source.hpp" #include "config.hpp" #include "errno.hpp" #include "fs_clonepath.hpp" @@ -44,6 +45,51 @@ _create_is_path_preserving() return impl && impl->path_preserving(); } +// Path-preserving link: only link on branches that already have BOTH oldpath +// and newdir; never clone newdir into branches that lacked it. +static +int +_link_preserve_path(const fs::path &oldpath_, + const fs::path &newpath_) +{ + Branches::Ptr branches = cfg.branches; + const fs::path newdir = newpath_.parent_path(); + int err; + bool found; + fs::path oldfullpath; + fs::path newfullpath; + + err = 0; + found = false; + for(auto &branch : *branches) + { + if(branch.ro()) + continue; + if(!fs::exists(branch.path,oldpath_)) + continue; + if(!fs::exists(branch.path,newdir)) + continue; + + oldfullpath = branch.path / oldpath_; + newfullpath = branch.path / newpath_; + + const int rv = fs::link(oldfullpath,newfullpath); + + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; + } + + if(!found) + return -EXDEV; + + return err; +} + static int _link(const fuse_req_ctx_t *ctx_, @@ -54,27 +100,16 @@ _link(const fuse_req_ctx_t *ctx_, { int rv; - // Honor path-preserving create policies: don't clone the new path + // Honor path-preserving create policies: link only on branches that + // already have both old and new-parent path; never clone the new path // structure into branches that don't already have it. Fall through - // to the link_exdev handling (PASSTHROUGH/REL_SYMLINK/etc.). + // to the link_exdev handling (PASSTHROUGH/REL_SYMLINK/etc.) when no + // qualifying branch exists. if(!cfg.ignorepponrename && ::_create_is_path_preserving()) - { - Branches::Ptr branches = cfg.branches; - const fs::path newdir = newpath_.parent_path(); - bool any_target = false; - for(const auto &branch : *branches) - { - if(branch.ro()) - continue; - if(fs::exists(branch.path,oldpath_) && - fs::exists(branch.path,newdir)) - { any_target = true; break; } - } - if(!any_target) - return -EXDEV; - } + rv = ::_link_preserve_path(oldpath_,newpath_); + else + rv = cfg.link(cfg.branches,oldpath_,newpath_); - rv = cfg.link(cfg.branches,oldpath_,newpath_); if(rv < 0) return rv; @@ -118,25 +153,25 @@ _link_exdev_abs_base_symlink(const fuse_req_ctx_t *ctx_, int rv; fs::path target; - for(const auto &branch : branches_) - { - if(!fs::exists(branch.path,oldpath_)) - continue; + // Honor func.open: pick the source branch via the configured open + // policy. For 'newest' this picks the branch holding the newest copy + // of oldpath; for the other defaults this is first-found. + Branches::Ptr branches = branches_; + const Branch *src = CloneSource::find(*branches,oldpath_,cfg.open.to_string()); + if(src == nullptr) + return -ENOENT; - target = branch.path / oldpath_; + target = src->path / oldpath_; - rv = FUSE::symlink(ctx_,target.c_str(),newpath_); - if(rv == 0) - rv = FUSE::getattr(ctx_,oldpath_,st_,timeouts_); + rv = FUSE::symlink(ctx_,target.c_str(),newpath_); + if(rv == 0) + rv = FUSE::getattr(ctx_,oldpath_,st_,timeouts_); - // Disable caching since we created a symlink but should be a regular. - timeouts_->attr = 0; - timeouts_->entry = 0; + // Disable caching since we created a symlink but should be a regular. + timeouts_->attr = 0; + timeouts_->entry = 0; - return rv; - } - - return -ENOENT; + return rv; } static diff --git a/src/fuse_rename.cpp b/src/fuse_rename.cpp index debd94dd..f35d21c6 100644 --- a/src/fuse_rename.cpp +++ b/src/fuse_rename.cpp @@ -206,35 +206,90 @@ _create_is_path_preserving() return impl && impl->path_preserving(); } +// Path-preserving rename: rename only on branches that already have BOTH +// oldpath and newdir. Never clone newdir into branches that lacked it. Other +// branches with oldpath get their stale source queued for removal so the file +// does not end up at both old and new paths. +static +int +_rename_preserve_path(const fs::path &oldpath_, + const fs::path &newpath_) +{ + Branches::Ptr branches = cfg.branches; + const fs::path newdir = newpath_.parent_path(); + StrVec toremove; + int err; + bool found; + fs::path oldfullpath; + fs::path newfullpath; + + err = 0; + found = false; + for(auto &branch : *branches) + { + if(branch.ro()) + continue; + + oldfullpath = branch.path / oldpath_; + newfullpath = branch.path / newpath_; + + const bool has_old = fs::exists(branch.path,oldpath_); + const bool has_newdir = fs::exists(branch.path,newdir); + + if(!has_old) + { + if(has_newdir) + toremove.push_back(newfullpath); + continue; + } + + if(!has_newdir) + { + // Branch has source but lacks newdir. Path-preserving: do NOT + // clonepath. Queue source for removal on overall success so the + // file ends up only at branches that did rename successfully. + toremove.push_back(oldfullpath); + continue; + } + + const int rv = fs::rename(oldfullpath,newfullpath); + if(rv < 0) + toremove.push_back(oldfullpath); + + if(!found) + { err = rv; found = true; continue; } + if(rv == 0) + { err = 0; continue; } + if(err == 0) + continue; + err = rv; + } + + if(!found) + return -EXDEV; + + if(err == 0) + { + for(const auto &path : toremove) + fs::remove(path); + } + + return err; +} + static int _rename(const fs::path &oldpath_, const fs::path &newpath_) { - // Honor ignorepponrename: when the create policy is path-preserving - // and the user has not opted out, refuse to clone the new path - // structure into branches that don't already have it. The fallback - // is the EXDEV path which lets the caller handle the move via - // copy+unlink or symlink per cfg.rename_exdev. + // Honor ignorepponrename: when the create policy is path-preserving and + // the user has not opted out, perform the rename only on branches that + // already have both oldpath and newdir — never clone newdir into a branch + // that previously lacked it. Fall through to EXDEV when no qualifying + // branch exists, letting cfg.rename_exdev decide on copy+unlink or + // symlink fallback. if(!cfg.ignorepponrename && ::_create_is_path_preserving()) - { - // Snapshot the Branches::Impl so the per-branch fs::exists - // calls below all observe the same set of branches even if - // cfg.branches is concurrently mutated. - Branches::Ptr branches = cfg.branches; - const fs::path newdir = newpath_.parent_path(); - bool any_target = false; - for(const auto &branch : *branches) - { - if(branch.ro()) - continue; - if(fs::exists(branch.path,oldpath_) && - fs::exists(branch.path,newdir)) - { any_target = true; break; } - } - if(!any_target) - return -EXDEV; - } + return ::_rename_preserve_path(oldpath_,newpath_); return cfg.rename(cfg.branches,oldpath_,newpath_); } diff --git a/src/fuse_write.cpp b/src/fuse_write.cpp index ffff4891..95b0ebc9 100644 --- a/src/fuse_write.cpp +++ b/src/fuse_write.cpp @@ -59,7 +59,8 @@ _move_and_pwrite(const char *buf_, if(cfg.moveonenospc.enabled == false) return err_; - rv = fs::movefile_and_open_as_root(cfg.branches, + rv = fs::movefile_and_open_as_root(cfg.moveonenospc.policy_name, + cfg.branches, fi_->branch.path, fi_->fusepath, fi_->fd); @@ -89,7 +90,8 @@ _move_and_pwriten(char const *buf_, if(cfg.moveonenospc.enabled == false) return err_; - rv = fs::movefile_and_open_as_root(cfg.branches, + rv = fs::movefile_and_open_as_root(cfg.moveonenospc.policy_name, + cfg.branches, fi_->branch.path, fi_->fusepath, fi_->fd);