checkpoint

This commit is contained in:
Antonio S. Musumeci 2026-05-26 21:30:38 -04:00
parent 96d8232853
commit d8ba75cca3
80 changed files with 1051 additions and 373 deletions

View file

@ -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_);

View file

@ -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";
}

View file

@ -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
};

View file

@ -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_);
}

View file

@ -21,18 +21,22 @@
#include "branches.hpp"
#include "fs_path.hpp"
#include <string>
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);
}

View file

@ -11,7 +11,7 @@ namespace Func2
{
public:
AccessBase() {}
~AccessBase() {}
virtual ~AccessBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -15,10 +15,27 @@ Func2::AccessFactory::valid(const std::string str_)
std::shared_ptr<Func2::AccessBase>
Func2::AccessFactory::make(const std::string_view str_)
{
if(str_ == "all") return std::make_shared<Func2::AccessAll>();
if(str_ == "epall") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "erofs") return std::make_shared<Func2::AccessEROFS>();
if(str_ == "ff") return std::make_shared<Func2::AccessFF>();
if(str_ == "erofs") return std::make_shared<Func2::AccessEROFS>();
if(str_ == "all") return std::make_shared<Func2::AccessAll>();
if(str_ == "epall") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "epff") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "eplfs") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "eplus") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "epmfs") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "eprand") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "ff") return std::make_shared<Func2::AccessFF>();
if(str_ == "lfs") return std::make_shared<Func2::AccessFF>();
if(str_ == "lup") return std::make_shared<Func2::AccessFF>();
if(str_ == "lus") return std::make_shared<Func2::AccessFF>();
if(str_ == "mfs") return std::make_shared<Func2::AccessFF>();
if(str_ == "msplfs") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "msplus") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::AccessEPAll>();
if(str_ == "newest") return std::make_shared<Func2::AccessFF>();
if(str_ == "pfrd") return std::make_shared<Func2::AccessFF>();
if(str_ == "rand") return std::make_shared<Func2::AccessFF>();
return {};
}

View file

@ -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)

View file

@ -13,7 +13,7 @@ namespace Func2
{
public:
ChmodBase() {}
~ChmodBase() {}
virtual ~ChmodBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -13,8 +13,27 @@ Func2::ChmodFactory::valid(const std::string str_)
std::shared_ptr<Func2::ChmodBase>
Func2::ChmodFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::ChmodEROFS>();
if(str_ == "all" || str_ == "epall") return std::make_shared<Func2::ChmodAll>();
if(str_ == "erofs") return std::make_shared<Func2::ChmodEROFS>();
if(str_ == "all") return std::make_shared<Func2::ChmodAll>();
if(str_ == "epall") return std::make_shared<Func2::ChmodAll>();
if(str_ == "epff") return std::make_shared<Func2::ChmodAll>();
if(str_ == "eplfs") return std::make_shared<Func2::ChmodAll>();
if(str_ == "eplus") return std::make_shared<Func2::ChmodAll>();
if(str_ == "epmfs") return std::make_shared<Func2::ChmodAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::ChmodAll>();
if(str_ == "eprand") return std::make_shared<Func2::ChmodAll>();
if(str_ == "ff") return std::make_shared<Func2::ChmodAll>();
if(str_ == "lfs") return std::make_shared<Func2::ChmodAll>();
if(str_ == "lup") return std::make_shared<Func2::ChmodAll>();
if(str_ == "lus") return std::make_shared<Func2::ChmodAll>();
if(str_ == "mfs") return std::make_shared<Func2::ChmodAll>();
if(str_ == "msplfs") return std::make_shared<Func2::ChmodAll>();
if(str_ == "msplus") return std::make_shared<Func2::ChmodAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::ChmodAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::ChmodAll>();
if(str_ == "newest") return std::make_shared<Func2::ChmodAll>();
if(str_ == "pfrd") return std::make_shared<Func2::ChmodAll>();
if(str_ == "rand") return std::make_shared<Func2::ChmodAll>();
return {};
}

View file

@ -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)

View file

@ -13,7 +13,7 @@ namespace Func2
{
public:
ChownBase() {}
~ChownBase() {}
virtual ~ChownBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -13,8 +13,27 @@ Func2::ChownFactory::valid(const std::string str_)
std::shared_ptr<Func2::ChownBase>
Func2::ChownFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::ChownEROFS>();
if(str_ == "all" || str_ == "epall") return std::make_shared<Func2::ChownAll>();
if(str_ == "erofs") return std::make_shared<Func2::ChownEROFS>();
if(str_ == "all") return std::make_shared<Func2::ChownAll>();
if(str_ == "epall") return std::make_shared<Func2::ChownAll>();
if(str_ == "epff") return std::make_shared<Func2::ChownAll>();
if(str_ == "eplfs") return std::make_shared<Func2::ChownAll>();
if(str_ == "eplus") return std::make_shared<Func2::ChownAll>();
if(str_ == "epmfs") return std::make_shared<Func2::ChownAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::ChownAll>();
if(str_ == "eprand") return std::make_shared<Func2::ChownAll>();
if(str_ == "ff") return std::make_shared<Func2::ChownAll>();
if(str_ == "lfs") return std::make_shared<Func2::ChownAll>();
if(str_ == "lup") return std::make_shared<Func2::ChownAll>();
if(str_ == "lus") return std::make_shared<Func2::ChownAll>();
if(str_ == "mfs") return std::make_shared<Func2::ChownAll>();
if(str_ == "msplfs") return std::make_shared<Func2::ChownAll>();
if(str_ == "msplus") return std::make_shared<Func2::ChownAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::ChownAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::ChownAll>();
if(str_ == "newest") return std::make_shared<Func2::ChownAll>();
if(str_ == "pfrd") return std::make_shared<Func2::ChownAll>();
if(str_ == "rand") return std::make_shared<Func2::ChownAll>();
return {};
}

View file

@ -13,7 +13,7 @@ namespace Func2
{
public:
CreateBase() {}
~CreateBase() {}
virtual ~CreateBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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;

View file

@ -20,7 +20,7 @@ namespace Func2
{
public:
GetAttrBase() {}
~GetAttrBase() {}
virtual ~GetAttrBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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;

View file

@ -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;

View file

@ -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<Func2::GetAttrCDCO>();
if(str_ == "ff") return std::make_shared<Func2::GetAttrFF>();
if(str_ == "newest") return std::make_shared<Func2::GetAttrNewest>();
if(str_ == "all") return std::make_shared<Func2::GetAttrFF>();
if(str_ == "epall") return std::make_shared<Func2::GetAttrFF>();
if(str_ == "epff") return std::make_shared<Func2::GetAttrFF>();
if(str_ == "eplfs") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "eplus") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "epmfs") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "eppfrd") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "eprand") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "ff") return std::make_shared<Func2::GetAttrFF>();
if(str_ == "lfs") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "lup") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "lus") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "mfs") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "msplfs") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "msplus") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "mspmfs") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "msppfrd") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "newest") return std::make_shared<Func2::GetAttrNewest>();
if(str_ == "pfrd") return std::make_shared<Func2::GetAttrCDFO>();
if(str_ == "rand") return std::make_shared<Func2::GetAttrCDFO>();
return {};
}

View file

@ -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_;

View file

@ -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;

View file

@ -10,7 +10,7 @@ namespace Func2
{
public:
GetxattrBase() {}
~GetxattrBase() {}
virtual ~GetxattrBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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::GetxattrBase>
Func2::GetxattrFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::GetxattrEROFS>();
if(str_ == "ff") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "all") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "epall") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "epff") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "eplfs") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "eplus") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "epmfs") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "eppfrd") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "eprand") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "ff") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "lfs") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "lup") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "lus") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "mfs") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "msplfs") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "msplus") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "mspmfs") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "msppfrd") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "newest") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "pfrd") return std::make_shared<Func2::GetxattrFF>();
if(str_ == "rand") return std::make_shared<Func2::GetxattrFF>();
return {};
}

View file

@ -12,7 +12,7 @@ namespace Func2
{
public:
IoctlBase() {}
~IoctlBase() {}
virtual ~IoctlBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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::IoctlBase>
Func2::IoctlFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::IoctlEROFS>();
if(str_ == "ff") return std::make_shared<Func2::IoctlFF>();
if(str_ == "all") return std::make_shared<Func2::IoctlFF>();
if(str_ == "epall") return std::make_shared<Func2::IoctlFF>();
if(str_ == "epff") return std::make_shared<Func2::IoctlFF>();
if(str_ == "eplfs") return std::make_shared<Func2::IoctlFF>();
if(str_ == "eplus") return std::make_shared<Func2::IoctlFF>();
if(str_ == "epmfs") return std::make_shared<Func2::IoctlFF>();
if(str_ == "eppfrd") return std::make_shared<Func2::IoctlFF>();
if(str_ == "eprand") return std::make_shared<Func2::IoctlFF>();
if(str_ == "ff") return std::make_shared<Func2::IoctlFF>();
if(str_ == "lfs") return std::make_shared<Func2::IoctlFF>();
if(str_ == "lup") return std::make_shared<Func2::IoctlFF>();
if(str_ == "lus") return std::make_shared<Func2::IoctlFF>();
if(str_ == "mfs") return std::make_shared<Func2::IoctlFF>();
if(str_ == "msplfs") return std::make_shared<Func2::IoctlFF>();
if(str_ == "msplus") return std::make_shared<Func2::IoctlFF>();
if(str_ == "mspmfs") return std::make_shared<Func2::IoctlFF>();
if(str_ == "msppfrd") return std::make_shared<Func2::IoctlFF>();
if(str_ == "newest") return std::make_shared<Func2::IoctlFF>();
if(str_ == "pfrd") return std::make_shared<Func2::IoctlFF>();
if(str_ == "rand") return std::make_shared<Func2::IoctlFF>();
return {};
}

View file

@ -9,7 +9,7 @@ namespace Func2
{
public:
LinkBase() {}
~LinkBase() {}
virtual ~LinkBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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)

View file

@ -13,8 +13,27 @@ Func2::LinkFactory::valid(const std::string str_)
std::shared_ptr<Func2::LinkBase>
Func2::LinkFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::LinkEROFS>();
if(str_ == "all" || str_ == "epall") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "erofs") return std::make_shared<Func2::LinkEROFS>();
if(str_ == "all") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "epall") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "epff") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "eplfs") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "eplus") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "epmfs") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "eprand") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "ff") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "lfs") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "lup") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "lus") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "mfs") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "msplfs") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "msplus") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "newest") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "pfrd") return std::make_shared<Func2::LinkEPAll>();
if(str_ == "rand") return std::make_shared<Func2::LinkEPAll>();
return {};
}

View file

@ -10,7 +10,7 @@ namespace Func2
{
public:
ListxattrBase() {}
~ListxattrBase() {}
virtual ~ListxattrBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -14,10 +14,27 @@ Func2::ListxattrFactory::valid(const std::string str_)
std::shared_ptr<Func2::ListxattrBase>
Func2::ListxattrFactory::make(const std::string_view str_)
{
if(str_ == "all") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "epall") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "erofs") return std::make_shared<Func2::ListxattrEROFS>();
if(str_ == "ff") return std::make_shared<Func2::ListxattrFF>();
if(str_ == "all") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "epall") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "epff") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "eplfs") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "eplus") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "epmfs") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "eprand") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "ff") return std::make_shared<Func2::ListxattrFF>();
if(str_ == "lfs") return std::make_shared<Func2::ListxattrFF>();
if(str_ == "lup") return std::make_shared<Func2::ListxattrFF>();
if(str_ == "lus") return std::make_shared<Func2::ListxattrFF>();
if(str_ == "mfs") return std::make_shared<Func2::ListxattrFF>();
if(str_ == "msplfs") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "msplus") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::ListxattrAll>();
if(str_ == "newest") return std::make_shared<Func2::ListxattrFF>();
if(str_ == "pfrd") return std::make_shared<Func2::ListxattrFF>();
if(str_ == "rand") return std::make_shared<Func2::ListxattrFF>();
return {};
}

View file

@ -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;
}

View file

@ -11,7 +11,7 @@ namespace Func2
{
public:
MkdirBase() {}
~MkdirBase() {}
virtual ~MkdirBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -13,7 +13,7 @@ namespace Func2
{
public:
MknodBase() {}
~MknodBase() {}
virtual ~MknodBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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;
}

View file

@ -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;

View file

@ -15,7 +15,7 @@ namespace Func2
{
public:
OpenBase() {}
~OpenBase() {}
virtual ~OpenBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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::OpenBase>
Func2::OpenFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::OpenEROFS>();
if(str_ == "ff") return std::make_shared<Func2::OpenFF>();
if(str_ == "all") return std::make_shared<Func2::OpenFF>();
if(str_ == "epall") return std::make_shared<Func2::OpenFF>();
if(str_ == "epff") return std::make_shared<Func2::OpenFF>();
if(str_ == "eplfs") return std::make_shared<Func2::OpenFF>();
if(str_ == "eplus") return std::make_shared<Func2::OpenFF>();
if(str_ == "epmfs") return std::make_shared<Func2::OpenFF>();
if(str_ == "eppfrd") return std::make_shared<Func2::OpenFF>();
if(str_ == "eprand") return std::make_shared<Func2::OpenFF>();
if(str_ == "ff") return std::make_shared<Func2::OpenFF>();
if(str_ == "lfs") return std::make_shared<Func2::OpenFF>();
if(str_ == "lup") return std::make_shared<Func2::OpenFF>();
if(str_ == "lus") return std::make_shared<Func2::OpenFF>();
if(str_ == "mfs") return std::make_shared<Func2::OpenFF>();
if(str_ == "msplfs") return std::make_shared<Func2::OpenFF>();
if(str_ == "msplus") return std::make_shared<Func2::OpenFF>();
if(str_ == "mspmfs") return std::make_shared<Func2::OpenFF>();
if(str_ == "msppfrd") return std::make_shared<Func2::OpenFF>();
if(str_ == "newest") return std::make_shared<Func2::OpenFF>();
if(str_ == "pfrd") return std::make_shared<Func2::OpenFF>();
if(str_ == "rand") return std::make_shared<Func2::OpenFF>();
return {};
}

View file

@ -10,7 +10,7 @@ namespace Func2
{
public:
ReadlinkBase() {}
~ReadlinkBase() {}
virtual ~ReadlinkBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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::ReadlinkBase>
Func2::ReadlinkFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::ReadlinkEROFS>();
if(str_ == "ff") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "all") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "epall") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "epff") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "eplfs") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "eplus") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "epmfs") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "eppfrd") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "eprand") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "ff") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "lfs") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "lup") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "lus") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "mfs") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "msplfs") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "msplus") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "mspmfs") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "msppfrd") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "newest") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "pfrd") return std::make_shared<Func2::ReadlinkFF>();
if(str_ == "rand") return std::make_shared<Func2::ReadlinkFF>();
return {};
}

View file

@ -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)

View file

@ -10,7 +10,7 @@ namespace Func2
{
public:
RemovexattrBase() {}
~RemovexattrBase() {}
virtual ~RemovexattrBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -13,8 +13,27 @@ Func2::RemovexattrFactory::valid(const std::string str_)
std::shared_ptr<Func2::RemovexattrBase>
Func2::RemovexattrFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::RemovexattrEROFS>();
if(str_ == "all" || str_ == "epall") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "erofs") return std::make_shared<Func2::RemovexattrEROFS>();
if(str_ == "all") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "epall") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "epff") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "eplfs") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "eplus") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "epmfs") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "eprand") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "ff") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "lfs") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "lup") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "lus") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "mfs") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "msplfs") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "msplus") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "newest") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "pfrd") return std::make_shared<Func2::RemovexattrAll>();
if(str_ == "rand") return std::make_shared<Func2::RemovexattrAll>();
return {};
}

View file

@ -9,7 +9,7 @@ namespace Func2
{
public:
RenameBase() {}
~RenameBase() {}
virtual ~RenameBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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)

View file

@ -13,8 +13,27 @@ Func2::RenameFactory::valid(const std::string str_)
std::shared_ptr<Func2::RenameBase>
Func2::RenameFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::RenameEROFS>();
if(str_ == "all" || str_ == "epall") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "erofs") return std::make_shared<Func2::RenameEROFS>();
if(str_ == "all") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "epall") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "epff") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "eplfs") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "eplus") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "epmfs") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "eprand") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "ff") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "lfs") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "lup") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "lus") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "mfs") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "msplfs") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "msplus") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "newest") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "pfrd") return std::make_shared<Func2::RenameEPAll>();
if(str_ == "rand") return std::make_shared<Func2::RenameEPAll>();
return {};
}

View file

@ -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)

View file

@ -10,7 +10,7 @@ namespace Func2
{
public:
RmdirBase() {}
~RmdirBase() {}
virtual ~RmdirBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -13,8 +13,27 @@ Func2::RmdirFactory::valid(const std::string str_)
std::shared_ptr<Func2::RmdirBase>
Func2::RmdirFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::RmdirEROFS>();
if(str_ == "all" || str_ == "epall") return std::make_shared<Func2::RmdirAll>();
if(str_ == "erofs") return std::make_shared<Func2::RmdirEROFS>();
if(str_ == "all") return std::make_shared<Func2::RmdirAll>();
if(str_ == "epall") return std::make_shared<Func2::RmdirAll>();
if(str_ == "epff") return std::make_shared<Func2::RmdirAll>();
if(str_ == "eplfs") return std::make_shared<Func2::RmdirAll>();
if(str_ == "eplus") return std::make_shared<Func2::RmdirAll>();
if(str_ == "epmfs") return std::make_shared<Func2::RmdirAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::RmdirAll>();
if(str_ == "eprand") return std::make_shared<Func2::RmdirAll>();
if(str_ == "ff") return std::make_shared<Func2::RmdirAll>();
if(str_ == "lfs") return std::make_shared<Func2::RmdirAll>();
if(str_ == "lup") return std::make_shared<Func2::RmdirAll>();
if(str_ == "lus") return std::make_shared<Func2::RmdirAll>();
if(str_ == "mfs") return std::make_shared<Func2::RmdirAll>();
if(str_ == "msplfs") return std::make_shared<Func2::RmdirAll>();
if(str_ == "msplus") return std::make_shared<Func2::RmdirAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::RmdirAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::RmdirAll>();
if(str_ == "newest") return std::make_shared<Func2::RmdirAll>();
if(str_ == "pfrd") return std::make_shared<Func2::RmdirAll>();
if(str_ == "rand") return std::make_shared<Func2::RmdirAll>();
return {};
}

View file

@ -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)

View file

@ -10,7 +10,7 @@ namespace Func2
{
public:
SetxattrBase() {}
~SetxattrBase() {}
virtual ~SetxattrBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -13,8 +13,27 @@ Func2::SetxattrFactory::valid(const std::string str_)
std::shared_ptr<Func2::SetxattrBase>
Func2::SetxattrFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::SetxattrEROFS>();
if(str_ == "all" || str_ == "epall") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "erofs") return std::make_shared<Func2::SetxattrEROFS>();
if(str_ == "all") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "epall") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "epff") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "eplfs") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "eplus") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "epmfs") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "eprand") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "ff") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "lfs") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "lup") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "lus") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "mfs") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "msplfs") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "msplus") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "newest") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "pfrd") return std::make_shared<Func2::SetxattrAll>();
if(str_ == "rand") return std::make_shared<Func2::SetxattrAll>();
return {};
}

View file

@ -21,7 +21,7 @@ namespace Func2
{
public:
StatxBase() {}
~StatxBase() {}
virtual ~StatxBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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;

View file

@ -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;

View file

@ -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<Func2::StatxCDCO>();
if(str_ == "ff") return std::make_shared<Func2::StatxFF>();
if(str_ == "newest") return std::make_shared<Func2::StatxNewest>();
if(str_ == "all") return std::make_shared<Func2::StatxFF>();
if(str_ == "epall") return std::make_shared<Func2::StatxFF>();
if(str_ == "epff") return std::make_shared<Func2::StatxFF>();
if(str_ == "eplfs") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "eplus") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "epmfs") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "eppfrd") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "eprand") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "ff") return std::make_shared<Func2::StatxFF>();
if(str_ == "lfs") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "lup") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "lus") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "mfs") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "msplfs") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "msplus") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "mspmfs") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "msppfrd") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "newest") return std::make_shared<Func2::StatxNewest>();
if(str_ == "pfrd") return std::make_shared<Func2::StatxCDFO>();
if(str_ == "rand") return std::make_shared<Func2::StatxCDFO>();
return {};
}

View file

@ -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_;

View file

@ -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;

View file

@ -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;
}

View file

@ -13,7 +13,7 @@ namespace Func2
{
public:
SymlinkBase() {}
~SymlinkBase() {}
virtual ~SymlinkBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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)

View file

@ -10,7 +10,7 @@ namespace Func2
{
public:
TruncateBase() {}
~TruncateBase() {}
virtual ~TruncateBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -13,8 +13,27 @@ Func2::TruncateFactory::valid(const std::string str_)
std::shared_ptr<Func2::TruncateBase>
Func2::TruncateFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::TruncateEROFS>();
if(str_ == "all" || str_ == "epall") return std::make_shared<Func2::TruncateAll>();
if(str_ == "erofs") return std::make_shared<Func2::TruncateEROFS>();
if(str_ == "all") return std::make_shared<Func2::TruncateAll>();
if(str_ == "epall") return std::make_shared<Func2::TruncateAll>();
if(str_ == "epff") return std::make_shared<Func2::TruncateAll>();
if(str_ == "eplfs") return std::make_shared<Func2::TruncateAll>();
if(str_ == "eplus") return std::make_shared<Func2::TruncateAll>();
if(str_ == "epmfs") return std::make_shared<Func2::TruncateAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::TruncateAll>();
if(str_ == "eprand") return std::make_shared<Func2::TruncateAll>();
if(str_ == "ff") return std::make_shared<Func2::TruncateAll>();
if(str_ == "lfs") return std::make_shared<Func2::TruncateAll>();
if(str_ == "lup") return std::make_shared<Func2::TruncateAll>();
if(str_ == "lus") return std::make_shared<Func2::TruncateAll>();
if(str_ == "mfs") return std::make_shared<Func2::TruncateAll>();
if(str_ == "msplfs") return std::make_shared<Func2::TruncateAll>();
if(str_ == "msplus") return std::make_shared<Func2::TruncateAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::TruncateAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::TruncateAll>();
if(str_ == "newest") return std::make_shared<Func2::TruncateAll>();
if(str_ == "pfrd") return std::make_shared<Func2::TruncateAll>();
if(str_ == "rand") return std::make_shared<Func2::TruncateAll>();
return {};
}

View file

@ -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)

View file

@ -10,7 +10,7 @@ namespace Func2
{
public:
UnlinkBase() {}
~UnlinkBase() {}
virtual ~UnlinkBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -14,10 +14,27 @@ Func2::UnlinkFactory::valid(const std::string str_)
std::shared_ptr<Func2::UnlinkBase>
Func2::UnlinkFactory::make(const std::string_view str_)
{
if(str_ == "all") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "epall") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "erofs") return std::make_shared<Func2::UnlinkEROFS>();
if(str_ == "newest") return std::make_shared<Func2::UnlinkNewest>();
if(str_ == "all") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "epall") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "epff") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "eplfs") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "eplus") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "epmfs") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "eprand") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "ff") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "lfs") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "lup") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "lus") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "mfs") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "msplfs") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "msplus") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "pfrd") return std::make_shared<Func2::UnlinkAll>();
if(str_ == "rand") return std::make_shared<Func2::UnlinkAll>();
return {};
}

View file

@ -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)

View file

@ -10,7 +10,7 @@ namespace Func2
{
public:
UtimensBase() {}
~UtimensBase() {}
virtual ~UtimensBase() = default;
public:
virtual std::string_view name() const = 0;

View file

@ -13,8 +13,27 @@ Func2::UtimensFactory::valid(const std::string str_)
std::shared_ptr<Func2::UtimensBase>
Func2::UtimensFactory::make(const std::string_view str_)
{
if(str_ == "erofs") return std::make_shared<Func2::UtimensEROFS>();
if(str_ == "all" || str_ == "epall") return std::make_shared<Func2::UtimensAll>();
if(str_ == "erofs") return std::make_shared<Func2::UtimensEROFS>();
if(str_ == "all") return std::make_shared<Func2::UtimensAll>();
if(str_ == "epall") return std::make_shared<Func2::UtimensAll>();
if(str_ == "epff") return std::make_shared<Func2::UtimensAll>();
if(str_ == "eplfs") return std::make_shared<Func2::UtimensAll>();
if(str_ == "eplus") return std::make_shared<Func2::UtimensAll>();
if(str_ == "epmfs") return std::make_shared<Func2::UtimensAll>();
if(str_ == "eppfrd") return std::make_shared<Func2::UtimensAll>();
if(str_ == "eprand") return std::make_shared<Func2::UtimensAll>();
if(str_ == "ff") return std::make_shared<Func2::UtimensAll>();
if(str_ == "lfs") return std::make_shared<Func2::UtimensAll>();
if(str_ == "lup") return std::make_shared<Func2::UtimensAll>();
if(str_ == "lus") return std::make_shared<Func2::UtimensAll>();
if(str_ == "mfs") return std::make_shared<Func2::UtimensAll>();
if(str_ == "msplfs") return std::make_shared<Func2::UtimensAll>();
if(str_ == "msplus") return std::make_shared<Func2::UtimensAll>();
if(str_ == "mspmfs") return std::make_shared<Func2::UtimensAll>();
if(str_ == "msppfrd") return std::make_shared<Func2::UtimensAll>();
if(str_ == "newest") return std::make_shared<Func2::UtimensAll>();
if(str_ == "pfrd") return std::make_shared<Func2::UtimensAll>();
if(str_ == "rand") return std::make_shared<Func2::UtimensAll>();
return {};
}

View file

@ -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

View file

@ -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_);
}

View file

@ -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);