mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-25 18:40:18 -04:00
Implement bespoke branch policies
Consolidate branch policy selection behind the BranchPolicy interfaces and update filesystem operations to use the bespoke policy implementations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
42ab831d97
commit
96d8232853
451 changed files with 18495 additions and 7562 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -31,3 +31,6 @@ rpmbuild/
|
|||
# mkdocs files
|
||||
mkdocs/venv
|
||||
__pycache__/
|
||||
|
||||
# claude code harness
|
||||
.claude/
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "tofrom_string.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
|
|
@ -78,10 +79,60 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
public:
|
||||
class ConstIterator
|
||||
{
|
||||
private:
|
||||
Branches::Ptr _impl;
|
||||
size_t _idx = 0;
|
||||
|
||||
public:
|
||||
ConstIterator() = default;
|
||||
ConstIterator(Branches::Ptr impl_,
|
||||
const size_t idx_)
|
||||
: _impl(impl_),
|
||||
_idx(idx_)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
const Branch& operator*() const
|
||||
{
|
||||
return (*_impl)[_idx];
|
||||
}
|
||||
|
||||
ConstIterator& operator++()
|
||||
{
|
||||
++_idx;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!=(const ConstIterator &rhs_) const
|
||||
{
|
||||
if(rhs_._impl == nullptr)
|
||||
return (_impl != nullptr && _idx < _impl->size());
|
||||
if(_impl == nullptr)
|
||||
return (rhs_._impl != nullptr && rhs_._idx < rhs_._impl->size());
|
||||
return ((_impl != rhs_._impl) || (_idx != rhs_._idx));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
int from_string(const std::string_view str) final;
|
||||
std::string to_string(void) const final;
|
||||
|
||||
public:
|
||||
ConstIterator begin() const
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lk(_mutex);
|
||||
return ConstIterator(_impl,0);
|
||||
}
|
||||
|
||||
ConstIterator end() const
|
||||
{
|
||||
return ConstIterator();
|
||||
}
|
||||
|
||||
public:
|
||||
operator Ptr() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
#include "category.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
int
|
||||
|
|
@ -34,16 +34,45 @@ Category::Base::from_string(const std::string_view s_)
|
|||
return rv;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(_last_set_mutex);
|
||||
_last_set = std::string(s_);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
Category::Base::to_string(void) const
|
||||
{
|
||||
std::set<std::string> rv;
|
||||
// Snapshot the last category-wide input under the lock so a
|
||||
// concurrent from_string can't tear the string mid-read.
|
||||
std::string last;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(_last_set_mutex);
|
||||
last = _last_set;
|
||||
}
|
||||
|
||||
// Collect current constituent names. Each FuncWrapper::to_string is
|
||||
// itself mutex-protected.
|
||||
std::set<std::string> names;
|
||||
for(const auto func : funcs)
|
||||
rv.insert(func->to_string());
|
||||
names.insert(func->to_string());
|
||||
|
||||
return str::join(rv,',');
|
||||
if(names.size() == 1)
|
||||
{
|
||||
// All children agree. Prefer _last_set (round-trippable through
|
||||
// the category-wide setter even when it maps to the agreed
|
||||
// name); otherwise fall back to the agreed name.
|
||||
if(!last.empty())
|
||||
return last;
|
||||
return *names.begin();
|
||||
}
|
||||
|
||||
// Children diverge — either no category-wide assignment ever ran,
|
||||
// or a per-function override has changed a child since the last
|
||||
// category-wide set. Report "mixed" rather than a stale _last_set,
|
||||
// since per-function .to_string()s are the source of truth for the
|
||||
// actual policy in effect.
|
||||
return std::string("mixed");
|
||||
}
|
||||
|
|
|
|||
119
src/category.hpp
119
src/category.hpp
|
|
@ -19,10 +19,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "tofrom_string.hpp"
|
||||
#include "funcs.hpp"
|
||||
#include "func.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Category
|
||||
{
|
||||
|
|
@ -34,6 +34,13 @@ namespace Category
|
|||
|
||||
protected:
|
||||
std::vector<ToFromString*> funcs;
|
||||
// The last value successfully applied via from_string. Categories
|
||||
// can map a single user input to different per-function default
|
||||
// classes, so the constituent name()s may disagree. Returning the
|
||||
// last-set value here keeps to_string output round-trippable, but
|
||||
// only if no per-function override has since diverged the children.
|
||||
std::string _last_set;
|
||||
mutable std::mutex _last_set_mutex;
|
||||
};
|
||||
|
||||
class Action final : public Base
|
||||
|
|
@ -42,18 +49,27 @@ namespace Category
|
|||
Action();
|
||||
|
||||
public:
|
||||
Action(Funcs &funcs_)
|
||||
Action(ToFromString &chmod_,
|
||||
ToFromString &chown_,
|
||||
ToFromString &link_,
|
||||
ToFromString &removexattr_,
|
||||
ToFromString &rename_,
|
||||
ToFromString &rmdir_,
|
||||
ToFromString &setxattr_,
|
||||
ToFromString &truncate_,
|
||||
ToFromString &unlink_,
|
||||
ToFromString &utimens_)
|
||||
{
|
||||
funcs.push_back(&funcs_.chmod);
|
||||
funcs.push_back(&funcs_.chown);
|
||||
funcs.push_back(&funcs_.link);
|
||||
funcs.push_back(&funcs_.removexattr);
|
||||
funcs.push_back(&funcs_.rename);
|
||||
funcs.push_back(&funcs_.rmdir);
|
||||
funcs.push_back(&funcs_.setxattr);
|
||||
funcs.push_back(&funcs_.truncate);
|
||||
funcs.push_back(&funcs_.unlink);
|
||||
funcs.push_back(&funcs_.utimens);
|
||||
funcs.push_back(&chmod_);
|
||||
funcs.push_back(&chown_);
|
||||
funcs.push_back(&link_);
|
||||
funcs.push_back(&removexattr_);
|
||||
funcs.push_back(&rename_);
|
||||
funcs.push_back(&rmdir_);
|
||||
funcs.push_back(&setxattr_);
|
||||
funcs.push_back(&truncate_);
|
||||
funcs.push_back(&unlink_);
|
||||
funcs.push_back(&utimens_);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -63,12 +79,15 @@ namespace Category
|
|||
Create();
|
||||
|
||||
public:
|
||||
Create(Funcs &funcs_)
|
||||
Create(ToFromString &create_,
|
||||
ToFromString &mkdir_,
|
||||
ToFromString &mknod_,
|
||||
ToFromString &symlink_)
|
||||
{
|
||||
funcs.push_back(&funcs_.create);
|
||||
funcs.push_back(&funcs_.mkdir);
|
||||
funcs.push_back(&funcs_.mknod);
|
||||
funcs.push_back(&funcs_.symlink);
|
||||
funcs.push_back(&create_);
|
||||
funcs.push_back(&mkdir_);
|
||||
funcs.push_back(&mknod_);
|
||||
funcs.push_back(&symlink_);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -78,14 +97,21 @@ namespace Category
|
|||
Search();
|
||||
|
||||
public:
|
||||
Search(Funcs &funcs_)
|
||||
Search(ToFromString &access_,
|
||||
ToFromString &getattr_,
|
||||
ToFromString &getxattr_,
|
||||
ToFromString &ioctl_,
|
||||
ToFromString &listxattr_,
|
||||
ToFromString &open_,
|
||||
ToFromString &readlink_)
|
||||
{
|
||||
funcs.push_back(&funcs_.access);
|
||||
funcs.push_back(&funcs_.getattr);
|
||||
funcs.push_back(&funcs_.getxattr);
|
||||
funcs.push_back(&funcs_.listxattr);
|
||||
funcs.push_back(&funcs_.open);
|
||||
funcs.push_back(&funcs_.readlink);
|
||||
funcs.push_back(&access_);
|
||||
funcs.push_back(&getattr_);
|
||||
funcs.push_back(&getxattr_);
|
||||
funcs.push_back(&ioctl_);
|
||||
funcs.push_back(&listxattr_);
|
||||
funcs.push_back(&open_);
|
||||
funcs.push_back(&readlink_);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -96,10 +122,45 @@ private:
|
|||
Categories();
|
||||
|
||||
public:
|
||||
Categories(Funcs &funcs_)
|
||||
: action(funcs_),
|
||||
create(funcs_),
|
||||
search(funcs_)
|
||||
Categories(ToFromString &access_,
|
||||
ToFromString &chmod_,
|
||||
ToFromString &chown_,
|
||||
ToFromString &link_,
|
||||
ToFromString &getattr_,
|
||||
ToFromString &getxattr_,
|
||||
ToFromString &ioctl_,
|
||||
ToFromString &listxattr_,
|
||||
ToFromString &open_,
|
||||
ToFromString &readlink_,
|
||||
ToFromString &rename_,
|
||||
ToFromString &removexattr_,
|
||||
ToFromString &rmdir_,
|
||||
ToFromString &setxattr_,
|
||||
ToFromString &truncate_,
|
||||
ToFromString &unlink_,
|
||||
ToFromString &utimens_,
|
||||
ToFromString &create_,
|
||||
ToFromString &mkdir_,
|
||||
ToFromString &mknod_,
|
||||
ToFromString &symlink_)
|
||||
: action(chmod_,
|
||||
chown_,
|
||||
link_,
|
||||
removexattr_,
|
||||
rename_,
|
||||
rmdir_,
|
||||
setxattr_,
|
||||
truncate_,
|
||||
unlink_,
|
||||
utimens_),
|
||||
create(create_,mkdir_,mknod_,symlink_),
|
||||
search(access_,
|
||||
getattr_,
|
||||
getxattr_,
|
||||
ioctl_,
|
||||
listxattr_,
|
||||
open_,
|
||||
readlink_)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -85,7 +85,27 @@ Config::Config()
|
|||
cache_statfs(0),
|
||||
cache_symlinks(false),
|
||||
cache_writeback(false),
|
||||
category(func),
|
||||
category(access,
|
||||
chmod,
|
||||
chown,
|
||||
link,
|
||||
_getattr_statx,
|
||||
getxattr,
|
||||
ioctl,
|
||||
listxattr,
|
||||
open,
|
||||
readlink,
|
||||
rename,
|
||||
removexattr,
|
||||
rmdir,
|
||||
setxattr,
|
||||
truncate,
|
||||
unlink,
|
||||
utimens,
|
||||
create,
|
||||
mkdir,
|
||||
mknod,
|
||||
symlink),
|
||||
config_file(),
|
||||
direct_io_allow_mmap(true),
|
||||
dropcacheonclose(false),
|
||||
|
|
@ -93,7 +113,6 @@ Config::Config()
|
|||
flushonclose(FlushOnClose::ENUM::OPENED_FOR_WRITE),
|
||||
follow_symlinks(FollowSymlinks::ENUM::NEVER),
|
||||
fsname(),
|
||||
func(),
|
||||
fuse_msg_size("1M"),
|
||||
handle_killpriv(true),
|
||||
handle_killpriv_v2(true),
|
||||
|
|
@ -219,27 +238,29 @@ Config::Config()
|
|||
_map["flush-on-close"] = &flushonclose;
|
||||
_map["follow-symlinks"] = &follow_symlinks;
|
||||
_map["fsname"] = &fsname;
|
||||
_map["func.access"] = &func.access;
|
||||
_map["func.chmod"] = &func.chmod;
|
||||
_map["func.chown"] = &func.chown;
|
||||
_map["func.create"] = &func.create;
|
||||
_map["func.getattr"] = &func.getattr;
|
||||
_map["func.getxattr"] = &func.getxattr;
|
||||
_map["func.link"] = &func.link;
|
||||
_map["func.listxattr"] = &func.listxattr;
|
||||
_map["func.mkdir"] = &func.mkdir;
|
||||
_map["func.mknod"] = &func.mknod;
|
||||
_map["func.open"] = &func.open;
|
||||
_map["func.access"] = &access;
|
||||
_map["func.chmod"] = &chmod;
|
||||
_map["func.chown"] = &chown;
|
||||
_map["func.create"] = &create;
|
||||
_map["func.getattr"] = &_getattr_statx;
|
||||
_map["func.getxattr"] = &getxattr;
|
||||
_map["func.ioctl"] = &ioctl;
|
||||
_map["func.link"] = &link;
|
||||
_map["func.listxattr"] = &listxattr;
|
||||
_map["func.mkdir"] = &mkdir;
|
||||
_map["func.mknod"] = &mknod;
|
||||
_map["func.open"] = &open;
|
||||
_map["func.readdir"] = &readdir;
|
||||
_map["func.readlink"] = &func.readlink;
|
||||
_map["func.removexattr"] = &func.removexattr;
|
||||
_map["func.rename"] = &func.rename;
|
||||
_map["func.rmdir"] = &func.rmdir;
|
||||
_map["func.setxattr"] = &func.setxattr;
|
||||
_map["func.symlink"] = &func.symlink;
|
||||
_map["func.truncate"] = &func.truncate;
|
||||
_map["func.unlink"] = &func.unlink;
|
||||
_map["func.utimens"] = &func.utimens;
|
||||
_map["func.readlink"] = &readlink;
|
||||
_map["func.removexattr"] = &removexattr;
|
||||
_map["func.rename"] = &rename;
|
||||
_map["func.rmdir"] = &rmdir;
|
||||
_map["func.setxattr"] = &setxattr;
|
||||
_map["func.statx"] = &_getattr_statx;
|
||||
_map["func.symlink"] = &symlink;
|
||||
_map["func.truncate"] = &truncate;
|
||||
_map["func.unlink"] = &unlink;
|
||||
_map["func.utimens"] = &utimens;
|
||||
_map["fuse-msg-size"] = &fuse_msg_size;
|
||||
_map["gid"] = &_gid;
|
||||
_map["gid-cache.expire-timeout"] = &_dummy;
|
||||
|
|
@ -448,6 +469,34 @@ Config::finish_initializing()
|
|||
_initialized = true;
|
||||
}
|
||||
|
||||
void
|
||||
Config::initialize_funcs()
|
||||
{
|
||||
access.initialize();
|
||||
chmod.initialize();
|
||||
chown.initialize();
|
||||
create.initialize();
|
||||
getattr.initialize();
|
||||
getxattr.initialize();
|
||||
ioctl.initialize();
|
||||
link.initialize();
|
||||
listxattr.initialize();
|
||||
mkdir.initialize();
|
||||
mknod.initialize();
|
||||
open.initialize();
|
||||
readlink.initialize();
|
||||
removexattr.initialize();
|
||||
rename.initialize();
|
||||
rmdir.initialize();
|
||||
setxattr.initialize();
|
||||
statx.initialize();
|
||||
symlink.initialize();
|
||||
truncate.initialize();
|
||||
unlink.initialize();
|
||||
utimens.initialize();
|
||||
readdir.initialize();
|
||||
}
|
||||
|
||||
bool
|
||||
Config::is_rootdir(const fs::path &fusepath_)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,6 +18,29 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "func_access.hpp"
|
||||
#include "func_chmod.hpp"
|
||||
#include "func_chown.hpp"
|
||||
#include "func_create.hpp"
|
||||
#include "func_getattr.hpp"
|
||||
#include "func_getxattr.hpp"
|
||||
#include "func_ioctl.hpp"
|
||||
#include "func_link.hpp"
|
||||
#include "func_listxattr.hpp"
|
||||
#include "func_mkdir.hpp"
|
||||
#include "func_mknod.hpp"
|
||||
#include "func_open.hpp"
|
||||
#include "func_readlink.hpp"
|
||||
#include "func_removexattr.hpp"
|
||||
#include "func_rename.hpp"
|
||||
#include "func_rmdir.hpp"
|
||||
#include "func_setxattr.hpp"
|
||||
#include "func_statx.hpp"
|
||||
#include "func_symlink.hpp"
|
||||
#include "func_truncate.hpp"
|
||||
#include "func_unlink.hpp"
|
||||
#include "func_utimens.hpp"
|
||||
|
||||
#include "branches.hpp"
|
||||
#include "category.hpp"
|
||||
#include "config_cachefiles.hpp"
|
||||
|
|
@ -25,6 +48,7 @@
|
|||
#include "config_dummy.hpp"
|
||||
#include "config_flushonclose.hpp"
|
||||
#include "config_follow_symlinks.hpp"
|
||||
#include "config_getattr_statx.hpp"
|
||||
#include "config_inodecalc.hpp"
|
||||
#include "config_link_exdev.hpp"
|
||||
#include "config_log_file.hpp"
|
||||
|
|
@ -43,10 +67,8 @@
|
|||
#include "enum.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "funcs.hpp"
|
||||
#include "fuse_cfg.hpp"
|
||||
#include "fuse_readdir.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "tofrom_ref.hpp"
|
||||
#include "tofrom_wrapper.hpp"
|
||||
#include "syslog.hpp"
|
||||
|
|
@ -107,6 +129,31 @@ public:
|
|||
Config();
|
||||
|
||||
public:
|
||||
Func2::Access access{"ff"};
|
||||
Func2::Chmod chmod{"all"};
|
||||
Func2::Chown chown{"all"};
|
||||
Func2::Create create{"pfrd"};
|
||||
Func2::GetAttr getattr{"cdfo"};
|
||||
Func2::Getxattr getxattr{"ff"};
|
||||
Func2::Ioctl ioctl{"ff"};
|
||||
Func2::Link link{"epall"};
|
||||
Func2::Listxattr listxattr{"ff"};
|
||||
Func2::Mkdir mkdir{"pfrd"};
|
||||
Func2::Mknod mknod{"ff"};
|
||||
Func2::Open open{"ff"};
|
||||
Func2::Readlink readlink{"ff"};
|
||||
Func2::Removexattr removexattr{"all"};
|
||||
Func2::Rename rename{"epall"};
|
||||
Func2::Rmdir rmdir{"all"};
|
||||
Func2::Setxattr setxattr{"all"};
|
||||
Func2::Statx statx{"cdfo"};
|
||||
Func2::Symlink symlink{"pfrd"};
|
||||
Func2::Truncate truncate{"all"};
|
||||
Func2::Unlink unlink{"all"};
|
||||
Func2::Utimens utimens{"all"};
|
||||
|
||||
ConfigGetAttrStatx _getattr_statx{getattr,statx};
|
||||
|
||||
ConfigBOOL allow_idmap;
|
||||
ConfigBOOL async_read;
|
||||
Branches branches;
|
||||
|
|
@ -129,7 +176,6 @@ public:
|
|||
FlushOnClose flushonclose;
|
||||
FollowSymlinks follow_symlinks;
|
||||
ConfigSTR fsname;
|
||||
Funcs func;
|
||||
ConfigPageSize fuse_msg_size;
|
||||
ConfigBOOL handle_killpriv;
|
||||
ConfigBOOL handle_killpriv_v2;
|
||||
|
|
@ -189,6 +235,7 @@ private:
|
|||
|
||||
public:
|
||||
void finish_initializing();
|
||||
void initialize_funcs();
|
||||
|
||||
public:
|
||||
friend std::ostream& operator<<(std::ostream &s,
|
||||
|
|
|
|||
|
|
@ -19,12 +19,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "enum.hpp"
|
||||
#include "follow_symlinks_enum.hpp"
|
||||
|
||||
enum class FollowSymlinksEnum
|
||||
{
|
||||
NEVER,
|
||||
DIRECTORY,
|
||||
REGULAR,
|
||||
ALL
|
||||
};
|
||||
typedef Enum<FollowSymlinksEnum> FollowSymlinks;
|
||||
|
|
|
|||
53
src/config_getattr_statx.hpp
Normal file
53
src/config_getattr_statx.hpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
#include "config.hpp"
|
||||
#include "tofrom_string.hpp"
|
||||
|
||||
class ConfigGetAttrStatx : public ToFromString
|
||||
{
|
||||
private:
|
||||
Func2::GetAttr &_getattr;
|
||||
Func2::Statx &_statx;
|
||||
|
||||
public:
|
||||
ConfigGetAttrStatx() = delete;
|
||||
ConfigGetAttrStatx(Func2::GetAttr &getattr_,
|
||||
Func2::Statx &statx_)
|
||||
: _getattr(getattr_),
|
||||
_statx(statx_)
|
||||
{
|
||||
}
|
||||
|
||||
std::string
|
||||
to_string() const
|
||||
{
|
||||
std::string g = _getattr.to_string();
|
||||
std::string s = _statx.to_string();
|
||||
|
||||
if(g == s)
|
||||
return g;
|
||||
|
||||
return g + "," + s;
|
||||
}
|
||||
|
||||
int
|
||||
from_string(const std::string_view str_)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if(!Func2::GetAttrFactory::valid(std::string(str_)))
|
||||
return -EINVAL;
|
||||
if(!Func2::StatxFactory::valid(std::string(str_)))
|
||||
return -EINVAL;
|
||||
|
||||
rv = _getattr.from_string(str_);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
rv = _statx.from_string(str_);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
#include "config_moveonenospc.hpp"
|
||||
#include "ef.hpp"
|
||||
|
||||
#include "errno.hpp"
|
||||
#include "from_string.hpp"
|
||||
|
||||
|
|
@ -25,34 +25,16 @@
|
|||
int
|
||||
MoveOnENOSPC::from_string(const std::string_view s_)
|
||||
{
|
||||
int rv;
|
||||
std::string s;
|
||||
Policy::CreateImpl *tmp;
|
||||
|
||||
rv = str::from(s_,&enabled);
|
||||
if((rv == 0) && (enabled == true))
|
||||
s = "pfrd";
|
||||
ef((rv == 0) && (enabled == false))
|
||||
return (enabled = false,0);
|
||||
ef(rv != 0)
|
||||
s = s_;
|
||||
else
|
||||
bool tmp;
|
||||
const int rv = str::from(s_,&tmp);
|
||||
if(rv != 0)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = Policies::Create::find(s);
|
||||
if(tmp == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
policy = tmp;
|
||||
enabled = true;
|
||||
|
||||
enabled = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
MoveOnENOSPC::to_string(void) const
|
||||
{
|
||||
if(enabled)
|
||||
return policy.name();
|
||||
return "false";
|
||||
return (enabled ? "true" : "false");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "policy.hpp"
|
||||
#include "policies.hpp"
|
||||
#include "tofrom_string.hpp"
|
||||
|
||||
#include <string>
|
||||
|
|
@ -29,8 +27,7 @@ class MoveOnENOSPC : public ToFromString
|
|||
{
|
||||
public:
|
||||
MoveOnENOSPC(const bool enabled_)
|
||||
: enabled(enabled_),
|
||||
policy(&Policies::Create::pfrd)
|
||||
: enabled(enabled_)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -40,5 +37,4 @@ public:
|
|||
|
||||
public:
|
||||
bool enabled;
|
||||
Policy::Create policy;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2026, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "errno.hpp"
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
||||
struct Err
|
||||
{
|
||||
private:
|
||||
std::optional<int> _err;
|
||||
|
||||
public:
|
||||
Err()
|
||||
{
|
||||
}
|
||||
|
||||
operator int()
|
||||
{
|
||||
return (_err.has_value() ? _err.value() : -ENOENT);
|
||||
}
|
||||
|
||||
Err&
|
||||
operator=(int v_)
|
||||
{
|
||||
if(!_err.has_value())
|
||||
_err = ((v_ >= 0) ? 0 : v_);
|
||||
else if(v_ >= 0)
|
||||
_err = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(int v_)
|
||||
{
|
||||
if(_err.has_value())
|
||||
return (_err.value() == v_);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
9
src/follow_symlinks_enum.hpp
Normal file
9
src/follow_symlinks_enum.hpp
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
enum class FollowSymlinksEnum
|
||||
{
|
||||
NEVER,
|
||||
DIRECTORY,
|
||||
REGULAR,
|
||||
ALL
|
||||
};
|
||||
|
|
@ -19,8 +19,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "to_neg_errno.hpp"
|
||||
|
||||
#include <string>
|
||||
#include "to_cstr.hpp"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
|
@ -29,25 +28,17 @@
|
|||
|
||||
namespace fs
|
||||
{
|
||||
template<typename PathType>
|
||||
static
|
||||
inline
|
||||
int
|
||||
lstat(const char *path_,
|
||||
struct stat *st_)
|
||||
lstat(const PathType &path_,
|
||||
struct stat *st_)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = ::lstat(path_,st_);
|
||||
rv = ::lstat(to_cstr(path_),st_);
|
||||
|
||||
return ::to_neg_errno(rv);
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
int
|
||||
lstat(const std::string &path_,
|
||||
struct stat *st_)
|
||||
{
|
||||
return fs::lstat(path_.c_str(),st_);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_mknod.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
|
|
@ -31,9 +32,13 @@ namespace fs
|
|||
int
|
||||
mknod_as(const ugid_t ugid_,
|
||||
const T &path_,
|
||||
const mode_t mode_,
|
||||
const dev_t dev_)
|
||||
mode_t mode_,
|
||||
dev_t dev_,
|
||||
mode_t umask_)
|
||||
{
|
||||
if(not fs::acl::dir_has_defaults(path_))
|
||||
mode_ &= ~umask_;
|
||||
|
||||
const ugid::SetGuard _(ugid_);
|
||||
|
||||
return fs::mknod(path_,mode_,dev_);
|
||||
|
|
@ -41,6 +46,7 @@ namespace fs
|
|||
}
|
||||
#elif defined __FreeBSD__
|
||||
#include "fs_lchown.hpp"
|
||||
#include "fs_unlink.hpp"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
|
|
@ -50,16 +56,29 @@ namespace fs
|
|||
int
|
||||
mknod_as(const ugid_t ugid_,
|
||||
const T &path_,
|
||||
const mode_t mode_,
|
||||
const dev_t dev_)
|
||||
mode_t mode_,
|
||||
dev_t dev_,
|
||||
mode_t umask_)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if(not fs::acl::dir_has_defaults(path_))
|
||||
mode_ &= ~umask_;
|
||||
|
||||
rv = fs::mknod(path_,mode_,dev_);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
fs::lchown(path_,ugid_.uid,ugid_.gid);
|
||||
const int lrv = fs::lchown(path_,ugid_.uid,ugid_.gid);
|
||||
if(lrv < 0)
|
||||
{
|
||||
// Clean up the just-created node so a retry sees -ENOENT
|
||||
// instead of -EEXIST and userspace doesn't observe a phantom.
|
||||
fs::unlink(path_);
|
||||
return lrv;
|
||||
}
|
||||
|
||||
return rv;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -21,28 +21,20 @@
|
|||
#include "base_types.h"
|
||||
#include "errno.hpp"
|
||||
#include "fs_clonepath.hpp"
|
||||
#include "fs_close.hpp"
|
||||
#include "fs_copyfile.hpp"
|
||||
#include "fs_file_size.hpp"
|
||||
#include "fs_findonfs.hpp"
|
||||
#include "fs_getfl.hpp"
|
||||
#include "fs_has_space.hpp"
|
||||
#include "fs_mktemp.hpp"
|
||||
#include "fs_info.hpp"
|
||||
#include "fs_info_t.hpp"
|
||||
#include "fs_open.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "fs_rename.hpp"
|
||||
#include "fs_stat.hpp"
|
||||
#include "fs_unlink.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "rnd.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static
|
||||
|
|
@ -59,13 +51,61 @@ _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).
|
||||
static
|
||||
int
|
||||
_movefile_and_open(const Policy::Create &createFunc_,
|
||||
const Branches::Ptr &branches_,
|
||||
const fs::path &branchpath_,
|
||||
const fs::path &fusepath_,
|
||||
int origfd_)
|
||||
_pick_pfrd_branch(const Branches &branches_,
|
||||
Branch *&chosen_)
|
||||
{
|
||||
int err = ENOENT;
|
||||
Branches::Ptr branches = branches_;
|
||||
fs::info_t info;
|
||||
struct W { Branch *b; uint64_t weight; };
|
||||
std::vector<W> writable;
|
||||
uint64_t sum = 0;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
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; }
|
||||
|
||||
writable.push_back({&branch,info.spaceavail});
|
||||
sum += info.spaceavail;
|
||||
}
|
||||
|
||||
if(writable.empty())
|
||||
return -err;
|
||||
if(sum == 0)
|
||||
return -ENOSPC;
|
||||
|
||||
const uint64_t threshold = RND::rand64(sum);
|
||||
uint64_t idx = 0;
|
||||
for(const auto &w : writable)
|
||||
{
|
||||
if(w.weight == 0) continue;
|
||||
idx += w.weight;
|
||||
if(idx > threshold) { chosen_ = w.b; return 0; }
|
||||
}
|
||||
|
||||
chosen_ = writable.back().b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
_movefile_and_open(const Branches &branches_,
|
||||
const fs::path &branchpath_,
|
||||
const fs::path &fusepath_,
|
||||
int origfd_)
|
||||
{
|
||||
int rv;
|
||||
int dstfd_flags;
|
||||
|
|
@ -75,14 +115,14 @@ _movefile_and_open(const Policy::Create &createFunc_,
|
|||
fs::path src_branch;
|
||||
fs::path src_filepath;
|
||||
fs::path dst_filepath;
|
||||
std::vector<Branch*> dst_branch;
|
||||
Branch *dst_branch = nullptr;
|
||||
|
||||
src_branch = branchpath_;
|
||||
|
||||
rv = createFunc_(branches_,fusepath_,dst_branch);
|
||||
rv = ::_pick_pfrd_branch(branches_,dst_branch);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
if(dst_branch.empty())
|
||||
if(dst_branch == nullptr)
|
||||
return -ENOSPC;
|
||||
|
||||
origfd_flags = fs::getfl(origfd_);
|
||||
|
|
@ -93,17 +133,17 @@ _movefile_and_open(const Policy::Create &createFunc_,
|
|||
if(src_size < 0)
|
||||
return src_size;
|
||||
|
||||
if(fs::has_space(dst_branch[0]->path,src_size) == false)
|
||||
if(fs::has_space(dst_branch->path,src_size) == false)
|
||||
return -ENOSPC;
|
||||
|
||||
fusedir = fusepath_.parent_path();
|
||||
|
||||
rv = fs::clonepath(src_branch,dst_branch[0]->path,fusedir);
|
||||
rv = fs::clonepath(src_branch,dst_branch->path,fusedir);
|
||||
if(rv < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
src_filepath = src_branch / fusepath_;
|
||||
dst_filepath = dst_branch[0]->path / fusepath_;
|
||||
dst_filepath = dst_branch->path / fusepath_;
|
||||
|
||||
rv = fs::copyfile(src_filepath,dst_filepath,{.cleanup_failure = true});
|
||||
if(rv < 0)
|
||||
|
|
@ -120,29 +160,19 @@ _movefile_and_open(const Policy::Create &createFunc_,
|
|||
}
|
||||
|
||||
int
|
||||
fs::movefile_and_open(const Policy::Create &policy_,
|
||||
const Branches::Ptr &branches_,
|
||||
const fs::path &branchpath_,
|
||||
const fs::path &fusepath_,
|
||||
const int origfd_)
|
||||
fs::movefile_and_open(const Branches &branches_,
|
||||
const fs::path &branchpath_,
|
||||
const fs::path &fusepath_,
|
||||
const int origfd_)
|
||||
{
|
||||
return ::_movefile_and_open(policy_,
|
||||
branches_,
|
||||
branchpath_,
|
||||
fusepath_,
|
||||
origfd_);
|
||||
return ::_movefile_and_open(branches_,branchpath_,fusepath_,origfd_);
|
||||
}
|
||||
|
||||
int
|
||||
fs::movefile_and_open_as_root(const Policy::Create &policy_,
|
||||
const Branches::Ptr &branches_,
|
||||
const fs::path &branchpath_,
|
||||
const fs::path &fusepath_,
|
||||
const int origfd_)
|
||||
fs::movefile_and_open_as_root(const Branches &branches_,
|
||||
const fs::path &branchpath_,
|
||||
const fs::path &fusepath_,
|
||||
const int origfd_)
|
||||
{
|
||||
return fs::movefile_and_open(policy_,
|
||||
branches_,
|
||||
branchpath_,
|
||||
fusepath_,
|
||||
origfd_);
|
||||
return fs::movefile_and_open(branches_,branchpath_,fusepath_,origfd_);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,24 +20,19 @@
|
|||
|
||||
#include "branches.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "policy.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace fs
|
||||
{
|
||||
int
|
||||
movefile_and_open(const Policy::Create &policy,
|
||||
const Branches::Ptr &branches_,
|
||||
const fs::path &branchpath,
|
||||
const fs::path &fusepath,
|
||||
const int origfd);
|
||||
movefile_and_open(const Branches &branches,
|
||||
const fs::path &branchpath,
|
||||
const fs::path &fusepath,
|
||||
const int origfd);
|
||||
|
||||
int
|
||||
movefile_and_open_as_root(const Policy::Create &policy,
|
||||
const Branches::Ptr &branches_,
|
||||
const fs::path &branchpath,
|
||||
const fs::path &fusepath,
|
||||
int origfd);
|
||||
movefile_and_open_as_root(const Branches &branches,
|
||||
const fs::path &branchpath,
|
||||
const fs::path &fusepath,
|
||||
int origfd);
|
||||
}
|
||||
|
|
|
|||
0
src/fs_stat.cpp
Normal file
0
src/fs_stat.cpp
Normal file
|
|
@ -18,7 +18,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "follow_symlinks_enum.hpp"
|
||||
#include "to_neg_errno.hpp"
|
||||
#include "to_cstr.hpp"
|
||||
#include "fs_lstat.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -29,25 +32,66 @@
|
|||
|
||||
namespace fs
|
||||
{
|
||||
template<typename PathType>
|
||||
static
|
||||
inline
|
||||
int
|
||||
stat(const char *path_,
|
||||
struct stat *st_)
|
||||
stat(const PathType &path_,
|
||||
struct stat *st_)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = ::stat(path_,st_);
|
||||
rv = ::stat(to_cstr(path_),st_);
|
||||
|
||||
return ::to_neg_errno(rv);
|
||||
}
|
||||
|
||||
template<typename PathType>
|
||||
static
|
||||
inline
|
||||
int
|
||||
stat(const std::string &path_,
|
||||
struct stat *st_)
|
||||
stat(const PathType &path_,
|
||||
struct stat *st_,
|
||||
FollowSymlinksEnum follow_)
|
||||
{
|
||||
return fs::stat(path_.c_str(),st_);
|
||||
int rv;
|
||||
|
||||
switch(follow_)
|
||||
{
|
||||
default:
|
||||
case FollowSymlinksEnum::NEVER:
|
||||
rv = fs::lstat(path_,st_);
|
||||
return rv;
|
||||
case FollowSymlinksEnum::DIRECTORY:
|
||||
rv = fs::lstat(path_,st_);
|
||||
if((rv >= 0) && S_ISLNK(st_->st_mode))
|
||||
{
|
||||
struct stat st{};
|
||||
|
||||
// If the link's target lookup fails (e.g. dangling link),
|
||||
// keep the link's own lstat data so callers like ls -l can
|
||||
// still display the entry.
|
||||
if((fs::stat(path_,&st) >= 0) && S_ISDIR(st.st_mode))
|
||||
*st_ = st;
|
||||
}
|
||||
return rv;
|
||||
case FollowSymlinksEnum::REGULAR:
|
||||
rv = fs::lstat(path_,st_);
|
||||
if((rv >= 0) && S_ISLNK(st_->st_mode))
|
||||
{
|
||||
struct stat st{};
|
||||
|
||||
if((fs::stat(path_,&st) >= 0) && S_ISREG(st.st_mode))
|
||||
*st_ = st;
|
||||
}
|
||||
return rv;
|
||||
case FollowSymlinksEnum::ALL:
|
||||
rv = fs::stat(path_,st_);
|
||||
if(rv < 0)
|
||||
rv = fs::lstat(path_,st_);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "follow_symlinks_enum.hpp"
|
||||
#include "to_cstr.hpp"
|
||||
#include "to_neg_errno.hpp"
|
||||
|
||||
#include "fuse_kernel.h"
|
||||
|
|
@ -33,13 +35,15 @@
|
|||
|
||||
#include "supported_statx.hpp"
|
||||
|
||||
|
||||
namespace fs
|
||||
{
|
||||
template<typename PathType>
|
||||
static
|
||||
inline
|
||||
int
|
||||
statx(const int dirfd_,
|
||||
const char *pathname_,
|
||||
const PathType &pathname_,
|
||||
const int flags_,
|
||||
const unsigned int mask_,
|
||||
struct fuse_statx *st_)
|
||||
|
|
@ -48,7 +52,7 @@ namespace fs
|
|||
int rv;
|
||||
|
||||
rv = ::statx(dirfd_,
|
||||
pathname_,
|
||||
to_cstr(pathname_),
|
||||
flags_,
|
||||
mask_,
|
||||
(struct statx*)st_);
|
||||
|
|
@ -59,19 +63,64 @@ namespace fs
|
|||
#endif
|
||||
}
|
||||
|
||||
template<typename PathType>
|
||||
static
|
||||
inline
|
||||
int
|
||||
statx(const int dirfd_,
|
||||
const std::string &pathname_,
|
||||
const PathType &pathname_,
|
||||
const int flags_,
|
||||
const unsigned int mask_,
|
||||
struct fuse_statx *st_)
|
||||
struct fuse_statx *st_,
|
||||
FollowSymlinksEnum followsymlinks_)
|
||||
{
|
||||
return fs::statx(dirfd_,
|
||||
pathname_.c_str(),
|
||||
flags_,
|
||||
mask_,
|
||||
st_);
|
||||
int rv;
|
||||
|
||||
// statx(2) recognises AT_SYMLINK_NOFOLLOW; follow-the-link is the
|
||||
// default when that flag is absent. AT_SYMLINK_FOLLOW (a linkat(2)
|
||||
// flag) is not meaningful here and is omitted.
|
||||
const int follow_flags = (flags_ & ~AT_SYMLINK_NOFOLLOW);
|
||||
const int nofollow_flags = (flags_ | AT_SYMLINK_NOFOLLOW);
|
||||
|
||||
switch(followsymlinks_)
|
||||
{
|
||||
case FollowSymlinksEnum::NEVER:
|
||||
rv = fs::statx(dirfd_,pathname_,nofollow_flags,mask_,st_);
|
||||
return rv;
|
||||
case FollowSymlinksEnum::DIRECTORY:
|
||||
rv = fs::statx(dirfd_,pathname_,nofollow_flags,mask_,st_);
|
||||
if((rv >= 0) && S_ISLNK(st_->mode))
|
||||
{
|
||||
struct fuse_statx st{};
|
||||
|
||||
// Request the same mask as the caller: STATX_TYPE alone
|
||||
// would leave the rest of `st` unspecified and clobber the
|
||||
// caller's data when we copy back. On follow failure
|
||||
// (dangling link, etc.), keep the lstat data so callers
|
||||
// can still display the entry.
|
||||
if((fs::statx(dirfd_,pathname_,follow_flags,mask_,&st) >= 0) &&
|
||||
S_ISDIR(st.mode))
|
||||
*st_ = st;
|
||||
}
|
||||
return rv;
|
||||
case FollowSymlinksEnum::REGULAR:
|
||||
rv = fs::statx(dirfd_,pathname_,nofollow_flags,mask_,st_);
|
||||
if((rv >= 0) && S_ISLNK(st_->mode))
|
||||
{
|
||||
struct fuse_statx st{};
|
||||
|
||||
if((fs::statx(dirfd_,pathname_,follow_flags,mask_,&st) >= 0) &&
|
||||
S_ISREG(st.mode))
|
||||
*st_ = st;
|
||||
}
|
||||
return rv;
|
||||
case FollowSymlinksEnum::ALL:
|
||||
rv = fs::statx(dirfd_,pathname_,follow_flags,mask_,st_);
|
||||
if(rv < 0)
|
||||
rv = fs::statx(dirfd_,pathname_,nofollow_flags,mask_,st_);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
36
src/fsproxy.cpp
Normal file
36
src/fsproxy.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#include "fsproxy.hpp"
|
||||
|
||||
#include "fs_close.hpp"
|
||||
|
||||
int
|
||||
FSProxy::_spawn_proxy_if_needed(const uid_t uid_,
|
||||
const gid_t gid_)
|
||||
{
|
||||
int rv;
|
||||
FSProxy::Process process;
|
||||
|
||||
if(_proxies.count({uid_,gid_}))
|
||||
return 0;
|
||||
|
||||
rv = pipe(process.req_pipe);
|
||||
if(rv == -1)
|
||||
return rv;
|
||||
rv = pipe(process.res_pipe);
|
||||
if(rv == -1)
|
||||
return rv;
|
||||
|
||||
process.pid = fork();
|
||||
if(process.pid != 0)
|
||||
{
|
||||
fs::close(process.req_pipe[1]);
|
||||
fs::close(process.res_pipe[0]);
|
||||
// listen on req in loop for instructions
|
||||
return 0;
|
||||
}
|
||||
|
||||
fs::close(process.req_pipe[0]);
|
||||
fs::close(process.res_pipe[1]);
|
||||
_proxies[UGID{uid_,gid_}] = process;
|
||||
|
||||
return 0;
|
||||
}
|
||||
54
src/fsproxy.hpp
Normal file
54
src/fsproxy.hpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
class FSProxy
|
||||
{
|
||||
public:
|
||||
struct UGID
|
||||
{
|
||||
bool
|
||||
operator==(const UGID &other_) const
|
||||
{
|
||||
return ((uid == other_.uid) &&
|
||||
(gid == other_.gid));
|
||||
}
|
||||
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
struct UGIDHash
|
||||
{
|
||||
size_t
|
||||
operator()(const UGID &key_) const
|
||||
{
|
||||
size_t h0 = std::hash<uid_t>{}(key_.uid);
|
||||
size_t h1 = std::hash<uid_t>{}(key_.gid);
|
||||
|
||||
return (h0 ^ (h1 << 1));
|
||||
}
|
||||
};
|
||||
|
||||
struct Process
|
||||
{
|
||||
int pid;
|
||||
int req_pipe[2];
|
||||
int res_pipe[2];
|
||||
};
|
||||
|
||||
public:
|
||||
int create(uid_t uid,
|
||||
gid_t gid,
|
||||
const char *pathname,
|
||||
mode_t mode);
|
||||
|
||||
private:
|
||||
int _spawn_proxy_if_needed(uid_t,gid_t);
|
||||
|
||||
private:
|
||||
std::unordered_map<UGID,Process,UGIDHash> _proxies;
|
||||
};
|
||||
77
src/func.cpp
77
src/func.cpp
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2026, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "func.hpp"
|
||||
|
||||
|
||||
int
|
||||
Func::Base::Action::from_string(const std::string_view policyname_)
|
||||
{
|
||||
auto *tmp = Policies::Action::find(policyname_);
|
||||
|
||||
if(not tmp)
|
||||
return -EINVAL;
|
||||
|
||||
policy = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
Func::Base::Action::to_string(void) const
|
||||
{
|
||||
return policy.name();
|
||||
}
|
||||
|
||||
int
|
||||
Func::Base::Create::from_string(const std::string_view policyname_)
|
||||
{
|
||||
auto *tmp = Policies::Create::find(policyname_);
|
||||
|
||||
if(not tmp)
|
||||
return -EINVAL;
|
||||
|
||||
policy = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
Func::Base::Create::to_string(void) const
|
||||
{
|
||||
return policy.name();
|
||||
}
|
||||
|
||||
int
|
||||
Func::Base::Search::from_string(const std::string_view policyname_)
|
||||
{
|
||||
auto *tmp = Policies::Search::find(policyname_);
|
||||
|
||||
if(not tmp)
|
||||
return -EINVAL;
|
||||
|
||||
policy = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
Func::Base::Search::to_string(void) const
|
||||
{
|
||||
return policy.name();
|
||||
}
|
||||
184
src/func.hpp
184
src/func.hpp
|
|
@ -1,184 +0,0 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2026, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "policy.hpp"
|
||||
#include "policies.hpp"
|
||||
#include "tofrom_string.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace Func
|
||||
{
|
||||
namespace Base
|
||||
{
|
||||
class Action : public ToFromString
|
||||
{
|
||||
public:
|
||||
Action(Policy::ActionImpl *policy_)
|
||||
: policy(policy_)
|
||||
{}
|
||||
|
||||
public:
|
||||
int from_string(const std::string_view s) final;
|
||||
std::string to_string() const final;
|
||||
|
||||
public:
|
||||
Policy::Action policy;
|
||||
};
|
||||
|
||||
class Create : public ToFromString
|
||||
{
|
||||
public:
|
||||
Create(Policy::CreateImpl *policy_)
|
||||
: policy(policy_)
|
||||
{}
|
||||
|
||||
public:
|
||||
int from_string(const std::string_view s) final;
|
||||
std::string to_string() const final;
|
||||
|
||||
public:
|
||||
Policy::Create policy;
|
||||
};
|
||||
|
||||
class Search : public ToFromString
|
||||
{
|
||||
public:
|
||||
Search(Policy::SearchImpl *policy_)
|
||||
: policy(policy_)
|
||||
{}
|
||||
|
||||
public:
|
||||
int from_string(const std::string_view s) final;
|
||||
std::string to_string() const final;
|
||||
|
||||
public:
|
||||
Policy::Search policy;
|
||||
};
|
||||
|
||||
class ActionDefault : public Action
|
||||
{
|
||||
public:
|
||||
ActionDefault()
|
||||
: Func::Base::Action(&Policies::Action::epall)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CreateDefault : public Create
|
||||
{
|
||||
public:
|
||||
CreateDefault()
|
||||
: Func::Base::Create(&Policies::Create::pfrd)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class SearchDefault : public Search
|
||||
{
|
||||
public:
|
||||
SearchDefault()
|
||||
: Func::Base::Search(&Policies::Search::ff)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class Access final : public Base::SearchDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Chmod final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Chown final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Create final : public Base::CreateDefault
|
||||
{
|
||||
};
|
||||
|
||||
class GetAttr final : public Base::SearchDefault
|
||||
{
|
||||
};
|
||||
|
||||
class GetXAttr final : public Base::SearchDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Link final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
|
||||
class ListXAttr final : public Base::SearchDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Mkdir final : public Base::CreateDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Mknod final : public Base::CreateDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Open final : public Base::SearchDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Readlink final : public Base::SearchDefault
|
||||
{
|
||||
};
|
||||
|
||||
class RemoveXAttr final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Rename final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Rmdir final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
|
||||
class SetXAttr final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Symlink final : public Base::CreateDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Truncate final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Unlink final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
|
||||
class Utimens final : public Base::ActionDefault
|
||||
{
|
||||
};
|
||||
}
|
||||
16
src/func_access.hpp
Normal file
16
src/func_access.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_access_base.hpp"
|
||||
#include "func_access_factory.hpp"
|
||||
|
||||
#include "func_wrapper.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
using Access = FuncWrapper<Func2::AccessBase,
|
||||
Func2::AccessFactory,
|
||||
int,
|
||||
const Branches&,
|
||||
const fs::path&,
|
||||
const int&>;
|
||||
}
|
||||
26
src/func_access_all.cpp
Normal file
26
src/func_access_all.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "func_access_all.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fs_eaccess.hpp"
|
||||
|
||||
std::string_view Func2::AccessAll::name() const { return "all"; }
|
||||
|
||||
// "all": every branch must satisfy eaccess (including the file existing
|
||||
// there). Returns the first failure.
|
||||
int
|
||||
Func2::AccessAll::operator()(const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
const int mode_)
|
||||
{
|
||||
bool any = false;
|
||||
for(const auto &branch : branches_)
|
||||
{
|
||||
any = true;
|
||||
const fs::path fullpath = branch.path / fusepath_;
|
||||
const int rv = fs::eaccess(fullpath,mode_);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
}
|
||||
if(!any)
|
||||
return -ENOENT;
|
||||
return 0;
|
||||
}
|
||||
10
src/func_access_all.hpp
Normal file
10
src/func_access_all.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include "func_access_base.hpp"
|
||||
namespace Func2 {
|
||||
class AccessAll : public AccessBase {
|
||||
public:
|
||||
AccessAll() {}
|
||||
std::string_view name() const;
|
||||
int operator()(const Branches&,const fs::path&,const int);
|
||||
};
|
||||
}
|
||||
24
src/func_access_base.hpp
Normal file
24
src/func_access_base.hpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "branches.hpp"
|
||||
|
||||
#include "fs_path.hpp"
|
||||
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class AccessBase
|
||||
{
|
||||
public:
|
||||
AccessBase() {}
|
||||
~AccessBase() {}
|
||||
|
||||
public:
|
||||
virtual std::string_view name() const = 0;
|
||||
|
||||
public:
|
||||
virtual int operator()(const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
const int mode) = 0;
|
||||
};
|
||||
}
|
||||
26
src/func_access_epall.cpp
Normal file
26
src/func_access_epall.cpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include "func_access_epall.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fs_eaccess.hpp"
|
||||
|
||||
std::string_view Func2::AccessEPAll::name() const { return "epall"; }
|
||||
|
||||
int
|
||||
Func2::AccessEPAll::operator()(const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
const int mode_)
|
||||
{
|
||||
bool found = false;
|
||||
for(const auto &branch : branches_)
|
||||
{
|
||||
const fs::path fullpath = branch.path / fusepath_;
|
||||
const int rv = fs::eaccess(fullpath,mode_);
|
||||
if(rv == -ENOENT)
|
||||
continue;
|
||||
found = true;
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
}
|
||||
if(!found)
|
||||
return -ENOENT;
|
||||
return 0;
|
||||
}
|
||||
10
src/func_access_epall.hpp
Normal file
10
src/func_access_epall.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include "func_access_base.hpp"
|
||||
namespace Func2 {
|
||||
class AccessEPAll : public AccessBase {
|
||||
public:
|
||||
AccessEPAll() {}
|
||||
std::string_view name() const;
|
||||
int operator()(const Branches&,const fs::path&,const int);
|
||||
};
|
||||
}
|
||||
12
src/func_access_erofs.cpp
Normal file
12
src/func_access_erofs.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#include "func_access_erofs.hpp"
|
||||
#include "errno.hpp"
|
||||
|
||||
std::string_view Func2::AccessEROFS::name() const { return "erofs"; }
|
||||
|
||||
int
|
||||
Func2::AccessEROFS::operator()(const Branches&,
|
||||
const fs::path&,
|
||||
const int)
|
||||
{
|
||||
return -EROFS;
|
||||
}
|
||||
10
src/func_access_erofs.hpp
Normal file
10
src/func_access_erofs.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include "func_access_base.hpp"
|
||||
namespace Func2 {
|
||||
class AccessEROFS : public AccessBase {
|
||||
public:
|
||||
AccessEROFS() {}
|
||||
std::string_view name() const;
|
||||
int operator()(const Branches&,const fs::path&,const int);
|
||||
};
|
||||
}
|
||||
24
src/func_access_factory.cpp
Normal file
24
src/func_access_factory.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#include "func_access_factory.hpp"
|
||||
|
||||
#include "func_access_all.hpp"
|
||||
#include "func_access_epall.hpp"
|
||||
#include "func_access_erofs.hpp"
|
||||
#include "func_access_ff.hpp"
|
||||
|
||||
|
||||
bool
|
||||
Func2::AccessFactory::valid(const std::string str_)
|
||||
{
|
||||
return (bool)make(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>();
|
||||
|
||||
return {};
|
||||
}
|
||||
13
src/func_access_factory.hpp
Normal file
13
src/func_access_factory.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_access_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class AccessFactory
|
||||
{
|
||||
public:
|
||||
static bool valid(const std::string str);
|
||||
static std::shared_ptr<AccessBase> make(const std::string_view str);
|
||||
};
|
||||
}
|
||||
32
src/func_access_ff.cpp
Normal file
32
src/func_access_ff.cpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#include "func_access_ff.hpp"
|
||||
|
||||
#include "errno.hpp"
|
||||
#include "fs_eaccess.hpp"
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::AccessFF::name() const
|
||||
{
|
||||
return "ff";
|
||||
}
|
||||
|
||||
int
|
||||
Func2::AccessFF::operator()(const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
const int mode_)
|
||||
{
|
||||
fs::path fullpath;
|
||||
|
||||
for(const auto &branch : branches_)
|
||||
{
|
||||
fullpath = branch.path / fusepath_;
|
||||
|
||||
const int rv = fs::eaccess(fullpath,mode_);
|
||||
if(rv == -ENOENT)
|
||||
continue;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
21
src/func_access_ff.hpp
Normal file
21
src/func_access_ff.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_access_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class AccessFF : public AccessBase
|
||||
{
|
||||
public:
|
||||
AccessFF() {}
|
||||
~AccessFF() {}
|
||||
|
||||
public:
|
||||
std::string_view name() const;
|
||||
|
||||
public:
|
||||
int operator()(const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
const int mode);
|
||||
};
|
||||
}
|
||||
17
src/func_chmod.hpp
Normal file
17
src/func_chmod.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_chmod_base.hpp"
|
||||
#include "func_chmod_factory.hpp"
|
||||
|
||||
#include "func_wrapper.hpp"
|
||||
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
using Chmod = FuncWrapper<Func2::ChmodBase,
|
||||
Func2::ChmodFactory,
|
||||
int,
|
||||
const Branches&,
|
||||
const fs::path&,
|
||||
const mode_t&>;
|
||||
}
|
||||
42
src/func_chmod_all.cpp
Normal file
42
src/func_chmod_all.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#include "func_chmod_all.hpp"
|
||||
|
||||
#include "errno.hpp"
|
||||
#include "fs_lchmod.hpp"
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::ChmodAll::name() const
|
||||
{
|
||||
return "all";
|
||||
}
|
||||
|
||||
int
|
||||
Func2::ChmodAll::operator()(const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
const mode_t mode_)
|
||||
{
|
||||
int err;
|
||||
bool found;
|
||||
fs::path fullpath;
|
||||
|
||||
err = 0;
|
||||
found = false;
|
||||
for(const auto &branch : branches_)
|
||||
{
|
||||
if(branch.ro())
|
||||
continue;
|
||||
fullpath = branch.path / fusepath_;
|
||||
|
||||
const int rv = fs::lchmod(fullpath,mode_);
|
||||
if(rv == -ENOENT)
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
err = rv;
|
||||
}
|
||||
|
||||
if(!found)
|
||||
return -ENOENT;
|
||||
|
||||
return err;
|
||||
}
|
||||
21
src/func_chmod_all.hpp
Normal file
21
src/func_chmod_all.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_chmod_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class ChmodAll : public ChmodBase
|
||||
{
|
||||
public:
|
||||
ChmodAll() {}
|
||||
~ChmodAll() {}
|
||||
|
||||
public:
|
||||
std::string_view name() const;
|
||||
|
||||
public:
|
||||
int operator()(const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
const mode_t mode);
|
||||
};
|
||||
}
|
||||
26
src/func_chmod_base.hpp
Normal file
26
src/func_chmod_base.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "branches.hpp"
|
||||
|
||||
#include "fs_path.hpp"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class ChmodBase
|
||||
{
|
||||
public:
|
||||
ChmodBase() {}
|
||||
~ChmodBase() {}
|
||||
|
||||
public:
|
||||
virtual std::string_view name() const = 0;
|
||||
|
||||
public:
|
||||
virtual int operator()(const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
const mode_t mode) = 0;
|
||||
};
|
||||
}
|
||||
10
src/func_chmod_erofs.cpp
Normal file
10
src/func_chmod_erofs.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "func_chmod_erofs.hpp"
|
||||
#include "errno.hpp"
|
||||
|
||||
std::string_view Func2::ChmodEROFS::name() const { return "erofs"; }
|
||||
|
||||
int
|
||||
Func2::ChmodEROFS::operator()(const Branches&,const fs::path&,const mode_t)
|
||||
{
|
||||
return -EROFS;
|
||||
}
|
||||
10
src/func_chmod_erofs.hpp
Normal file
10
src/func_chmod_erofs.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include "func_chmod_base.hpp"
|
||||
namespace Func2 {
|
||||
class ChmodEROFS : public ChmodBase {
|
||||
public:
|
||||
ChmodEROFS() {}
|
||||
std::string_view name() const;
|
||||
int operator()(const Branches&,const fs::path&,const mode_t);
|
||||
};
|
||||
}
|
||||
20
src/func_chmod_factory.cpp
Normal file
20
src/func_chmod_factory.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "func_chmod_factory.hpp"
|
||||
|
||||
#include "func_chmod_all.hpp"
|
||||
#include "func_chmod_erofs.hpp"
|
||||
|
||||
|
||||
bool
|
||||
Func2::ChmodFactory::valid(const std::string str_)
|
||||
{
|
||||
return (bool)make(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>();
|
||||
|
||||
return {};
|
||||
}
|
||||
13
src/func_chmod_factory.hpp
Normal file
13
src/func_chmod_factory.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_chmod_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class ChmodFactory
|
||||
{
|
||||
public:
|
||||
static bool valid(const std::string str);
|
||||
static std::shared_ptr<ChmodBase> make(const std::string_view str);
|
||||
};
|
||||
}
|
||||
18
src/func_chown.hpp
Normal file
18
src/func_chown.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_chown_base.hpp"
|
||||
#include "func_chown_factory.hpp"
|
||||
|
||||
#include "func_wrapper.hpp"
|
||||
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
using Chown = FuncWrapper<Func2::ChownBase,
|
||||
Func2::ChownFactory,
|
||||
int,
|
||||
const Branches&,
|
||||
const fs::path&,
|
||||
const uid_t&,
|
||||
const gid_t&>;
|
||||
}
|
||||
43
src/func_chown_all.cpp
Normal file
43
src/func_chown_all.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#include "func_chown_all.hpp"
|
||||
|
||||
#include "errno.hpp"
|
||||
#include "fs_lchown.hpp"
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::ChownAll::name() const
|
||||
{
|
||||
return "all";
|
||||
}
|
||||
|
||||
int
|
||||
Func2::ChownAll::operator()(const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
const uid_t uid_,
|
||||
const gid_t gid_)
|
||||
{
|
||||
int err;
|
||||
bool found;
|
||||
fs::path fullpath;
|
||||
|
||||
err = 0;
|
||||
found = false;
|
||||
for(const auto &branch : branches_)
|
||||
{
|
||||
if(branch.ro())
|
||||
continue;
|
||||
fullpath = branch.path / fusepath_;
|
||||
|
||||
const int rv = fs::lchown(fullpath,uid_,gid_);
|
||||
if(rv == -ENOENT)
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
err = rv;
|
||||
}
|
||||
|
||||
if(!found)
|
||||
return -ENOENT;
|
||||
|
||||
return err;
|
||||
}
|
||||
22
src/func_chown_all.hpp
Normal file
22
src/func_chown_all.hpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_chown_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class ChownAll : public ChownBase
|
||||
{
|
||||
public:
|
||||
ChownAll() {}
|
||||
~ChownAll() {}
|
||||
|
||||
public:
|
||||
std::string_view name() const;
|
||||
|
||||
public:
|
||||
int operator()(const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
const uid_t uid,
|
||||
const gid_t gid);
|
||||
};
|
||||
}
|
||||
27
src/func_chown_base.hpp
Normal file
27
src/func_chown_base.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include "branches.hpp"
|
||||
|
||||
#include "fs_path.hpp"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class ChownBase
|
||||
{
|
||||
public:
|
||||
ChownBase() {}
|
||||
~ChownBase() {}
|
||||
|
||||
public:
|
||||
virtual std::string_view name() const = 0;
|
||||
|
||||
public:
|
||||
virtual int operator()(const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
const uid_t uid,
|
||||
const gid_t gid) = 0;
|
||||
};
|
||||
}
|
||||
10
src/func_chown_erofs.cpp
Normal file
10
src/func_chown_erofs.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "func_chown_erofs.hpp"
|
||||
#include "errno.hpp"
|
||||
|
||||
std::string_view Func2::ChownEROFS::name() const { return "erofs"; }
|
||||
|
||||
int
|
||||
Func2::ChownEROFS::operator()(const Branches&,const fs::path&,const uid_t,const gid_t)
|
||||
{
|
||||
return -EROFS;
|
||||
}
|
||||
10
src/func_chown_erofs.hpp
Normal file
10
src/func_chown_erofs.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include "func_chown_base.hpp"
|
||||
namespace Func2 {
|
||||
class ChownEROFS : public ChownBase {
|
||||
public:
|
||||
ChownEROFS() {}
|
||||
std::string_view name() const;
|
||||
int operator()(const Branches&,const fs::path&,const uid_t,const gid_t);
|
||||
};
|
||||
}
|
||||
20
src/func_chown_factory.cpp
Normal file
20
src/func_chown_factory.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "func_chown_factory.hpp"
|
||||
|
||||
#include "func_chown_all.hpp"
|
||||
#include "func_chown_erofs.hpp"
|
||||
|
||||
|
||||
bool
|
||||
Func2::ChownFactory::valid(const std::string str_)
|
||||
{
|
||||
return (bool)make(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>();
|
||||
|
||||
return {};
|
||||
}
|
||||
13
src/func_chown_factory.hpp
Normal file
13
src/func_chown_factory.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_chown_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class ChownFactory
|
||||
{
|
||||
public:
|
||||
static bool valid(const std::string str);
|
||||
static std::shared_ptr<ChownBase> make(const std::string_view str);
|
||||
};
|
||||
}
|
||||
20
src/func_create.hpp
Normal file
20
src/func_create.hpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
#include "func_create_factory.hpp"
|
||||
|
||||
#include "func_wrapper.hpp"
|
||||
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
using Create = FuncWrapper<Func2::CreateBase,
|
||||
Func2::CreateFactory,
|
||||
int,
|
||||
const ugid_t&,
|
||||
const Branches&,
|
||||
const fs::path&,
|
||||
fuse_file_info_t*&,
|
||||
const mode_t&,
|
||||
const mode_t&>;
|
||||
}
|
||||
131
src/func_create_all.cpp
Normal file
131
src/func_create_all.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#include "func_create_all.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateAll::name() const
|
||||
{
|
||||
return "all";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateAll::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateAll::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
const Branch *clone_src;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
clone_src = nullptr;
|
||||
error = ENOENT;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
chosen = &branch;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
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_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
25
src/func_create_all.hpp
Normal file
25
src/func_create_all.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateAll : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateAll() {}
|
||||
~CreateAll() {}
|
||||
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
30
src/func_create_base.hpp
Normal file
30
src/func_create_base.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "branches.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include "fuse.h"
|
||||
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateBase
|
||||
{
|
||||
public:
|
||||
CreateBase() {}
|
||||
~CreateBase() {}
|
||||
|
||||
public:
|
||||
virtual std::string_view name() const = 0;
|
||||
virtual bool path_preserving() const = 0;
|
||||
|
||||
public:
|
||||
virtual int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask) = 0;
|
||||
};
|
||||
}
|
||||
113
src/func_create_epall.cpp
Normal file
113
src/func_create_epall.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#include "func_create_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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateEPALL::name() const
|
||||
{
|
||||
return "epall";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateEPALL::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateEPALL::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,fusepath_.parent_path()))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
chosen = &branch;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
return -error;
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_epall.hpp
Normal file
23
src/func_create_epall.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateEPALL : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateEPALL() {}
|
||||
~CreateEPALL() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
113
src/func_create_epff.cpp
Normal file
113
src/func_create_epff.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#include "func_create_epff.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateEPFF::name() const
|
||||
{
|
||||
return "epff";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateEPFF::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateEPFF::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,fusepath_.parent_path()))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
chosen = &branch;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
return -error;
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_epff.hpp
Normal file
23
src/func_create_epff.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateEPFF : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateEPFF() {}
|
||||
~CreateEPFF() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
119
src/func_create_eplfs.cpp
Normal file
119
src/func_create_eplfs.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#include "func_create_eplfs.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include <limits>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateEPLFS::name() const
|
||||
{
|
||||
return "eplfs";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateEPLFS::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateEPLFS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
u64 lfs;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
lfs = std::numeric_limits<u64>::max();
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,fusepath_.parent_path()))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
if(info.spaceavail > lfs)
|
||||
continue;
|
||||
|
||||
lfs = info.spaceavail;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
return -error;
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_eplfs.hpp
Normal file
23
src/func_create_eplfs.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateEPLFS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateEPLFS() {}
|
||||
~CreateEPLFS() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
119
src/func_create_eplus.cpp
Normal file
119
src/func_create_eplus.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#include "func_create_eplus.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include <limits>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateEPLUS::name() const
|
||||
{
|
||||
return "eplus";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateEPLUS::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateEPLUS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
u64 lus;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
lus = std::numeric_limits<u64>::max();
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,fusepath_.parent_path()))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
if(info.spaceused > lus)
|
||||
continue;
|
||||
|
||||
lus = info.spaceused;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
return -error;
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_eplus.hpp
Normal file
23
src/func_create_eplus.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateEPLUS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateEPLUS() {}
|
||||
~CreateEPLUS() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
118
src/func_create_epmfs.cpp
Normal file
118
src/func_create_epmfs.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#include "func_create_epmfs.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateEPMFS::name() const
|
||||
{
|
||||
return "epmfs";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateEPMFS::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateEPMFS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
u64 mfs;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
mfs = 0;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,fusepath_.parent_path()))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
if(info.spaceavail < mfs)
|
||||
continue;
|
||||
|
||||
mfs = info.spaceavail;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
return -error;
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_epmfs.hpp
Normal file
23
src/func_create_epmfs.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateEPMFS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateEPMFS() {}
|
||||
~CreateEPMFS() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
141
src/func_create_eppfrd.cpp
Normal file
141
src/func_create_eppfrd.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#include "func_create_eppfrd.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include "rnd.hpp"
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateEPPFRD::name() const
|
||||
{
|
||||
return "eppfrd";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateEPPFRD::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateEPPFRD::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
u64 sum;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
struct W { Branch *b; u64 weight; };
|
||||
std::vector<W> writable;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
sum = 0;
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,fusepath_.parent_path()))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
writable.push_back({&branch,info.spaceavail});
|
||||
sum += info.spaceavail;
|
||||
}
|
||||
|
||||
if(writable.empty())
|
||||
return -error;
|
||||
if(sum == 0)
|
||||
return -ENOSPC;
|
||||
|
||||
{
|
||||
u64 idx;
|
||||
u64 threshold;
|
||||
|
||||
idx = 0;
|
||||
threshold = RND::rand64(sum);
|
||||
for(const auto &w : writable)
|
||||
{
|
||||
if(w.weight == 0)
|
||||
continue;
|
||||
idx += w.weight;
|
||||
if(idx > threshold)
|
||||
{
|
||||
chosen = w.b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!chosen)
|
||||
chosen = writable.back().b;
|
||||
}
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_eppfrd.hpp
Normal file
23
src/func_create_eppfrd.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateEPPFRD : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateEPPFRD() {}
|
||||
~CreateEPPFRD() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
116
src/func_create_eprand.cpp
Normal file
116
src/func_create_eprand.cpp
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
#include "func_create_eprand.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include "rnd.hpp"
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateEPRAND::name() const
|
||||
{
|
||||
return "eprand";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateEPRAND::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateEPRAND::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
std::vector<Branch*> writable;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,fusepath_.parent_path()))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
writable.push_back(&branch);
|
||||
}
|
||||
|
||||
if(writable.empty())
|
||||
return -error;
|
||||
|
||||
chosen = writable[RND::rand64(writable.size())];
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_eprand.hpp
Normal file
23
src/func_create_eprand.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateEPRAND : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateEPRAND() {}
|
||||
~CreateEPRAND() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
35
src/func_create_erofs.cpp
Normal file
35
src/func_create_erofs.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include "func_create_erofs.hpp"
|
||||
|
||||
#include "errno.hpp"
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateEROFS::name() const
|
||||
{
|
||||
return "erofs";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateEROFS::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateEROFS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
(void)ugid_;
|
||||
(void)branches_;
|
||||
(void)fusepath_;
|
||||
(void)ffi_;
|
||||
(void)mode_;
|
||||
(void)umask_;
|
||||
|
||||
return -EROFS;
|
||||
}
|
||||
25
src/func_create_erofs.hpp
Normal file
25
src/func_create_erofs.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateEROFS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateEROFS() {}
|
||||
~CreateEROFS() {}
|
||||
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
58
src/func_create_factory.cpp
Normal file
58
src/func_create_factory.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#include "func_create_factory.hpp"
|
||||
|
||||
#include "func_create_all.hpp"
|
||||
#include "func_create_epall.hpp"
|
||||
#include "func_create_epff.hpp"
|
||||
#include "func_create_eplfs.hpp"
|
||||
#include "func_create_eplus.hpp"
|
||||
#include "func_create_epmfs.hpp"
|
||||
#include "func_create_eppfrd.hpp"
|
||||
#include "func_create_eprand.hpp"
|
||||
#include "func_create_erofs.hpp"
|
||||
#include "func_create_ff.hpp"
|
||||
#include "func_create_lfs.hpp"
|
||||
#include "func_create_lup.hpp"
|
||||
#include "func_create_lus.hpp"
|
||||
#include "func_create_mfs.hpp"
|
||||
#include "func_create_msplfs.hpp"
|
||||
#include "func_create_msplus.hpp"
|
||||
#include "func_create_mspmfs.hpp"
|
||||
#include "func_create_msppfrd.hpp"
|
||||
#include "func_create_newest.hpp"
|
||||
#include "func_create_pfrd.hpp"
|
||||
#include "func_create_rand.hpp"
|
||||
|
||||
|
||||
bool
|
||||
Func2::CreateFactory::valid(const std::string str_)
|
||||
{
|
||||
return (bool)make(str_);
|
||||
}
|
||||
|
||||
std::shared_ptr<Func2::CreateBase>
|
||||
Func2::CreateFactory::make(const std::string_view str_)
|
||||
{
|
||||
if(str_ == "all") return std::make_shared<Func2::CreateAll>();
|
||||
if(str_ == "epall") return std::make_shared<Func2::CreateEPALL>();
|
||||
if(str_ == "epff") return std::make_shared<Func2::CreateEPFF>();
|
||||
if(str_ == "eplfs") return std::make_shared<Func2::CreateEPLFS>();
|
||||
if(str_ == "eplus") return std::make_shared<Func2::CreateEPLUS>();
|
||||
if(str_ == "epmfs") return std::make_shared<Func2::CreateEPMFS>();
|
||||
if(str_ == "eppfrd") return std::make_shared<Func2::CreateEPPFRD>();
|
||||
if(str_ == "eprand") return std::make_shared<Func2::CreateEPRAND>();
|
||||
if(str_ == "erofs") return std::make_shared<Func2::CreateEROFS>();
|
||||
if(str_ == "ff") return std::make_shared<Func2::CreateFF>();
|
||||
if(str_ == "lfs") return std::make_shared<Func2::CreateLFS>();
|
||||
if(str_ == "lup") return std::make_shared<Func2::CreateLUP>();
|
||||
if(str_ == "lus") return std::make_shared<Func2::CreateLUS>();
|
||||
if(str_ == "mfs") return std::make_shared<Func2::CreateMFS>();
|
||||
if(str_ == "msplfs") return std::make_shared<Func2::CreateMSPLFS>();
|
||||
if(str_ == "msplus") return std::make_shared<Func2::CreateMSPLUS>();
|
||||
if(str_ == "mspmfs") return std::make_shared<Func2::CreateMSPMFS>();
|
||||
if(str_ == "msppfrd") return std::make_shared<Func2::CreateMSPPFRD>();
|
||||
if(str_ == "newest") return std::make_shared<Func2::CreateNewest>();
|
||||
if(str_ == "pfrd") return std::make_shared<Func2::CreatePFRD>();
|
||||
if(str_ == "rand") return std::make_shared<Func2::CreateRAND>();
|
||||
|
||||
return {};
|
||||
}
|
||||
17
src/func_create_factory.hpp
Normal file
17
src/func_create_factory.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateBase;
|
||||
|
||||
class CreateFactory
|
||||
{
|
||||
public:
|
||||
static bool valid(const std::string str_);
|
||||
|
||||
static std::shared_ptr<CreateBase> make(const std::string_view str_);
|
||||
};
|
||||
}
|
||||
131
src/func_create_ff.cpp
Normal file
131
src/func_create_ff.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#include "func_create_ff.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateFF::name() const
|
||||
{
|
||||
return "ff";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateFF::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateFF::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
const Branch *clone_src;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
clone_src = nullptr;
|
||||
error = ENOENT;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
chosen = &branch;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
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_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
25
src/func_create_ff.hpp
Normal file
25
src/func_create_ff.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateFF : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateFF() {}
|
||||
~CreateFF() {}
|
||||
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
137
src/func_create_lfs.cpp
Normal file
137
src/func_create_lfs.cpp
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#include "func_create_lfs.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include <limits>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateLFS::name() const
|
||||
{
|
||||
return "lfs";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateLFS::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateLFS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
const Branch *clone_src;
|
||||
u64 lfs;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
clone_src = nullptr;
|
||||
error = ENOENT;
|
||||
lfs = std::numeric_limits<u64>::max();
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
if(info.spaceavail > lfs)
|
||||
continue;
|
||||
|
||||
lfs = info.spaceavail;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
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_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_lfs.hpp
Normal file
23
src/func_create_lfs.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateLFS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateLFS() {}
|
||||
~CreateLFS() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
145
src/func_create_lup.cpp
Normal file
145
src/func_create_lup.cpp
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#include "func_create_lup.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateLUP::name() const
|
||||
{
|
||||
return "lup";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateLUP::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateLUP::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
const Branch *clone_src;
|
||||
long double best_ratio;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
clone_src = nullptr;
|
||||
error = ENOENT;
|
||||
best_ratio = 2.0L;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
{
|
||||
u64 used = info.spaceused;
|
||||
u64 total = info.spaceused + info.spaceavail;
|
||||
long double ratio;
|
||||
|
||||
if(total == 0)
|
||||
{ used = 0; total = 1; }
|
||||
ratio = (long double)used / (long double)total;
|
||||
if(ratio >= best_ratio)
|
||||
continue;
|
||||
|
||||
best_ratio = ratio;
|
||||
chosen = &branch;
|
||||
}
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
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_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_lup.hpp
Normal file
23
src/func_create_lup.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateLUP : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateLUP() {}
|
||||
~CreateLUP() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
137
src/func_create_lus.cpp
Normal file
137
src/func_create_lus.cpp
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
#include "func_create_lus.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include <limits>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateLUS::name() const
|
||||
{
|
||||
return "lus";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateLUS::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateLUS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
const Branch *clone_src;
|
||||
u64 lus;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
clone_src = nullptr;
|
||||
error = ENOENT;
|
||||
lus = std::numeric_limits<u64>::max();
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
if(info.spaceused > lus)
|
||||
continue;
|
||||
|
||||
lus = info.spaceused;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
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_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_lus.hpp
Normal file
23
src/func_create_lus.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateLUS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateLUS() {}
|
||||
~CreateLUS() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
136
src/func_create_mfs.cpp
Normal file
136
src/func_create_mfs.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
#include "func_create_mfs.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateMFS::name() const
|
||||
{
|
||||
return "mfs";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateMFS::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateMFS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
const Branch *clone_src;
|
||||
u64 mfs;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
clone_src = nullptr;
|
||||
error = ENOENT;
|
||||
mfs = 0;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
if(info.spaceavail < mfs)
|
||||
continue;
|
||||
|
||||
mfs = info.spaceavail;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
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_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_mfs.hpp
Normal file
23
src/func_create_mfs.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateMFS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateMFS() {}
|
||||
~CreateMFS() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
172
src/func_create_msplfs.cpp
Normal file
172
src/func_create_msplfs.cpp
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
#include "func_create_msplfs.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include "fs_mkdir_as.hpp"
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateMSPLFS::name() const
|
||||
{
|
||||
return "msplfs";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateMSPLFS::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateMSPLFS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
fs::path walk;
|
||||
std::vector<fs::path> segments;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
mode_t dirmode;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
walk = fusepath_.parent_path();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
bool any;
|
||||
u64 lfs;
|
||||
|
||||
any = false;
|
||||
lfs = std::numeric_limits<u64>::max();
|
||||
chosen = nullptr;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,walk))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
any = true;
|
||||
if(info.spaceavail > lfs)
|
||||
continue;
|
||||
lfs = info.spaceavail;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(any)
|
||||
break;
|
||||
if(walk == "/")
|
||||
break;
|
||||
walk = walk.parent_path();
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
return -error;
|
||||
|
||||
for(fs::path p = fusepath_.parent_path();
|
||||
!p.empty() && p != "/";
|
||||
p = p.parent_path())
|
||||
segments.push_back(p);
|
||||
|
||||
dirmode = (0777 & ~umask_);
|
||||
for(auto it = segments.rbegin(); it != segments.rend(); ++it)
|
||||
{
|
||||
const Branch *src;
|
||||
const fs::path full = chosen->path / *it;
|
||||
|
||||
if(fs::exists(full))
|
||||
continue;
|
||||
|
||||
src = nullptr;
|
||||
for(auto &b : *branches)
|
||||
{
|
||||
if(&b == chosen)
|
||||
continue;
|
||||
if(!fs::exists(b.path,*it))
|
||||
continue;
|
||||
src = &b;
|
||||
break;
|
||||
}
|
||||
|
||||
if(src != nullptr)
|
||||
rv = fs::clonepath(src->path,chosen->path,*it);
|
||||
else
|
||||
rv = fs::mkdir_as(ugid_,full,dirmode);
|
||||
if((rv < 0) && (rv != -EEXIST))
|
||||
return rv;
|
||||
}
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_msplfs.hpp
Normal file
23
src/func_create_msplfs.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateMSPLFS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateMSPLFS() {}
|
||||
~CreateMSPLFS() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
172
src/func_create_msplus.cpp
Normal file
172
src/func_create_msplus.cpp
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
#include "func_create_msplus.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include "fs_mkdir_as.hpp"
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateMSPLUS::name() const
|
||||
{
|
||||
return "msplus";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateMSPLUS::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateMSPLUS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
fs::path walk;
|
||||
std::vector<fs::path> segments;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
mode_t dirmode;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
walk = fusepath_.parent_path();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
bool any;
|
||||
u64 lus;
|
||||
|
||||
any = false;
|
||||
lus = std::numeric_limits<u64>::max();
|
||||
chosen = nullptr;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,walk))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
any = true;
|
||||
if(info.spaceused > lus)
|
||||
continue;
|
||||
lus = info.spaceused;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(any)
|
||||
break;
|
||||
if(walk == "/")
|
||||
break;
|
||||
walk = walk.parent_path();
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
return -error;
|
||||
|
||||
for(fs::path p = fusepath_.parent_path();
|
||||
!p.empty() && p != "/";
|
||||
p = p.parent_path())
|
||||
segments.push_back(p);
|
||||
|
||||
dirmode = (0777 & ~umask_);
|
||||
for(auto it = segments.rbegin(); it != segments.rend(); ++it)
|
||||
{
|
||||
const Branch *src;
|
||||
const fs::path full = chosen->path / *it;
|
||||
|
||||
if(fs::exists(full))
|
||||
continue;
|
||||
|
||||
src = nullptr;
|
||||
for(auto &b : *branches)
|
||||
{
|
||||
if(&b == chosen)
|
||||
continue;
|
||||
if(!fs::exists(b.path,*it))
|
||||
continue;
|
||||
src = &b;
|
||||
break;
|
||||
}
|
||||
|
||||
if(src != nullptr)
|
||||
rv = fs::clonepath(src->path,chosen->path,*it);
|
||||
else
|
||||
rv = fs::mkdir_as(ugid_,full,dirmode);
|
||||
if((rv < 0) && (rv != -EEXIST))
|
||||
return rv;
|
||||
}
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_msplus.hpp
Normal file
23
src/func_create_msplus.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateMSPLUS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateMSPLUS() {}
|
||||
~CreateMSPLUS() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
172
src/func_create_mspmfs.cpp
Normal file
172
src/func_create_mspmfs.cpp
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
#include "func_create_mspmfs.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include "fs_mkdir_as.hpp"
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateMSPMFS::name() const
|
||||
{
|
||||
return "mspmfs";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateMSPMFS::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateMSPMFS::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
fs::path walk;
|
||||
std::vector<fs::path> segments;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
mode_t dirmode;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
walk = fusepath_.parent_path();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
bool any;
|
||||
u64 mfs;
|
||||
|
||||
any = false;
|
||||
mfs = 0;
|
||||
chosen = nullptr;
|
||||
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,walk))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
any = true;
|
||||
if(info.spaceavail < mfs)
|
||||
continue;
|
||||
mfs = info.spaceavail;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(any)
|
||||
break;
|
||||
if(walk == "/")
|
||||
break;
|
||||
walk = walk.parent_path();
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
return -error;
|
||||
|
||||
for(fs::path p = fusepath_.parent_path();
|
||||
!p.empty() && p != "/";
|
||||
p = p.parent_path())
|
||||
segments.push_back(p);
|
||||
|
||||
dirmode = (0777 & ~umask_);
|
||||
for(auto it = segments.rbegin(); it != segments.rend(); ++it)
|
||||
{
|
||||
const Branch *src;
|
||||
const fs::path full = chosen->path / *it;
|
||||
|
||||
if(fs::exists(full))
|
||||
continue;
|
||||
|
||||
src = nullptr;
|
||||
for(auto &b : *branches)
|
||||
{
|
||||
if(&b == chosen)
|
||||
continue;
|
||||
if(!fs::exists(b.path,*it))
|
||||
continue;
|
||||
src = &b;
|
||||
break;
|
||||
}
|
||||
|
||||
if(src != nullptr)
|
||||
rv = fs::clonepath(src->path,chosen->path,*it);
|
||||
else
|
||||
rv = fs::mkdir_as(ugid_,full,dirmode);
|
||||
if((rv < 0) && (rv != -EEXIST))
|
||||
return rv;
|
||||
}
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_mspmfs.hpp
Normal file
23
src/func_create_mspmfs.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateMSPMFS : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateMSPMFS() {}
|
||||
~CreateMSPMFS() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
195
src/func_create_msppfrd.cpp
Normal file
195
src/func_create_msppfrd.cpp
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
#include "func_create_msppfrd.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include "fs_mkdir_as.hpp"
|
||||
#include "rnd.hpp"
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateMSPPFRD::name() const
|
||||
{
|
||||
return "msppfrd";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateMSPPFRD::path_preserving() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateMSPPFRD::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
fs::path walk;
|
||||
std::vector<fs::path> segments;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
mode_t dirmode;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
error = ENOENT;
|
||||
walk = fusepath_.parent_path();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
u64 sum;
|
||||
struct W { Branch *b; u64 weight; };
|
||||
std::vector<W> writable;
|
||||
|
||||
sum = 0;
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,walk))
|
||||
error_and_continue(error,ENOENT);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
writable.push_back({&branch,info.spaceavail});
|
||||
sum += info.spaceavail;
|
||||
}
|
||||
|
||||
if(!writable.empty())
|
||||
{
|
||||
if(sum == 0)
|
||||
{
|
||||
chosen = writable.front().b;
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 idx;
|
||||
u64 threshold;
|
||||
|
||||
idx = 0;
|
||||
threshold = RND::rand64(sum);
|
||||
for(const auto &w : writable)
|
||||
{
|
||||
if(w.weight == 0)
|
||||
continue;
|
||||
idx += w.weight;
|
||||
if(idx > threshold)
|
||||
{
|
||||
chosen = w.b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!chosen)
|
||||
chosen = writable.back().b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(walk == "/")
|
||||
break;
|
||||
walk = walk.parent_path();
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
return -error;
|
||||
|
||||
for(fs::path p = fusepath_.parent_path();
|
||||
!p.empty() && p != "/";
|
||||
p = p.parent_path())
|
||||
segments.push_back(p);
|
||||
|
||||
dirmode = (0777 & ~umask_);
|
||||
for(auto it = segments.rbegin(); it != segments.rend(); ++it)
|
||||
{
|
||||
const Branch *src;
|
||||
const fs::path full = chosen->path / *it;
|
||||
|
||||
if(fs::exists(full))
|
||||
continue;
|
||||
|
||||
src = nullptr;
|
||||
for(auto &b : *branches)
|
||||
{
|
||||
if(&b == chosen)
|
||||
continue;
|
||||
if(!fs::exists(b.path,*it))
|
||||
continue;
|
||||
src = &b;
|
||||
break;
|
||||
}
|
||||
|
||||
if(src != nullptr)
|
||||
rv = fs::clonepath(src->path,chosen->path,*it);
|
||||
else
|
||||
rv = fs::mkdir_as(ugid_,full,dirmode);
|
||||
if((rv < 0) && (rv != -EEXIST))
|
||||
return rv;
|
||||
}
|
||||
|
||||
fullpath = chosen->path / fusepath_;
|
||||
mode = mode_;
|
||||
if(!fs::acl::dir_has_defaults(fullpath))
|
||||
mode &= ~umask_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_msppfrd.hpp
Normal file
23
src/func_create_msppfrd.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateMSPPFRD : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateMSPPFRD() {}
|
||||
~CreateMSPPFRD() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
139
src/func_create_newest.cpp
Normal file
139
src/func_create_newest.cpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
#include "func_create_newest.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include "timespec_utils.hpp"
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateNewest::name() const
|
||||
{
|
||||
return "newest";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateNewest::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateNewest::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
struct stat st;
|
||||
timespec newest;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
const Branch *clone_src;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
clone_src = nullptr;
|
||||
error = ENOENT;
|
||||
newest = {0,0};
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
if(!fs::exists(branch.path,fusepath_,&st))
|
||||
error_and_continue(error,ENOENT);
|
||||
if(chosen && (st.st_mtim < newest))
|
||||
continue;
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
newest = st.st_mtim;
|
||||
chosen = &branch;
|
||||
}
|
||||
|
||||
if(!chosen)
|
||||
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_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_newest.hpp
Normal file
23
src/func_create_newest.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateNewest : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateNewest() {}
|
||||
~CreateNewest() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
159
src/func_create_pfrd.cpp
Normal file
159
src/func_create_pfrd.cpp
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
#include "func_create_pfrd.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include "rnd.hpp"
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreatePFRD::name() const
|
||||
{
|
||||
return "pfrd";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreatePFRD::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreatePFRD::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
u64 sum;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
const Branch *clone_src;
|
||||
struct W { Branch *b; u64 weight; };
|
||||
std::vector<W> writable;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
clone_src = nullptr;
|
||||
error = ENOENT;
|
||||
sum = 0;
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
writable.push_back({&branch,info.spaceavail});
|
||||
sum += info.spaceavail;
|
||||
}
|
||||
|
||||
if(writable.empty())
|
||||
return -error;
|
||||
if(sum == 0)
|
||||
return -ENOSPC;
|
||||
|
||||
{
|
||||
u64 idx;
|
||||
u64 threshold;
|
||||
|
||||
idx = 0;
|
||||
threshold = RND::rand64(sum);
|
||||
for(const auto &w : writable)
|
||||
{
|
||||
if(w.weight == 0)
|
||||
continue;
|
||||
idx += w.weight;
|
||||
if(idx > threshold)
|
||||
{
|
||||
chosen = w.b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!chosen)
|
||||
chosen = writable.back().b;
|
||||
}
|
||||
|
||||
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_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
25
src/func_create_pfrd.hpp
Normal file
25
src/func_create_pfrd.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreatePFRD : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreatePFRD() {}
|
||||
~CreatePFRD() {}
|
||||
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
134
src/func_create_rand.cpp
Normal file
134
src/func_create_rand.cpp
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#include "func_create_rand.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 "fileinfo.hpp"
|
||||
#include "fs_acl.hpp"
|
||||
#include "fs_open_as.hpp"
|
||||
#include "rnd.hpp"
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define error_and_continue(CUR,ERR) \
|
||||
do { \
|
||||
::_calc_error(CUR,ERR); \
|
||||
continue; \
|
||||
} while(0)
|
||||
|
||||
static
|
||||
inline
|
||||
void
|
||||
_calc_error(int &cur_,
|
||||
const int err_)
|
||||
{
|
||||
switch(cur_)
|
||||
{
|
||||
default:
|
||||
case ENOENT:
|
||||
cur_ = err_;
|
||||
break;
|
||||
case ENOSPC:
|
||||
if(err_ != ENOENT)
|
||||
cur_ = err_;
|
||||
break;
|
||||
case EROFS:
|
||||
if((err_ != ENOENT) && (err_ != ENOSPC))
|
||||
cur_ = err_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::CreateRAND::name() const
|
||||
{
|
||||
return "rand";
|
||||
}
|
||||
|
||||
bool
|
||||
Func2::CreateRAND::path_preserving() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Func2::CreateRAND::operator()(const ugid_t &ugid_,
|
||||
const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
fuse_file_info_t *&ffi_,
|
||||
const mode_t &mode_,
|
||||
const mode_t &umask_)
|
||||
{
|
||||
int rv;
|
||||
int error;
|
||||
fs::info_t info;
|
||||
Branches::Ptr branches;
|
||||
const Branch *chosen;
|
||||
const Branch *clone_src;
|
||||
std::vector<Branch*> writable;
|
||||
int fd;
|
||||
fs::path fullpath;
|
||||
mode_t mode;
|
||||
FileInfo *fi;
|
||||
|
||||
branches = branches_;
|
||||
chosen = nullptr;
|
||||
clone_src = nullptr;
|
||||
error = ENOENT;
|
||||
for(auto &branch : *branches)
|
||||
{
|
||||
if(branch.ro_or_nc())
|
||||
error_and_continue(error,EROFS);
|
||||
rv = fs::info(branch.path,&info);
|
||||
if(rv < 0)
|
||||
error_and_continue(error,ENOENT);
|
||||
if(info.readonly)
|
||||
error_and_continue(error,EROFS);
|
||||
if(info.spaceavail < branch.minfreespace())
|
||||
error_and_continue(error,ENOSPC);
|
||||
|
||||
writable.push_back(&branch);
|
||||
}
|
||||
|
||||
if(writable.empty())
|
||||
return -error;
|
||||
|
||||
chosen = writable[RND::rand64(writable.size())];
|
||||
|
||||
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_;
|
||||
|
||||
fd = fs::open_as(ugid_,fullpath,ffi_->flags,mode);
|
||||
if(fd < 0)
|
||||
return fd;
|
||||
|
||||
fi = new FileInfo(fd,chosen,fusepath_,ffi_->direct_io);
|
||||
ffi_->fh = fi->to_fh();
|
||||
|
||||
return 0;
|
||||
}
|
||||
23
src/func_create_rand.hpp
Normal file
23
src/func_create_rand.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_create_base.hpp"
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class CreateRAND : public CreateBase
|
||||
{
|
||||
public:
|
||||
CreateRAND() {}
|
||||
~CreateRAND() {}
|
||||
public:
|
||||
std::string_view name() const;
|
||||
bool path_preserving() const;
|
||||
public:
|
||||
int operator()(const ugid_t &ugid,
|
||||
const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
fuse_file_info_t *&ffi,
|
||||
const mode_t &mode,
|
||||
const mode_t &umask);
|
||||
};
|
||||
}
|
||||
20
src/func_getattr.hpp
Normal file
20
src/func_getattr.hpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "func_getattr_base.hpp"
|
||||
#include "func_getattr_factory.hpp"
|
||||
|
||||
#include "func_wrapper.hpp"
|
||||
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
using GetAttr = FuncWrapper<Func2::GetAttrBase,
|
||||
Func2::GetAttrFactory,
|
||||
int,
|
||||
const Branches&,
|
||||
const fs::path&,
|
||||
struct stat*&,
|
||||
const FollowSymlinksEnum&,
|
||||
const bool&,
|
||||
const s64&>;
|
||||
}
|
||||
36
src/func_getattr_base.hpp
Normal file
36
src/func_getattr_base.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include "follow_symlinks_enum.hpp"
|
||||
|
||||
#include "fs_path.hpp"
|
||||
#include "branches.hpp"
|
||||
#include "base_types.h"
|
||||
|
||||
#include "fuse.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace Func2
|
||||
{
|
||||
class GetAttrBase
|
||||
{
|
||||
public:
|
||||
GetAttrBase() {}
|
||||
~GetAttrBase() {}
|
||||
|
||||
public:
|
||||
virtual std::string_view name() const = 0;
|
||||
|
||||
public:
|
||||
virtual int operator()(const Branches &branches,
|
||||
const fs::path &fusepath,
|
||||
struct stat *st,
|
||||
const FollowSymlinksEnum follow_symlinks,
|
||||
const bool symlinkify,
|
||||
const s64 symlinkify_timeout) = 0;
|
||||
};
|
||||
}
|
||||
78
src/func_getattr_cdco.cpp
Normal file
78
src/func_getattr_cdco.cpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#include "func_getattr_cdco.hpp"
|
||||
|
||||
#include "fs_inode.hpp"
|
||||
#include "fs_stat.hpp"
|
||||
#include "symlinkify.hpp"
|
||||
#include "timespec_utils.hpp"
|
||||
|
||||
|
||||
std::string_view
|
||||
Func2::GetAttrCDCO::name() const
|
||||
{
|
||||
return "cdco";
|
||||
}
|
||||
|
||||
int
|
||||
Func2::GetAttrCDCO::operator()(const Branches &branches_,
|
||||
const fs::path &fusepath_,
|
||||
struct stat *st_,
|
||||
const FollowSymlinksEnum follow_symlinks_,
|
||||
const bool symlinkify_,
|
||||
const s64 symlinkify_timeout_)
|
||||
{
|
||||
int rv;
|
||||
int err;
|
||||
fs::path fullpath;
|
||||
const Branch *first_branch;
|
||||
|
||||
err = 0;
|
||||
first_branch = nullptr;
|
||||
for(const auto &branch : branches_)
|
||||
{
|
||||
struct stat tmp_st;
|
||||
|
||||
fullpath = branch.path / fusepath_;
|
||||
|
||||
rv = fs::stat(fullpath,&tmp_st,follow_symlinks_);
|
||||
if(rv < 0)
|
||||
{
|
||||
err = rv;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(not first_branch)
|
||||
{
|
||||
*st_ = tmp_st;
|
||||
first_branch = &branch;
|
||||
continue;
|
||||
}
|
||||
|
||||
// This upgrades the uid:gid because mergerfs now does most
|
||||
// file interaction as root and relies on `default_permissions`
|
||||
// to manage permissions. Want to ensure that root owned files
|
||||
// can't be changed so we treat them all as root owned.
|
||||
if(tmp_st.st_uid == 0)
|
||||
st_->st_uid = 0;
|
||||
if(tmp_st.st_gid == 0)
|
||||
st_->st_gid = 0;
|
||||
st_->st_atim = TimeSpec::newest(st_->st_atim,tmp_st.st_atim);
|
||||
st_->st_ctim = TimeSpec::newest(st_->st_ctim,tmp_st.st_ctim);
|
||||
st_->st_mtim = TimeSpec::newest(st_->st_mtim,tmp_st.st_mtim);
|
||||
st_->st_nlink += tmp_st.st_nlink;
|
||||
}
|
||||
|
||||
if(!first_branch)
|
||||
return err;
|
||||
|
||||
if(symlinkify_)
|
||||
{
|
||||
fullpath = first_branch->path / fusepath_;
|
||||
symlinkify::convert_if_can_be_symlink(fullpath,
|
||||
st_,
|
||||
symlinkify_timeout_);
|
||||
}
|
||||
|
||||
fs::inode::calc(first_branch->path,fusepath_,st_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue